{"id":19421490,"url":"https://github.com/sitbon/lazi","last_synced_at":"2026-05-29T16:31:22.957Z","repository":{"id":163781694,"uuid":"638837892","full_name":"sitbon/lazi","owner":"sitbon","description":"An easy way to implement lazy imports globally.","archived":false,"fork":false,"pushed_at":"2023-05-26T18:14:13.000Z","size":261,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-18T16:34:56.700Z","etag":null,"topics":["auto-load","import","inspection","lazy-loading","modules","python"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/lazi","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sitbon.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-10T08:03:30.000Z","updated_at":"2025-08-06T02:50:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"a8004ecb-1488-4c71-a5a0-dac890462e9e","html_url":"https://github.com/sitbon/lazi","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sitbon/lazi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitbon%2Flazi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitbon%2Flazi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitbon%2Flazi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitbon%2Flazi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sitbon","download_url":"https://codeload.github.com/sitbon/lazi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitbon%2Flazi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33662205,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["auto-load","import","inspection","lazy-loading","modules","python"],"created_at":"2024-11-10T13:28:28.376Z","updated_at":"2026-05-29T16:31:22.942Z","avatar_url":"https://github.com/sitbon.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lazi: Lazy Imports Everywhere\n\nAn easy way to implement and track lazy imports globally.\n\nNo external dependencies.\n\n**Requires Python \u003e= 3.10, and 3.11 is HIGHLY Recommended.**\n\n## Usage:\n\n```shell\npoetry add lazi\n```\n```shell\nTRACE=1 python3\n```\n```pycon\n\u003e\u003e\u003e import lazi.auto\n\u003e\u003e\u003e import django\n\u003e\u003e\u003e django.VERSION\n[7FD30C5BD2B0] LAZY \u003e\u003e\u003e\u003e [7FD30C84E0C0] django VERSION  # Lazy loaded django due to VERSION attr access.\n[7FD30C5BD080] LAZY \u003c\u003c\u003c\u003c [7FD30C5BD030] django.utils version = [7FD30C5BD6C0]  # Ditto for django.utils setattr.\n[7FD30C5BD6C0] LAZY \u003e\u003e\u003e\u003e [7FD30C5BD170] django.utils|version get_version # Accessing get_version in django.utils.version.\n[7FD30C5BE200] LAZY \u003e\u003e\u003e\u003e [7FD30C5BE110] django.utils|regex_helper _lazy_re_compile\n[7FD30C5BE5C0] LAZY \u003e\u003e\u003e\u003e [7FD30C5BE4D0] django.utils|functional SimpleLazyObject\n(4, 2, 1, 'final', 0)\n\u003e\u003e\u003e _\n```\n\nAnd with `TRACE=3`:\n\n```pycon\n\u003e\u003e\u003e import lazi.auto\n[7F4C28B37350] HOOK Finder refs:0 inst:0 sys:5 \n\u003e\u003e\u003e import django\n[7F4C28B37350] FIND pyc  django *\n[7F4C289BD5D0] CREA LAZY [7F4C28C4A160] django ....  # This is where a lazy module is set up.\n\u003e\u003e\u003e django.VERSION\n[7F4C289BD5D0] LAZY \u003e\u003e\u003e\u003e [7F4C28C4A160] django VERSION\n[7F4C289BD5D0] LAZY EXEC [7F4C28C4A160] django \u003e\u003e\u003e\u003e \n[7F4C28B37350] FIND pyc  django.utils \n[7F4C289BD080] CREA LAZY [7F4C289BD0D0] django.utils .... \n[7F4C28B37350] FIND pyc  django.utils|version \n[7F4C289BD800] CREA LAZY [7F4C289BD490] django.utils|version .... \n[7F4C289BD080] LAZY \u003e\u003e\u003e\u003e [7F4C289BD0D0] django.utils version = [7F4C289BD800]\n[7F4C289BD080] LAZY EXEC [7F4C289BD0D0] django.utils \u003e\u003e\u003e\u003e \n[7F4C289BD080] EXEC LOAD [7F4C289BD0D0] django.utils ++++ \n[7F4C289BD800] LAZY \u003e\u003e\u003e\u003e [7F4C289BD490] django.utils|version get_version\n[7F4C289BD800] LAZY EXEC [7F4C289BD490] django.utils|version \u003e\u003e\u003e\u003e \n[7F4C28B37350] FIND pycS datetime *  # \"S\" means it's a stdlib module. \"B\" means it's a builtin module.\n[7F4C289BDF30] CREA LAZY [7F4C289BDF80] datetime .... \n[7F4C28B37350] FIND pycS subprocess *\n[7F4C289BE020] CREA LAZY [7F4C289BE070] subprocess .... \n[7F4C28B37350] FIND pyc  django.utils|regex_helper \n[7F4C289BE0C0] CREA LAZY [7F4C289BDFD0] django.utils|regex_helper .... \n[7F4C289BE0C0] LAZY \u003e\u003e\u003e\u003e [7F4C289BDFD0] django.utils|regex_helper _lazy_re_compile\n[7F4C289BE0C0] LAZY EXEC [7F4C289BDFD0] django.utils|regex_helper \u003e\u003e\u003e\u003e \n[7F4C28B37350] FIND pyc  django.utils|functional \n[7F4C289BE4D0] CREA LAZY [7F4C289BE3E0] django.utils|functional .... \n[7F4C289BE4D0] LAZY \u003e\u003e\u003e\u003e [7F4C289BE3E0] django.utils|functional SimpleLazyObject\n[7F4C289BE4D0] LAZY EXEC [7F4C289BE3E0] django.utils|functional \u003e\u003e\u003e\u003e \n[7F4C28B37350] FIND pycS copy *\n[7F4C289BF830] CREA LAZY [7F4C289BF380] copy .... \n[7F4C289BE4D0] EXEC LOAD [7F4C289BE3E0] django.utils|functional ++++ \n[7F4C289BE0C0] EXEC LOAD [7F4C289BDFD0] django.utils|regex_helper ++++ \n[7F4C289BD800] EXEC LOAD [7F4C289BD490] django.utils|version ++++ \n[7F4C289BD5D0] EXEC LOAD [7F4C28C4A160] django ++++  # This is where a lazy module is fully loaded. \n(4, 2, 1, 'final', 0)\n\u003e\u003e\u003e exit()\n[7F4C289BF830] LAZY DEAD [7F4C289BF380] copy\n[7F4C289BE4D0] LOAD DEAD [7F4C289BE3E0] django.utils|functional\n[7F4C289BE0C0] LOAD DEAD [7F4C289BDFD0] django.utils|regex_helper\n[7F4C289BE020] LAZY DEAD [7F4C289BE070] subprocess\n[7F4C289BDF30] LAZY DEAD [7F4C289BDF80] datetime\n[7F4C289BD800] LOAD DEAD [7F4C289BD490] django.utils|version\n[7F4C289BD080] LOAD DEAD [7F4C289BD0D0] django.utils\n[7F4C289BD5D0] LOAD DEAD [7F4C28C4A160] django\n```\n\n### Use for specific modules:\n\n```pycon\n\u003e\u003e\u003e from lazi.core import lazi\n\u003e\u003e\u003e with lazi:\n...   import django\n...   print(django.VERSION)\n... \n(4, 2, 1, 'final', 0)\n\u003e\u003e\u003e _\n```\n\nOr:\n\n```pycon\n\u003e\u003e\u003e from lazi.core import lazy\n\u003e\u003e\u003e django = lazy(\"django\")\n\u003e\u003e\u003e django.VERSION\n(4, 2, 1, 'final', 0)\n\u003e\u003e\u003e _\n```\n\n## Tricky Situations\n\n### Expected global state is not there.\n\nThis is the most common issue when using `lazi.auto`, and can be difficult to debug.\n\nFortunately, Lazi wraps the original exception before it poetentially gets transformed into an `ImportError`.\n\nExample (with `TRACE=0`):\n```pycon\n\u003e\u003e\u003e import lazi.auto\n\u003e\u003e\u003e import pandas.core.nanops\nTraceback (most recent call last):\n  File \"/home/jq/pr/lazi/lazi/core/loader.py\", line 115, in exec_module\n    self.loader.exec_module(target if target is not None else module)\n  File \"\u003cfrozen importlib._bootstrap_external\u003e\", line 940, in exec_module\n  File \"\u003cfrozen importlib._bootstrap\u003e\", line 241, in _call_with_frames_removed\n  File \"\u003csite-packages\u003e/pandas/core/nanops.py\", line 74, in \u003cmodule\u003e\n    set_use_bottleneck(get_option(\"compute.use_bottleneck\"))\n                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"\u003csite-packages\u003e/pandas/_config/config.py\", line 261, in __call__\n    return self.__func__(*args, **kwds)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"\u003csite-packages\u003e/pandas/_config/config.py\", line 135, in _get_option\n    key = _get_single_key(pat, silent)\n          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"\u003csite-packages\u003e/pandas/_config/config.py\", line 121, in _get_single_key\n    raise OptionError(f\"No such keys(s): {repr(pat)}\")\npandas._config.config.OptionError: No such keys(s): 'compute.use_bottleneck'\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n  File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\n  File \"/home/jq/pr/lazi/lazi/core/module.py\", line 102, in __setattr__\n    spec.loader.exec_module(self, True)\n  File \"/home/jq/pr/lazi/lazi/core/loader.py\", line 115, in exec_module\n    self.loader.exec_module(target if target is not None else module)\n  File \"\u003csite-packages\u003e/pandas/__init__.py\", line 48, in \u003cmodule\u003e\n    from pandas.core.api import (\n  File \"/home/jq/pr/lazi/lazi/core/module.py\", line 75, in __getattribute__\n    spec.loader.exec_module(self, True)\n  File \"/home/jq/pr/lazi/lazi/core/loader.py\", line 115, in exec_module\n    self.loader.exec_module(target if target is not None else module)\n  File \"\u003csite-packages\u003e/pandas/core/api.py\", line 27, in \u003cmodule\u003e\n    from pandas.core.arrays import Categorical\n  File \"/home/jq/pr/lazi/lazi/core/module.py\", line 75, in __getattribute__\n    spec.loader.exec_module(self, True)\n  File \"/home/jq/pr/lazi/lazi/core/loader.py\", line 115, in exec_module\n    self.loader.exec_module(target if target is not None else module)\n  File \"\u003csite-packages\u003e/pandas/core/arrays/__init__.py\", line 19, in \u003cmodule\u003e\n    from pandas.core.arrays.sparse import SparseArray\n  File \"/home/jq/pr/lazi/lazi/core/module.py\", line 75, in __getattribute__\n    spec.loader.exec_module(self, True)\n  File \"/home/jq/pr/lazi/lazi/core/loader.py\", line 115, in exec_module\n    self.loader.exec_module(target if target is not None else module)\n  File \"\u003csite-packages\u003e/pandas/core/arrays/sparse/__init__.py\", line 1, in \u003cmodule\u003e\n    from pandas.core.arrays.sparse.accessor import (\n  File \"/home/jq/pr/lazi/lazi/core/module.py\", line 75, in __getattribute__\n    spec.loader.exec_module(self, True)\n  File \"/home/jq/pr/lazi/lazi/core/loader.py\", line 115, in exec_module\n    self.loader.exec_module(target if target is not None else module)\n  File \"\u003csite-packages\u003e/pandas/core/arrays/sparse/accessor.py\", line 16, in \u003cmodule\u003e\n    from pandas.core.arrays.sparse.array import SparseArray\n  File \"/home/jq/pr/lazi/lazi/core/module.py\", line 75, in __getattribute__\n    spec.loader.exec_module(self, True)\n  File \"/home/jq/pr/lazi/lazi/core/loader.py\", line 115, in exec_module\n    self.loader.exec_module(target if target is not None else module)\n  File \"\u003csite-packages\u003e/pandas/core/arrays/sparse/array.py\", line 101, in \u003cmodule\u003e\n    from pandas.core.nanops import check_below_min_count\n  File \"/home/jq/pr/lazi/lazi/core/module.py\", line 75, in __getattribute__\n    spec.loader.exec_module(self, True)\n  File \"/home/jq/pr/lazi/lazi/core/loader.py\", line 136, in exec_module\n    raise Loader.Error(f\"Error loading {name_}\" if not __debug__ else msg) from e\nlazi.core.loader.Loader.Error: [7F899C139260] EXEC DEAD [7F899C1382C0] pandas.core|nanops !!!! OptionError\n\u003e\u003e\u003e _\n```\n\n_Unforunately_... This isn't something that can be worked around without outer dependency tracking, which\ngenerally results in entire packages getting loaded anyway.\n\nIf you're more interested in just tracking imports with Lazi, use the `NO_HOOK`\nor `NO_LAZY` config variables (see below and [lazi/conf/base.py](lazi/conf/base.py)).\n\n## Configuration\n\nThe `lazi.conf` namespace package contains configuration modules\nthat get autoloaded (in import order) by `lazi.conf.conf`.\nIt is fully decoupled from the rest of the codebase.\n\nAs a result, it's possible configure Lazi by creating `lazi.conf`\nmodules in your project (within the `lazi.conf` namespace package),\nand use conf modules provided by other packages.\n\nConfiguration variables can also be set from the environment.\n\nIt's also possible to manually change the configuration at runtime,\nwith the caveat that some variables may have already been used by\n`lazi.core`. To avoid this, configure Lazi before importing it:\n\n```python\nfrom lazi.conf import conf\n\nconf.TRACE = 1\nimport lazi.auto\n# ...\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsitbon%2Flazi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsitbon%2Flazi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsitbon%2Flazi/lists"}