Skip to content

Commit

Permalink
Merge pull request #36 from Erotemic/dev/1.1.0
Browse files Browse the repository at this point in the history
Cleanup and small fix
  • Loading branch information
Erotemic committed Apr 1, 2023
2 parents 16d3a61 + 11810c2 commit 3e0e7ab
Show file tree
Hide file tree
Showing 9 changed files with 276 additions and 136 deletions.
248 changes: 163 additions & 85 deletions .github/workflows/tests.yml

Large diffs are not rendered by default.

23 changes: 4 additions & 19 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,18 @@
# .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
#
#
# See Also:
# https://readthedocs.org/dashboard/mkinit/advanced/

# Required
version: 2

# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/source/conf.py

# Build documentation with MkDocs
#mkdocs:
# configuration: mkdocs.yml

# Optionally build your docs in additional formats such as PDF and ePub
formats: all

# Optionally set the version of Python and requirements required to build your docs
python:
version: 3.7
install:
- requirements: requirements/docs.txt
- method: pip
path: .
#extra_requirements:
# - docs

#conda:
# environment: environment.yml
- requirements: requirements/docs.txt
- method: pip
path: .
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ We are currently working on porting this changelog to the specifications in
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## Version: 1.1.0 -

### Changed
* Code cleanup

### Fixed
* Extra newlines in generated files


## Version: 1.0.0 - Released 2022-12-03

### Added
Expand Down
94 changes: 79 additions & 15 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mkinit
======

|CircleCI| |Travis| |Appveyor| |Codecov| |Pypi| |Downloads| |ReadTheDocs|
|CircleCI| |Appveyor| |Codecov| |Pypi| |Downloads| |ReadTheDocs|


Read the docs here: http://mkinit.readthedocs.io/en/latest/ (although this is
Expand All @@ -17,6 +17,13 @@ It can do this dynamically, or it can statically autogenerate the ``__init__``
for faster import times. Its kinda like using the ``fromimport *`` syntax, but
its easy to replace with text that wont make other developers lose their hair.

This module supports Scientific Python `SPEC1 <https://scientific-python.org/specs/spec-0001/>`_.

Also note that the docs in this readme are somewhat old, and need to be updated
to make best practices more clear. There are a lot of ways you can use the
module, but the current recommended way is to use
``mkinit --lazy_loader <path-to-init.py>``

Installation
============

Expand All @@ -41,7 +48,7 @@ Say you have a python module structured like so:
And you would like to make all functions inside of ``submod.py`` and
``nested.py`` available at the top-level of the package.
``nested.py`` available at the top-level of the package.

Imagine the contents of submod.py and nested.py are:

Expand All @@ -61,15 +68,15 @@ You could manually write:


.. code:: python
from mkinit_demo_pkg.submod import *
from mkinit_demo_pkg.subpkg.nested import *
But that has a few problems. Using ``import *`` makes it hard for people
reading the code to know what is coming from where. Furthermore, if there were
many submodules you wanted to expose attributes of, writing this would become
tedious and hard to maintain.
tedious and hard to maintain.

Enter the mkinit package. It has the ability to autogenerate explicit ``__init__.py``
files using static analysis. Normally, the mkinit CLI only works on one file at
Expand Down Expand Up @@ -107,7 +114,7 @@ See ``mkinit --help`` for more details.
Lastly, while exposing all attributes can be helpful for larger projects,
import time can start to become a consideration. Thankfully, PEP 0562 outlines
a lazy import specification for Python >= 3.7. As of 2020-12-26 mkinit
supports autogenerating these lazy init files.
supports autogenerating these lazy init files.

Unfortunately, there is no syntax support for lazy imports, so mkinit must
define a ``lazy_import`` boilerplate function in each ``__init__.py`` file.
Expand Down Expand Up @@ -156,7 +163,7 @@ define a ``lazy_import`` boilerplate function in each ``__init__.py`` file.
__getattr__(attr)
return __getattr__
__getattr__ = lazy_import(
__name__,
submodules={
Expand Down Expand Up @@ -197,10 +204,68 @@ be used to help maintain customized `__init__.py` files.
You can also enclose the area allowed to be clobbered in the auto-generation
with special xml-like comments.

Running ``mkint --help`` displays:

.. code::
usage: python -m mkinit [-h] [--dry] [-i] [--diff] [--noattrs] [--nomods] [--noall] [--relative] [--lazy | --lazy_loader] [--black] [--lazy_boilerplate LAZY_BOILERPLATE] [--recursive] [--norespect_all]
[--verbose [VERBOSE]] [--version]
[modname_or_path]
Autogenerate an `__init__.py` that exposes a top-level API.
Behavior is modified depending on the existing content of the
`__init__.py` file (subsequent runs of mkinit are idempotent).
The following `__init__.py` variables modify autogeneration behavior:
`__submodules__` (List[str] | Dict[str, List[str])) -
Indicates the list of submodules to be introspected, if
unspecified all submodules are introspected. Can be a list
of submodule names, or a dictionary mapping each submodule name
to a list of attribute names to expose. If the value is None,
then all attributes are exposed (or __all__) is respected).
`__external__` - Specify external modules to expose the attributes of.
`__explicit__` - Add custom explicitly defined names to this, and
they will be automatically added to the __all__ variable.
`__protected__` - Protected modules are exposed, but their attributes are not.
`__private__` - Private modules and their attributes are not exposed.
`__ignore__` - Tells mkinit to ignore particular attributes
positional arguments:
modname_or_path module or path to generate __init__.py for
options:
-h, --help show this help message and exit
--dry
-i, -w, --write, --inplace
modify / write to the file inplace
--diff show the diff (forces dry mode)
--noattrs Do not generate attribute from imports
--nomods Do not generate modules imports
--noall Do not generate an __all__ variable
--relative Use relative . imports instead of <modname>
--lazy Use lazy imports with more boilerplate but no dependencies (Python >= 3.7 only!)
--lazy_loader Use lazy imports with less boilerplate but requires the lazy_loader module (Python >= 3.7 only!)
--black Use black formatting
--lazy_boilerplate LAZY_BOILERPLATE
Code that defines a custom lazy_import callable
--recursive If specified, runs mkinit on all subpackages in a package
--norespect_all if False does not respect __all__ attributes of submodules when parsing
--verbose [VERBOSE] Verbosity level
--version print version and exit
Dynamic Usage
-------------

NOTE: Dynamic usage is NOT recommended.
NOTE: Dynamic usage is NOT recommended.

In most cases, we recommend using mkinit command line tool to statically
generate / update the `__init__.py` file, but there is an option to to use it
Expand Down Expand Up @@ -259,7 +324,7 @@ Step 2 (Optional): Enumerate relevant submodules

After optionally writing any custom code, you may optionally specify exactly
what submodules should be considered when auto-generating imports. This is done
by setting the `__submodules__` attribute to a list of submodule names.
by setting the `__submodules__` attribute to a list of submodule names.

In `ubelt` this section looks similar to the following:

Expand Down Expand Up @@ -307,7 +372,7 @@ Now that we have inserted the auto-generation tags, we can actually run
Assuming the `ubelt` repo is checked out in `~/code/`, the command to
autogenerate its `__init__.py` file would be: `mkinit ~/code/ubelt/ubelt`.
Given the previously specified `__submodules__`, the resulting auto-generated
portion of the code looks like this:
portion of the code looks like this:


.. code:: python
Expand Down Expand Up @@ -369,7 +434,7 @@ This is almost equivalent to running the static command line variant. However,
instead of using static analysis, this will use the Python interpreter to
execute and import all submodules and dynamically inspect the defined members.
This is faster than using static analysis, and in most circumstances there will
be no difference in the resulting imported attributes. To avoid all differences
be no difference in the resulting imported attributes. To avoid all differences
simply specify the `__all__` attribute in each submodule.

Note that inclusion of the `__submodules__` attribute is not strictly
Expand Down Expand Up @@ -413,9 +478,9 @@ following:
attribute by default. In general it is good practice to specify this
property; doing so will also avoid the following caveats.

* Static analysis currently only extracts top-level module attributes. However,
* Static analysis currently only extracts top-level module attributes. However,
if will also extract attributes defined on all non-error raising paths of
conditional if-else or try-except statements.
conditional if-else or try-except statements.

* Static analysis currently does not look or account for the usage of the `del`
operator. Again, these will be accounted for by dynamic analysis.
Expand All @@ -429,10 +494,9 @@ following:
TODO
----

- [ ] Give `dynamic_init` an options dict to maintain a compatible API with `static_init`.
- [ ] Give `dynamic_init` an options dict to maintain a compatible API with `static_init`.

- [ ] If an attribute would be defined twice, then don't define it at all.
Currently, it is defined, but its value is not well-defined.
- [ ] If an attribute would be defined twice, then don't define it at all. Currently, it is defined, but its value is not well-defined.


.. |CircleCI| image:: https://circleci.com/gh/Erotemic/mkinit.svg?style=svg
Expand Down
3 changes: 1 addition & 2 deletions mkinit/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
The MkInit Module
-----------------
Expand All @@ -11,7 +10,7 @@
mkinit ~/code/mkinit/mkinit
"""

__version__ = "1.0.0"
__version__ = "1.1.0"

__submodules__ = [
"dynamic_mkinit",
Expand Down
2 changes: 0 additions & 2 deletions mkinit/dynamic_mkinit.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
"""
Dynamically generate the import exec
"""
from __future__ import absolute_import, division, print_function, unicode_literals
from os.path import dirname, join, exists
import sys
import multiprocessing
Expand Down
5 changes: 5 additions & 0 deletions mkinit/formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,14 @@ def _insert_autogen_text(modpath, initstr):
startline, endline, init_indent = _find_insert_points(lines)
initstr_ = _indent(initstr, init_indent) + "\n"

QUICKFIX_REMOVE_LEADING_NEWLINES = 1
if QUICKFIX_REMOVE_LEADING_NEWLINES:
initstr_ = initstr_.lstrip('\n')

new_lines = lines[:startline] + [initstr_] + lines[endline:]

new_text = "".join(new_lines).rstrip() + "\n"
print(new_text)
return init_fpath, new_text


Expand Down
4 changes: 2 additions & 2 deletions requirements/tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ pytest-cov>=2.9.0 ; python_version < '3.6.0' and python_version >= '3
pytest-cov>=2.8.1 ; python_version < '3.5.0' and python_version >= '3.4.0' # Python 3.4
pytest-cov>=2.8.1 ; python_version < '2.8.0' and python_version >= '2.7.0' # Python 2.7

# python ~/local/tools/supported_python_versions_pip.py xdoctest
# python ~/local/tools/supported_python_versions_pip.py coverage
# xdev availpkg xdoctest
# xdev availpkg coverage
coverage>=6.1.1 ; python_version >= '3.10' # Python 3.10+
coverage>=5.3.1 ; python_version < '3.10' and python_version >= '3.9' # Python 3.9
coverage>=6.1.1 ; python_version < '3.9' and python_version >= '3.8' # Python 3.8
Expand Down
24 changes: 13 additions & 11 deletions setup.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#!/usr/bin/env python
# Generated by ~/code/xcookie/xcookie/builders/setup.py
# based on part ~/code/xcookie/xcookie/rc/setup.py.in
import sys
from os.path import exists
import re
from os.path import exists, dirname, join
from setuptools import find_packages
from setuptools import setup

Expand Down Expand Up @@ -52,8 +54,6 @@ def parse_description():
pandoc --from=markdown --to=rst --output=README.rst README.md
python -c "import setup; print(setup.parse_description())"
"""
from os.path import dirname, join, exists

readme_fpath = join(dirname(__file__), "README.rst")
# This breaks on pip install, so check that it exists.
if exists(readme_fpath):
Expand All @@ -76,10 +76,10 @@ def parse_requirements(fname="requirements.txt", versions=False):
Returns:
List[str]: list of requirements items
"""
from os.path import exists, dirname, join
import re
CommandLine:
python -c "import setup, ubelt; print(ubelt.urepr(setup.parse_requirements()))"
"""
require_fpath = fname

def parse_line(line, dpath=""):
Expand Down Expand Up @@ -197,16 +197,18 @@ def gen_packages_items():

NAME = "mkinit"
INIT_PATH = "mkinit/__init__.py"
VERSION = parse_version("mkinit/__init__.py")
VERSION = parse_version(INIT_PATH)

if __name__ == "__main__":
setupkw = {}

setupkw["install_requires"] = parse_requirements("requirements/runtime.txt")
setupkw["install_requires"] = parse_requirements(
"requirements/runtime.txt", versions="loose"
)
setupkw["extras_require"] = {
"all": parse_requirements("requirements.txt"),
"tests": parse_requirements("requirements/tests.txt"),
"optional": parse_requirements("requirements/optional.txt"),
"all": parse_requirements("requirements.txt", versions="loose"),
"tests": parse_requirements("requirements/tests.txt", versions="loose"),
"optional": parse_requirements("requirements/optional.txt", versions="loose"),
"all-strict": parse_requirements("requirements.txt", versions="strict"),
"runtime-strict": parse_requirements(
"requirements/runtime.txt", versions="strict"
Expand Down

0 comments on commit 3e0e7ab

Please sign in to comment.