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. Imports and __all__ assignments that would exceed 88 characters are wrapped with one name per line.

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.4.tar.gz (8.7 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.4-py3-none-any.whl (10.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: autolazy-1.1.4.tar.gz
  • Upload date:
  • Size: 8.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","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.4.tar.gz
Algorithm Hash digest
SHA256 1f5bd1dde25c7738ad73c476e3a3a451e592030b3f6be74b91953edf8e8a9349
MD5 03e9a11bb5e2bb7a240fddd988d5d443
BLAKE2b-256 c6a6f8213f7354e156d9c9266d54a4c587cae883714ef574a7191e875ef587b9

See more details on using hashes here.

File details

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

File metadata

  • Download URL: autolazy-1.1.4-py3-none-any.whl
  • Upload date:
  • Size: 10.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","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.4-py3-none-any.whl
Algorithm Hash digest
SHA256 325fc6d8c5eae7a7dbe81bec78f1ab32ab8905117da68d4138a17a4f1029c444
MD5 5ba9ff7376e08618cc3207b6c34b0317
BLAKE2b-256 158ad53ca8c489f710d854bd53bd43b914598c0b193facab2b7df7165178cf13

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