### Install lazy-loader Source: https://github.com/scientific-python/lazy-loader/blob/main/README.md Install the lazy-loader package using pip. It is recommended to use Python 3.11.9+ or 3.12.3+ to avoid known race conditions. ```bash pip install -U lazy-loader ``` -------------------------------- ### Load optional dependencies with version requirements Source: https://github.com/scientific-python/lazy-loader/blob/main/README.md Lazily load optional dependencies and specify version requirements. If the installed version does not meet the requirement, an error will be raised upon attribute access. ```python np = lazy.load("numpy", require="numpy >=1.24") ``` -------------------------------- ### Create GitHub Release Source: https://github.com/scientific-python/lazy-loader/blob/main/RELEASE.md Manually create a new release on GitHub from the newly pushed tag. This involves setting the release title, pasting the release notes, and optionally marking it as a pre-release. ```bash - go to https://github.com/scientific-python/lazy-loader/releases/new?tag=v${VERSION} - add v${VERSION} for the `Release title` - paste contents (or upload) of ${VERSION}.md in the `Describe this release section` - if pre-release check the box labelled `Set as a pre-release` ``` -------------------------------- ### Update Changelog File Source: https://github.com/scientific-python/lazy-loader/blob/main/RELEASE.md Prepend the newly generated release notes to the main CHANGELOG.md file. This ensures the latest release notes are at the top. ```bash cat ${VERSION}.md | cat - ${LOG} > temp && mv temp ${LOG} ``` -------------------------------- ### Bump Version and Push Source: https://github.com/scientific-python/lazy-loader/blob/main/RELEASE.md After the release is finalized, update the `version` in `src/lazy-loader/__init__.py` to the next development version. Commit this change and push it to the main branch. ```bash git add src/lazy-loader/__init__.py git commit -m 'Bump version' git push origin main ``` -------------------------------- ### Tag the Release Source: https://github.com/scientific-python/lazy-loader/blob/main/RELEASE.md Create an annotated git tag for the release. Use `-s` for signed tags, which is important for Debian packaging. If a GPG key is not available, use `-u`. ```bash git tag -s v${VERSION} -m "signed ${VERSION} tag" ``` -------------------------------- ### Push Tags to GitHub Source: https://github.com/scientific-python/lazy-loader/blob/main/RELEASE.md Push all new tags, including the signed release tag, to the GitHub repository. Ensure `origin` is correctly configured to point to the repository. ```bash git push --tags origin main ``` -------------------------------- ### Lazily load subpackages in __init__.py Source: https://github.com/scientific-python/lazy-loader/blob/main/README.md Use lazy.attach in your package's __init__.py to make subpackages available on demand. The subpackages will only be loaded when accessed. ```python subpackages = [ ..., 'filters', ... ] import lazy_loader as lazy __getattr__, __dir__, _ = lazy.attach(__name__, subpackages) ``` -------------------------------- ### Autogenerate Release Notes Source: https://github.com/scientific-python/lazy-loader/blob/main/RELEASE.md Use the changelist tool to automatically generate release notes based on commit history between two versions. The output is saved to a version-specific markdown file. ```bash changelist ${ORG}/${REPO} v${PREVIOUS} main --version ${VERSION} --config pyproject.toml --out ${VERSION}.md ``` -------------------------------- ### Set Release Variables Source: https://github.com/scientific-python/lazy-loader/blob/main/RELEASE.md Export environment variables to configure the release process. These variables define the version numbers, repository details, and changelog file. ```bash export VERSION= export PREVIOUS= export ORG="scientific-python" export REPO="lazy-loader" export LOG="CHANGELOG.md" ``` -------------------------------- ### Commit Release Changes Source: https://github.com/scientific-python/lazy-loader/blob/main/RELEASE.md Stage and commit the updated `__init__.py` file and the `CHANGELOG.md` file. The commit message should clearly state the version being released. ```bash git add src/lazy-loader/__init__.py ${LOG} git commit -m "Designate ${VERSION} release" ``` -------------------------------- ### Programmatic control of eager loading with unittest.mock Source: https://context7.com/scientific-python/lazy-loader/llms.txt Control eager loading programmatically within tests using `unittest.mock.patch.dict`. This allows simulating the `EAGER_IMPORT` environment variable for specific test blocks. ```python # Programmatic control inside tests: import os from unittest import mock import lazy_loader as lazy # Simulate eager loading environment with mock.patch.dict(os.environ, {"EAGER_IMPORT": "1"}): # Any lazy.attach() call inside this block will eagerly import everything __getattr__, __dir__, __all__ = lazy.attach( "mypackage", submodules=["io"], submod_attrs={"_core": ["func_a", "func_b"]}, ) # func_a, func_b, and io are all imported immediately # Outside the block, lazy loading resumes normally ``` -------------------------------- ### Lazily Attach Submodules and Attributes with lazy.attach Source: https://context7.com/scientific-python/lazy-loader/llms.txt Use this in your package's `__init__.py` to make submodules and attributes load lazily. It replaces the need for explicit imports, deferring them until first use. Eager loading can be enabled via the `EAGER_IMPORT` environment variable. ```python # mypackage/__init__.py import lazy_loader as lazy # Declare which submodules and which attributes from which submodules to expose lazily __getattr__, __dir__, __all__ = lazy.attach( __name__, # always pass __name__ submodules=["utils", "io"], # subpackages exposed as mypackage.utils / mypackage.io submod_attrs={ "_filters": ["gaussian", "sobel"], # from ._filters import gaussian, sobel "_stats": ["mean", "std"], # from ._stats import mean, std }, ) # Equivalent non-lazy version: # from . import utils, io # from ._filters import gaussian, sobel # from ._stats import mean, std # # Usage (in user code): # import mypackage # result = mypackage.gaussian(image) # ._filters is imported here, not at package load # mypackage.utils.helper() # utils subpackage is imported here # # __all__ will be: ['gaussian', 'io', 'mean', 'sobel', 'std', 'utils'] print(__all__) # ['gaussian', 'io', 'mean', 'sobel', 'std', 'utils'] # Force eager loading during tests via environment variable: # EAGER_IMPORT=1 python -m pytest ``` -------------------------------- ### Lazy load modules with lazy.load Source: https://context7.com/scientific-python/lazy-loader/llms.txt Use `lazy.load` to create a proxy for a module that is imported only when an attribute is accessed. Handles missing modules with deferred or immediate errors, and supports version specifiers for optional dependencies. ```python import lazy_loader as lazy # --- Basic lazy load of a standard library module --- math = lazy.load("math") # 'math' is now a lazy proxy; no actual import has occurred yet result = math.sin(math.pi) # import happens here print(result) # ≈ 0.0 # --- Missing module: deferred error --- fake = lazy.load("not_a_real_module") try: fake.something # ModuleNotFoundError raised here, not at load() time except ModuleNotFoundError as e: print(e) # --- Missing module: immediate error --- try: lazy.load("not_a_real_module", error_on_import=True) except ModuleNotFoundError as e: print(e) # raised immediately # --- Optional dependency with version requirement --- np = lazy.load("numpy", require="numpy >=1.24") # If numpy < 1.24 is installed, np behaves like a DelayedImportErrorModule # and raises an error when any attribute is accessed. arr = np.array([1, 2, 3]) # error raised here if version unsatisfied # --- Loading a subpackage (discouraged, triggers eager load of parent) --- import warnings with warnings.catch_warnings(): warnings.simplefilter("ignore", RuntimeWarning) html_parser = lazy.load("html.parser") # html is now eagerly loaded even though html.parser is lazy # --- Thread-safe parallel loading --- import threading, time def worker(): time.sleep(0.1) mod = lazy.load("math") _ = mod.pi # safe across threads threads = [threading.Thread(target=worker) for _ in range(8)] for t in threads: t.start() for t in threads: t.join() ``` -------------------------------- ### lazy.attach Source: https://context7.com/scientific-python/lazy-loader/llms.txt Lazily attach submodules and attributes to a package by setting up `__getattr__`, `__dir__`, and `__all__`. This function should be called in the package's `__init__.py` and its return value assigned directly. ```APIDOC ## lazy.attach — Lazily attach submodules and attributes to a package ### Description Sets up a package's `__getattr__`, `__dir__`, and `__all__` so that listed submodules and submodule attributes are only imported upon first access. This is the primary tool for making a package's internal structure load lazily. It returns a `(getattr, dir, all)` triple that should be assigned directly in the package's `__init__.py`. ### Method ```python lazy.attach(name: str, submodules: list[str] | None = None, submod_attrs: dict[str, list[str]] | None = None) ``` ### Parameters #### Path Parameters - **name** (str) - Required - The name of the package, typically `__name__`. - **submodules** (list[str] | None) - Optional - A list of subpackage names to expose lazily. - **submod_attrs** (dict[str, list[str]] | None) - Optional - A dictionary where keys are submodule names and values are lists of attributes to expose lazily from those submodules. ### Request Example ```python # mypackage/__init__.py import lazy_loader as lazy __getattr__, __dir__, __all__ = lazy.attach( __name__, submodules=["utils", "io"], submod_attrs={ "_filters": ["gaussian", "sobel"], "_stats": ["mean", "std"], }, ) ``` ### Response #### Success Response (200) - **getattr** (function) - A function to be assigned to `__getattr__`. - **dir** (function) - A function to be assigned to `__dir__`. - **all** (list[str]) - A list of all exposed attributes and submodules, to be assigned to `__all__`. ``` -------------------------------- ### Lazily load subpackages and functions Source: https://github.com/scientific-python/lazy-loader/blob/main/README.md Configure lazy loading for both submodules and specific functions within a submodule. This allows granular control over when code is imported. ```python from ..util import lazy __getattr__, __dir__, __all__ = lazy.attach( __name__, submodules=['rank'], submod_attrs={ '_gaussian': ['gaussian', 'difference_of_gaussians'], 'edges': ['sobel', 'scharr', 'prewitt', 'roberts', 'laplace', 'farid'] } ) ``` -------------------------------- ### Update GitHub Milestones Source: https://github.com/scientific-python/lazy-loader/blob/main/RELEASE.md Manage milestones on GitHub by closing the completed milestone and ensuring a new milestone exists for the next release cycle. Consider setting a due date for the new milestone. ```bash - close old milestone - ensure new milestone exists (perhaps setting due date) ``` -------------------------------- ### Attach type stubs for static analysis Source: https://github.com/scientific-python/lazy-loader/blob/main/README.md Use lazy.attach_stub to integrate with static type checkers by loading type stubs from a .pyi file. This is necessary for IDEs and type checkers to infer types correctly. ```python import lazy_loader as lazy __getattr__, __dir__, _ = lazy.attach_stub(__name__, "subpackages.pyi") ``` -------------------------------- ### Lazily load external libraries Source: https://github.com/scientific-python/lazy-loader/blob/main/README.md Import external libraries lazily using lazy.load. The library will only be loaded into memory when one of its attributes is accessed. ```python sp = lazy.load('scipy') # `sp` will only be loaded when accessed sp.linalg.norm(...) ``` -------------------------------- ### Lazily Attach Imports from a Type Stub with lazy.attach_stub Source: https://context7.com/scientific-python/lazy-loader/llms.txt This function automatically infers submodules and attributes from a `.pyi` stub file, enabling lazy loading while satisfying static type checkers. The stub file must be present at runtime. It raises `ValueError` for non-existent stubs, out-of-package imports, or star imports. ```python # mypackage/__init__.py import lazy_loader as lazy # The stub file mypackage/__init__.pyi declares all public imports: # from . import utils, io # from ._filters import gaussian, sobel __getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) # lazy_loader reads __init__.pyi adjacent to __init__.py and # derives submodules/submod_attrs automatically. # ---- mypackage/__init__.pyi (for type checkers AND runtime) ---- # from . import utils # from . import io # from ._filters import gaussian # from ._filters import sobel # Error cases: import tempfile, os, lazy_loader as lazy tmpdir = tempfile.mkdtemp() # 1. Stub file does not exist → ValueError try: lazy.attach_stub("mypkg", "/nonexistent/path/__init__.py") except ValueError as e: print(e) # Cannot load imports from non-existent stub '...' # # 2. Relative import going outside the package (level > 1) → ValueError bad_stub = os.path.join(tmpdir, "bad.pyi") with open(bad_stub, "w") as f: f.write("from ..other import func\n") try: lazy.attach_stub("mypkg", bad_stub) except ValueError as e: print(e) # Only within-module imports are supported (`from .* import`) # # 3. Star imports are forbidden → ValueError star_stub = os.path.join(tmpdir, "star.pyi") with open(star_stub, "w") as f: f.write("from .mod import *\n") try: lazy.attach_stub("mypkg", star_stub) except ValueError as e: print(e) # lazy stub loader does not support star import # ``` -------------------------------- ### lazy.attach_stub Source: https://context7.com/scientific-python/lazy-loader/llms.txt Lazily attach imports declared in a `.pyi` type stub file. This function automatically infers `submodules` and `submod_attrs` from the stub file, allowing static type checkers to work while keeping runtime imports lazy. ```APIDOC ## lazy.attach_stub — Lazily attach imports declared in a `.pyi` type stub ### Description A variant of `attach` that reads a `.pyi` stub file to infer `submodules` and `submod_attrs` automatically, rather than declaring them by hand. This allows static type checkers (mypy, pyright, pylance) and IDEs to discover types normally while keeping runtime imports lazy. The `.pyi` file must exist at runtime as well as during type checking. ### Method ```python lazy.attach_stub(name: str, file_path: str) ``` ### Parameters #### Path Parameters - **name** (str) - Required - The name of the package. - **file_path** (str) - Required - The path to the `.pyi` stub file (e.g., `__file__`). ### Request Example ```python # mypackage/__init__.py import lazy_loader as lazy __getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) ``` ### Response #### Success Response (200) - **getattr** (function) - A function to be assigned to `__getattr__`. - **dir** (function) - A function to be assigned to `__dir__`. - **all** (list[str]) - A list of all exposed attributes and submodules, to be assigned to `__all__`. ### Error Handling - **ValueError**: Raised if the stub file does not exist, if a relative import goes outside the package, or if star imports are used. ``` -------------------------------- ### Handle missing modules with lazy.DelayedImportErrorModule Source: https://context7.com/scientific-python/lazy-loader/llms.txt Use `lazy.DelayedImportErrorModule` as a placeholder for modules that cannot be found. It defers `ModuleNotFoundError` until attribute access and includes the original call-site location in the error message. ```python import lazy_loader as lazy missing = lazy.load("nonexistent_package") # isinstance check lets you guard optional-dependency code paths if isinstance(missing, lazy.DelayedImportErrorModule): print("nonexistent_package is not installed; skipping optional feature") else: missing.do_something() # The error message includes the original call-site location: try: missing.attr except ModuleNotFoundError as e: print(e) # No module named 'nonexistent_package' # # This error is lazily reported, having originally occurred in # File example.py, line 3, in # # ----> missing = lazy.load("nonexistent_package") ``` -------------------------------- ### Eagerly raise import errors Source: https://github.com/scientific-python/lazy-loader/blob/main/README.md Configure lazy.load to raise import errors immediately upon calling the function, rather than deferring the error until the module is accessed. Useful for development and testing. ```python linalg = lazy.load('scipy.linalg', error_on_import=True) ``` -------------------------------- ### Disable lazy loading globally with EAGER_IMPORT Source: https://context7.com/scientific-python/lazy-loader/llms.txt Set the `EAGER_IMPORT` environment variable to disable lazy loading globally. This forces all `lazy.attach`-decorated packages to import submodules and attributes immediately, useful for CI and development to catch import errors early. ```bash # Run your test suite with all lazy imports resolved eagerly, # so missing dependencies fail at import time rather than at use time: EAGER_IMPORT=1 python -m pytest # Explicitly re-enable lazy loading (also the default when unset): EAGER_IMPORT=0 python -c "import mypackage" ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.