pyrollup
Simple mechanism to rollup API symbols to a Python module from its submodules
Background
Conventionally, a Python package's public API symbols (or at least a subset) are exported from the top-level package. These symbols are typically imported from various submodules in the module hierarchy. This leads to a rather tedious listing of symbols exported (via a module's __init__.py) at each level.
For example:
from .submodule_a import ClassA, ClassA2
from .submodule_b import ClassB
from .submodule_c import ClassC
__all__ = [
ClassA,
ClassA2
ClassB,
ClassC,
]
The definition of __all__ can be omitted, although some schools of thought encourage its use.
Problem statement
With the above approach, the burden of which symbols are considered public for a given submodule falls on the containing module importing them. In addition, __all__ must be maintained alongside symbol imports, potentially resulting in duplication.
This can become problematic for complex projects with many nested symbols imported at the top-level package. For example:
from .submodule_a import ClassA, ClassA2
from .submodule_a.submodule_a1 import ClassA1_1, ClassA1_2
from .submodule_a.submodule_a2 import ClassA2_1, ClassA2_2
from .submodule_a.submodule_a3 import ClassA3_1, ClassA3_2
from .submodule_b import ClassB
from .submodule_c import ClassC
__all__ = [
ClassA,
ClassA2,
ClassA1_1,
ClassA1_2,
ClassA2_1,
ClassA2_2,
ClassA3_1,
ClassA3_2,
ClassB,
ClassC,
]
In addition, submodules must similarly maintain their own imports and/or definition of __all__ if they export symbols from their submodules.
Proposed solution
Ideally, a module should "rollup" public symbols from its submodules, letting each submodule decide which symbols those are. Submodules should therefore optionally provide an allow-list and block-list to describe which public symbols should be propagated to the parent module.
In other words, a given module should have ownership of:
- Its own public symbols (Python convention)
- Defined by
__all__
- Defined by
- Which of those public symbols should be propagated to parent modules (functionality provided by
pyrollup)- Defined by
__rollup__: allow-list, defaulting to__all____nrollup__: block-list, defaulting to[]
- Defined by
Then, the example above can be modified as:
from pyrollup import rollup
# import submodules
from . import submodule_a, submodule_b, submodule_c
# import public symbols from each submodule
from .submodule_a import *
from .submodule_b import *
from .submodule_c import *
# export public symbols from each submodule, filtered by allow-list/block-list
__all__ = rollup(submodule_a, submodule_b, submodule_c)
This allows a project with a complex module hierarchy to flexibly propagate public symbols from wherever they are defined to the top-level package.
Downsides
Static analysis tools are unable to evaluate the value of __all__ since with this approach it is computed dynamically upon import. Therefore, code documentation generator tools using static analysis (e.g. autoapi or autodoc2) will fail to detect a module's public symbols.
Tools using the traditional approach of importing the package for which documentation is being generated (e.g. Sphinx's built-in autodoc) should have no problem with such dynamic imports.
It is possible to use a "hybrid" approach; the author has had some success with extending autodoc2 to work with dynamically-evaluated __all__.
TODO: document and generalize this solution
Metadata
Release files for pyrollup 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| pyrollup-0.1.0.tar.gz | 3.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyrollup-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 7.2 kB
Release files / pyrollup-0.1.0.tar.gz
| Download URL | pyrollup-0.1.0.tar.gz |
|---|---|
| Size | 3.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
388c152b20b5467d2378462dcc6bac121db3bd98ef1902874caa0e30b24a0f21
|
|
BLAKE2b-256 checksum How to use checksums |
d72779fd7b38ba488482ed0813db78b6e0e49fde9417c967c755ca3800655f6e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.6.1 CPython/3.10.12 Linux/5.15.0-87-generic
|
Release files / pyrollup-0.1.0-py3-none-any.whl
| Download URL | pyrollup-0.1.0-py3-none-any.whl |
|---|---|
| Size | 3.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a2f73b823e251f6e3c9e14dfe7ce43323824a62fe5fc66d5e6221db6d9fae6ba
|
|
BLAKE2b-256 checksum How to use checksums |
c38f4375e0fbf96962aca89243ee0661956972bf8350c283acc13ec4a6dd7918
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.6.1 CPython/3.10.12 Linux/5.15.0-87-generic
|
Security for pyrollup 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.