Skip to main content

Simple mechanism to rollup API symbols to a Python module from its submodules

Project description

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__
  • 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 []

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyrollup-0.1.0.tar.gz (3.4 kB view details)

Uploaded Source

Built Distribution

pyrollup-0.1.0-py3-none-any.whl (3.8 kB view details)

Uploaded Python 3

File details

Details for the file pyrollup-0.1.0.tar.gz.

File metadata

  • Download URL: pyrollup-0.1.0.tar.gz
  • Upload date:
  • Size: 3.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.6.1 CPython/3.10.12 Linux/5.15.0-87-generic

File hashes

Hashes for pyrollup-0.1.0.tar.gz
Algorithm Hash digest
SHA256 388c152b20b5467d2378462dcc6bac121db3bd98ef1902874caa0e30b24a0f21
MD5 4987b1a23b3d31ebdfa47ef7d21a4dea
BLAKE2b-256 d72779fd7b38ba488482ed0813db78b6e0e49fde9417c967c755ca3800655f6e

See more details on using hashes here.

Provenance

File details

Details for the file pyrollup-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pyrollup-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 3.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.6.1 CPython/3.10.12 Linux/5.15.0-87-generic

File hashes

Hashes for pyrollup-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a2f73b823e251f6e3c9e14dfe7ce43323824a62fe5fc66d5e6221db6d9fae6ba
MD5 7c997e695f8b9f1f8150577c3ce5b6e0
BLAKE2b-256 c38f4375e0fbf96962aca89243ee0661956972bf8350c283acc13ec4a6dd7918

See more details on using hashes here.

Provenance

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page