{"id":891,"library":"lazy-loader","title":"Lazy Loader","description":"The `lazy-loader` library makes it easy to load Python subpackages and functions on demand. This utility is designed to help projects, especially in the scientific Python ecosystem, reduce startup time and memory usage by deferring module imports until the imported objects are actually accessed. It is actively maintained, currently at version 0.5, and sees regular updates to enhance functionality and fix bugs.","status":"active","version":"0.5","language":"python","source_language":"en","source_url":"https://github.com/scientific-python/lazy-loader","tags":["lazy loading","import","optimization","startup performance","module loading","scientific python"],"install":[{"cmd":"pip install lazy-loader","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"note":"Used within a package's `__init__.py` to lazily expose subpackages or attributes.","symbol":"lazy.attach","correct":"import lazy_loader as lazy\n__getattr__, __dir__, _ = lazy.attach(__name__, __file__, subpackages=['my_subpackage'])"},{"note":"Used to lazily import an entire external module. The module is only loaded when `external_module` is first accessed.","symbol":"lazy.load","correct":"import lazy_loader as lazy\nexternal_module = lazy.load('some_external_library')"}],"quickstart":{"code":"import lazy_loader as lazy\nimport os\n\n# This would typically be in your package's __init__.py\n# For demonstration, we simulate it.\n\n# Define a dummy 'heavy_module' that prints when imported\n# In a real scenario, this would be a separate file or external library\nwith open('heavy_module.py', 'w') as f:\n    f.write(\"\"\"print('heavy_module imported!')\ndef expensive_func():\n    return 'Result from expensive_func'\n\"\"\")\n\n# Create a dummy package directory and __init__.py\nos.makedirs('mypackage', exist_ok=True)\nwith open('mypackage/__init__.py', 'w') as f:\n    f.write(\"\"\"import lazy_loader as lazy\n\n__getattr__, __dir__, _ = lazy.attach(\n    __name__, __file__,\n    subpackages=[\n        'heavy_module', # This will be lazily loaded\n    ],\n    attributes={\n        'my_utility_func': ('some_utility_module', 'my_utility_func') # Example for external functions\n    }\n)\n\n# If you also wanted to lazy load an external library directly (less common in __init__.py)\n# external_lib = lazy.load('sys') # Example: lazily load 'sys'\n\"\"\")\n\nprint(\"Before importing mypackage\")\nimport mypackage\nprint(\"After importing mypackage (heavy_module not yet loaded)\")\n\n# Accessing an attribute of mypackage.heavy_module triggers its load\nresult = mypackage.heavy_module.expensive_func()\nprint(f\"Accessed heavy_module: {result}\")\n\n# Clean up dummy files\nos.remove('heavy_module.py')\nos.remove('mypackage/__init__.py')\nos.rmdir('mypackage')","lang":"python","description":"This example demonstrates how to use `lazy.attach` within a package's `__init__.py` to lazily load submodules. The `heavy_module` is only imported (and its 'imported!' message printed) when one of its attributes is first accessed, not during the initial `import mypackage` statement. This is the primary use case for `lazy-loader` to improve package import times."},"warnings":[{"fix":"For `lazy-loader` versions 0.4 and later, do not use the `subpackages` argument with `lazy.attach()`. Instead, `lazy.attach(__name__, __file__)` should be used for the package itself. Subpackage lazy loading should be handled by explicitly defining `__getattr__` or `__dir__` to return submodules, or by using `lazy.load` within these functions. If you require the functionality of `subpackages` for `lazy.attach`, you would need to downgrade to `lazy-loader` version `0.3.x`.","message":"The `subpackages` argument for `lazy.attach()` was removed in `lazy-loader` version 0.4. Attempting to use this argument will result in a `TypeError`. The previous recommendation for lazily loading subpackages using this argument is no longer valid.","severity":"breaking","affected_versions":"0.4 and later"},{"fix":"Upgrade Python to version 3.11.9 or later, or 3.12.3 or later, to avoid these known race conditions.","message":"Users on specific patch versions of Python 3.11 and 3.12 may encounter a known race condition due to upstream Python bugs affecting `lazy-loader`'s functionality.","severity":"breaking","affected_versions":"<3.11.9, <3.12.3"},{"fix":"Set the `EAGER_IMPORT` environment variable to `1` (e.g., `EAGER_IMPORT=1 python your_script.py`) to force eager loading of all modules managed by `lazy-loader`. This allows import errors to surface immediately upon program startup.","message":"Lazy loading can defer import errors until runtime, making early detection of missing dependencies or typos harder during development. For debugging, `lazy-loader` can be disabled.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure the package name in the `require` argument precisely matches the distribution name. For example, `pyyaml` is the distribution name for the `yaml` module.","message":"When using the `require` argument in `lazy.load()` to specify version requirements (e.g., `lazy.load('numpy', require='numpy>=1.24')`), the requirement string must use the *package distribution name* (as found on PyPI), not necessarily the module import name.","severity":"gotcha","affected_versions":"0.4 and later"}],"env_vars":null,"last_verified":"2026-05-12T20:58:58.747Z","next_check":"2026-06-27T00:00:00.000Z","problems":[{"fix":"First, ensure the library is installed with `pip install lazy-loader`. Then, in your Python code, use `import lazy_loader` or `from lazy_loader import ...`.","cause":"The user attempted to import the `lazy-loader` library using an incorrect package name. The correct package name is `lazy-loader` (installed via `pip install lazy-loader`), which is then imported as `lazy_loader` in Python code.","error":"ModuleNotFoundError: No module named 'lazy-load'"},{"fix":"If encountering this in a multithreaded context, ensure proper synchronization around the first access of lazily loaded modules. For Python 3.11 or 3.12, upgrade to patch versions 3.11.9+ or 3.12.3+ respectively. During debugging or for problematic scenarios, setting the environment variable `EAGER_IMPORT` to `\"1\"` (e.g., `EAGER_IMPORT=1 python your_script.py`) can temporarily disable lazy loading to identify if it's the root cause.","cause":"This error often occurs when a lazily loaded module is accessed prematurely in a multithreaded or concurrent environment before it has been fully initialized, leading to an incomplete module object. It can also stem from known race conditions in specific Python versions (e.g., Python 3.11 prior to 3.11.9 or 3.12 prior to 3.12.3).","error":"AttributeError: module 'your_module' has no attribute 'your_attribute'"},{"fix":"Review your `lazy_loader` configuration to ensure it's not inadvertently triggering eager loads. Avoid using `lazy_loader.load('parent_package.sub_package')` as it is discouraged and can cause the parent to load immediately. If this behavior persists despite correct configuration, check the official `lazy-loader` GitHub repository for known bugs and potential workarounds or updates. Setting `EAGER_IMPORT='1'` can help confirm if eager loading is indeed occurring.","cause":"This is a reported behavioral issue where `lazy-loader` might unexpectedly import all specified modules eagerly, even when only a subset or a missing module is accessed, thus defeating the performance benefits of lazy loading. This can also happen if `lazy_loader.load()` is used for a subpackage (e.g., `lazy_loader.load('parent_package.sub_package')`), which immediately imports the parent package.","error":"All lazy-loaded packages are imported at once (unexpected eager loading)"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":null,"quickstart_tag":null,"pypi_latest":"0.5","cli_name":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.6,"disk_size":"18.6M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.6,"disk_size":"18.4M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0.01,"mem_mb":0.6,"disk_size":"19M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.6,"disk_size":"19M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.9,"disk_size":"20.5M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.9,"disk_size":"20.3M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.7,"import_time_s":0.01,"mem_mb":0.9,"disk_size":"21M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.9,"disk_size":"21M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.7,"disk_size":"12.4M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.7,"disk_size":"12.2M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.5,"import_time_s":0.01,"mem_mb":0.7,"disk_size":"13M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.7,"disk_size":"13M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.9,"disk_size":"12.1M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.9,"disk_size":"11.8M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.5,"import_time_s":0.01,"mem_mb":0.7,"disk_size":"13M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.7,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":1.2,"disk_size":"18.1M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":1.2,"disk_size":"17.9M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.8,"import_time_s":0.01,"mem_mb":1.2,"disk_size":"19M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":1.2,"disk_size":"18M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":null,"tag_description":null,"results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}