Skip to main content

Utilities for building lazily imported Python packages

Project description

autolazy

Utilities for building lazily imported Python packages.

autolazy provides helper functions that make it easy to set up lazy_loader-based packages. It automatically discovers each submodule's public API by parsing __all__ declarations — no imports, no side effects, just AST analysis — and wires everything up in a single call.

Installation

pip install autolazy

Requires Python 3.12+.

Quick start

Suppose you have a package like this:

mypkg/
├── __init__.py
├── audio.py       # __all__ = ["AudioLoader", "AudioWriter"]
└── vision.py      # __all__ = ["ImageLoader"]

Replace the usual eager imports in __init__.py with:

from autolazy import lazy_attach

__getattr__, __dir__, __all__ = lazy_attach(
    package_name=__name__,
    init_file_path=__file__,
    submod_attrs=["audio", "vision"],
)

Now symbols are imported on first access:

import mypkg

mypkg.AudioLoader   # imports audio.py only at this point
mypkg.ImageLoader   # imports vision.py only at this point

Submodules themselves can also be exposed lazily:

__getattr__, __dir__, __all__ = lazy_attach(
    package_name=__name__,
    init_file_path=__file__,
    submodules=["utils"],       # exposed as mypkg.utils
    submod_attrs=["audio"],     # symbols exposed at mypkg level
)

API

lazy_attach

lazy_attach(
    package_name: str,
    init_file_path: str,
    submodules: list[str] | None = None,
    submod_attrs: list[str] | None = None,
) -> tuple[__getattr__, __dir__, __all__]

Scans each name in submod_attrs, extracts its __all__ via AST parsing, and passes the result to lazy_loader.attach().

Parameter Description
package_name The package name — pass __name__
init_file_path Path to __init__.py — pass __file__
submodules Submodules exposed as pkg.submod (not flattened)
submod_attrs Submodules whose public symbols are flattened into the package namespace

If a name in submod_attrs has no __all__ (or the file is missing), it falls back to being treated as a plain submodule and a UserWarning is emitted for missing files.

Dotted names (e.g. "sub.module") are resolved relative to the package directory, so nested packages work out of the box.


parse_all

parse_all(path: Path) -> list[str]

Parses a Python source file and returns the names declared in __all__, without importing the module. Supports all common patterns:

__all__ = ["a", "b"]       # assignment
__all__ += ["c"]           # augmented assignment
__all__.append("d")        # append
__all__.extend(["e", "f"]) # extend

Non-string elements in __all__ are silently ignored. If multiple assignments to __all__ exist, the last one wins (matching Python semantics).


sync_type_checking

Since lazy_attach builds the API at runtime, static type checkers like Pylance/pyright can't see mypkg.AudioLoader. sync_type_checking generates an if TYPE_CHECKING: block of literal imports (never executed, so lazy loading is preserved) that keeps them in sync.

The easiest way is the CLI — it reads the arguments from your existing lazy_attach(...) call, so there's nothing to configure:

python -m autolazy mypkg/__init__.py

It inserts (and, on re-runs, refreshes in place) a marker-delimited block:

# >>> autolazy: type-checking imports (auto-generated) >>>
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from .audio import AudioLoader, AudioWriter
    from .vision import ImageLoader

    __all__ = ["AudioLoader", "AudioWriter", "ImageLoader"]
# <<< autolazy: type-checking imports <<<

The literal __all__ marks the imports as re-exports, so ruff and pyright stay quiet with no as aliases or # noqa. It sits under if TYPE_CHECKING:, so it never runs — your runtime __all__ stays the one lazy_attach builds.

The same is available programmatically as sync_type_checking(init_file_path, submodules=..., submod_attrs=...) (pass write=False to get the block as a string). See the guide for details.

How it compares to manual lazy_loader usage

Without autolazy you must maintain submod_attrs by hand:

# manual — must be kept in sync with each module's __all__
__getattr__, __dir__, __all__ = lazy.attach(
    __name__,
    submod_attrs={
        "audio": ["AudioLoader", "AudioWriter"],
        "vision": ["ImageLoader"],
    },
)

With autolazy:

# automatic — __all__ is read from each file at import time
__getattr__, __dir__, __all__ = lazy_attach(
    package_name=__name__,
    init_file_path=__file__,
    submod_attrs=["audio", "vision"],
)

Requirements

License

MIT — see LICENSE.

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

autolazy-1.1.2.tar.gz (8.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

autolazy-1.1.2-py3-none-any.whl (10.0 kB view details)

Uploaded Python 3

File details

Details for the file autolazy-1.1.2.tar.gz.

File metadata

  • Download URL: autolazy-1.1.2.tar.gz
  • Upload date:
  • Size: 8.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for autolazy-1.1.2.tar.gz
Algorithm Hash digest
SHA256 ad9db0ec1fedb04d34f0f2e8fb76a3948a28e273190a7f851bc8839af43a15fa
MD5 8a20ae9e3810b37cbf33416f1d1f7b4d
BLAKE2b-256 e30bc8b2684c94ff760f6114aed5d899ed02c0d95c3a95661a0b06f19a9dc6e4

See more details on using hashes here.

File details

Details for the file autolazy-1.1.2-py3-none-any.whl.

File metadata

  • Download URL: autolazy-1.1.2-py3-none-any.whl
  • Upload date:
  • Size: 10.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for autolazy-1.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 31d7abb567f72f6705aba28446281ab39028d93e24c05b6632db178c5b1624d6
MD5 387098d5cf16755b2f9f536c78bae256
BLAKE2b-256 493ec802cd7f6b8088a5a91c2a6559bc814e025a510f606f3da9180016acda2f

See more details on using hashes here.

Supported by

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