Skip to main content

Lazy import utilities for deferred module loading and attribute access. Truly lazy, truly late.

Project description

lateimport

Lazy import utilities for Python — defer module loading until an imported object is actually used.

PyPI Python License CI

Overview

lateimport provides two complementary tools:

  • lateimport — an explicit proxy for deferring imports in application code
  • create_late_getattr — a factory for the __getattr__ hook in package __init__.py files, for use with dispatch-table-based lazy loading (e.g. as generated by Exportify)

Both are stdlib-only. No dependencies.

Requirements

Python 3.12+

Installation

pip install lateimport

Usage

Explicit lazy imports

Use lateimport when you want to defer a heavy import in application code. The module is not imported until the returned proxy is actually used — called, subscripted, passed to isinstance, etc.

from lateimport import lateimport

# No import happens here
numpy = lateimport("numpy")
pandas = lateimport("pandas", "DataFrame")  # defers pandas.DataFrame

# Import triggered on first use
result = numpy.array([1, 2, 3])
df = pandas({"a": [1, 2]})

Proxies are thread-safe and cache the resolved object after first access.

proxy = lateimport("heavy.module", "ExpensiveClass")

proxy.is_resolved()   # False
instance = proxy()    # heavy.module imported, ExpensiveClass resolved
proxy.is_resolved()   # True

Type annotations

LateImport[T] is a generic class. Annotating a variable with the resolved type gives you full type-checking and autocompletion downstream — the type checker knows that calling or accessing the proxy produces a T.

from __future__ import annotations

from typing import TYPE_CHECKING

from lateimport import LateImport, lateimport

if TYPE_CHECKING:
    import numpy as np
    from pandas import DataFrame

# Type checker knows ndarray() returns np.ndarray
ndarray: LateImport[np.ndarray] = lateimport("numpy", "ndarray")
arr = ndarray([1, 2, 3])  # arr: np.ndarray

# type[DataFrame] means calling the proxy produces a DataFrame instance
DataFrame: LateImport[type[DataFrame]] = lateimport("pandas", "DataFrame")
df = DataFrame({"col": [1, 2, 3]})  # df: DataFrame

The TYPE_CHECKING guard keeps the imports from executing at runtime — you get static type information without the import cost, which is the whole point.

For types that are always available no guard is needed:

from pathlib import Path
from lateimport import LateImport, lateimport

MkPath: LateImport[type[Path]] = lateimport("pathlib", "Path")
p = MkPath("/tmp/out")  # p: Path

Package-level lazy __getattr__

For packages using a dispatch-table pattern (e.g. generated by Exportify), create_late_getattr creates a __getattr__ hook that imports attributes on demand:

# mypackage/__init__.py
from types import MappingProxyType
from lateimport import create_late_getattr
# NOTE: for IDE support, import any dynamic imports in a TYPE_CHECKING block:
from typing import TYPE_CHECKING:
    from mypackage.core.models import MyClass
    from mypackage.utils.helpers import my_function
    from mypackage import SubModule

_dynamic_imports = MappingProxyType({
    "MyClass":      ("mypackage.core",   "models"),
    "my_function":  ("mypackage.utils",  "helpers"),
    # for the current package you can just use __spec__.parent:
    "SubModule":    (__spec__.parent,        "__module__"),
})

__getattr__ = create_late_getattr(_dynamic_imports, globals(), __name__)

__all__ = ("MyClass", "my_function", "SubModule")

# Make sure dir calls use __all__ and not globals:
__dir__ = lambda: list(__all__)

The dispatch tuple is (package, submodule):

  • Normal attributes: imports package.submodule and returns getattr(submodule, attr_name)
  • "__module__": imports the submodule itself as the attribute (import_module(f".{attr_name}", package=package))

Resolved attributes are cached in globals() so subsequent accesses are direct.

API

lateimport(module_name, *attrs) -> LateImport[T]

Create a lazy proxy for module_name. Optional attrs are an attribute chain traversed after import. The function is generic — annotate the variable as LateImport[T] to propagate the resolved type to callers.

lateimport("os")                    # proxy for the os module
lateimport("os.path", "join")       # proxy for os.path.join
lateimport("mypackage", "A", "B")   # proxy for mypackage.A.B

class LateImport[T]

The generic proxy class returned by lateimport. Annotate the variable with LateImport[T] to tell the type checker what type the proxy resolves to — __call__ and _resolve() are typed to return T. Supports call, attribute access, dir(), and repr(). Thread-safe.

Method Description
is_resolved() True if the import has been triggered
_resolve() Force immediate resolution and return the object (typed as T)

create_late_getattr(dynamic_imports, module_globals, module_name)

Create a __getattr__ function for package-level lazy loading.

Parameter Type Description
dynamic_imports MappingProxyType[str, tuple[str, str]] Dispatch table
module_globals dict[str, object] globals() of the calling module
module_name str __name__ of the calling module

INTROSPECTION_ATTRIBUTES

frozenset of dunder attribute names that are resolved immediately rather than proxied (e.g. __doc__, __name__, __module__). Available for reference when implementing custom proxy patterns.

License

MIT OR Apache-2.0 — see LICENSE-MIT and LICENSE-Apache-2.0.

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

lateimport-0.1.0.tar.gz (38.0 kB view details)

Uploaded Source

Built Distribution

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

lateimport-0.1.0-py3-none-any.whl (16.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: lateimport-0.1.0.tar.gz
  • Upload date:
  • Size: 38.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for lateimport-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8da4efbaaa21f4e6f42ef072b7ccd8a16c9bcd1cfc8640de8577419942f327aa
MD5 be765c50b7b6058ff5f89e921da3b4da
BLAKE2b-256 796236f8a340120e167889ec3760d8dc61af101779fbf601a3d400c3ac829172

See more details on using hashes here.

Provenance

The following attestation bundles were made for lateimport-0.1.0.tar.gz:

Publisher: publish.yml on knitli/lateimport

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

  • Download URL: lateimport-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 16.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for lateimport-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6eb33d131f72722a9e3ca9fba33233abafd77e1fa7f7e0cd9292bd368928dd37
MD5 3f4d5f6dc7adab5c8a7ff017986ac4c0
BLAKE2b-256 ffb5435c78e583f3d53bc6bccad2fd65aacea158a244624eb0505d4fd8c97a61

See more details on using hashes here.

Provenance

The following attestation bundles were made for lateimport-0.1.0-py3-none-any.whl:

Publisher: publish.yml on knitli/lateimport

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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