Package: lazi
Lazi: Lazy Imports EverywhereAn easy way to implement and track lazy imports globally.No external dependencies.Requires Python >= 3.10, and 3.11 is HIGHLY Recommended.Usage:poetryaddlaziTRACE=1python3>>>importlazi.auto>>>importdjango>>>django.VERSION[7FD30C5BD2B0] LAZY >>>> [7FD30C84E0C0] django VERSION  # Lazy loaded django due to VERSION attr access.[7FD30C5BD080] LAZY <<<< [7FD30C5BD030] django.utils version = [7FD30C5BD6C0]  # Ditto for django.utils setattr.[7FD30C5BD6C0] LAZY >>>> [7FD30C5BD170] django.utils|version get_version # Accessing get_version in django.utils.version.[7FD30C5BE200] LAZY >>>> [7FD30C5BE110] django.utils|regex_helper _lazy_re_compile[7FD30C5BE5C0] LAZY >>>> [7FD30C5BE4D0] django.utils|functional SimpleLazyObject(4, 2, 1, 'final', 0)>>>_And withTRACE=3:>>>importlazi.auto[7F4C28B37350] HOOK Finder refs:0 inst:0 sys:5>>>importdjango[7F4C28B37350] FIND pyc  django *[7F4C289BD5D0] CREA LAZY [7F4C28C4A160] django ....  # This is where the a module is set up.>>>django.VERSION[7F4C289BD5D0] LAZY >>>> [7F4C28C4A160] django VERSION[7F4C289BD5D0] LAZY EXEC [7F4C28C4A160] django >>>>[7F4C28B37350] FIND pyc  django.utils[7F4C289BD080] CREA LAZY [7F4C289BD0D0] django.utils ....[7F4C28B37350] FIND pyc  django.utils|version[7F4C289BD800] CREA LAZY [7F4C289BD490] django.utils|version ....[7F4C289BD080] LAZY >>>> [7F4C289BD0D0] django.utils version = [7F4C289BD800][7F4C289BD080] LAZY EXEC [7F4C289BD0D0] django.utils >>>>[7F4C289BD080] EXEC LOAD [7F4C289BD0D0] django.utils ++++[7F4C289BD800] LAZY >>>> [7F4C289BD490] django.utils|version get_version[7F4C289BD800] LAZY EXEC [7F4C289BD490] django.utils|version >>>>[7F4C28B37350] FIND pycS datetime *  # "S" means it's a stdlib module. "B" means it's a builtin module.[7F4C289BDF30] CREA LAZY [7F4C289BDF80] datetime ....[7F4C28B37350] FIND pycS subprocess *[7F4C289BE020] CREA LAZY [7F4C289BE070] subprocess ....[7F4C28B37350] FIND pyc  django.utils|regex_helper[7F4C289BE0C0] CREA LAZY [7F4C289BDFD0] django.utils|regex_helper ....[7F4C289BE0C0] LAZY >>>> [7F4C289BDFD0] django.utils|regex_helper _lazy_re_compile[7F4C289BE0C0] LAZY EXEC [7F4C289BDFD0] django.utils|regex_helper >>>>[7F4C28B37350] FIND pyc  django.utils|functional[7F4C289BE4D0] CREA LAZY [7F4C289BE3E0] django.utils|functional ....[7F4C289BE4D0] LAZY >>>> [7F4C289BE3E0] django.utils|functional SimpleLazyObject[7F4C289BE4D0] LAZY EXEC [7F4C289BE3E0] django.utils|functional >>>>[7F4C28B37350] FIND pycS copy *[7F4C289BF830] CREA LAZY [7F4C289BF380] copy ....[7F4C289BE4D0] EXEC LOAD [7F4C289BE3E0] django.utils|functional ++++[7F4C289BE0C0] EXEC LOAD [7F4C289BDFD0] django.utils|regex_helper ++++[7F4C289BD800] EXEC LOAD [7F4C289BD490] django.utils|version ++++[7F4C289BD5D0] EXEC LOAD [7F4C28C4A160] django ++++  # This is where a lazy module is fully loaded.(4, 2, 1, 'final', 0)>>>exit()[7F4C289BF830] LAZY DEAD [7F4C289BF380] copy[7F4C289BE4D0] LOAD DEAD [7F4C289BE3E0] django.utils|functional[7F4C289BE0C0] LOAD DEAD [7F4C289BDFD0] django.utils|regex_helper[7F4C289BE020] LAZY DEAD [7F4C289BE070] subprocess[7F4C289BDF30] LAZY DEAD [7F4C289BDF80] datetime[7F4C289BD800] LOAD DEAD [7F4C289BD490] django.utils|version[7F4C289BD080] LOAD DEAD [7F4C289BD0D0] django.utils[7F4C289BD5D0] LOAD DEAD [7F4C28C4A160] djangoUse for specific modules:>>>fromlazi.coreimportlazi>>>withlazi:...importdjango...print(django.VERSION)...(4, 2, 1, 'final', 0)>>>_Or:>>>fromlazi.coreimportlazy>>>django=lazy("django")>>>django.VERSION(4, 2, 1, 'final', 0)>>>_Tricky SituationsExpected global state is not there.This is the most common issue when usinglazi.auto, and can be difficult to debug.Fortunately, Lazi wraps the original exception before it poetentially gets transformed into anImportError.Example (withTRACE=0):>>>importlazi.auto>>>importpandas.core.nanopsTraceback (most recent call last):File"/home/jq/pr/lazi/lazi/core/loader.py", line115, inexec_moduleself.loader.exec_module(targetiftargetisnotNoneelsemodule)File"<frozen importlib._bootstrap_external>", line940, inexec_moduleFile"<frozen importlib._bootstrap>", line241, in_call_with_frames_removedFile"<site-packages>/pandas/core/nanops.py", line74, in<module>set_use_bottleneck(get_option("compute.use_bottleneck"))^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File"<site-packages>/pandas/_config/config.py", line261, in__call__returnself.__func__(*args,**kwds)^^^^^^^^^^^^^^^^^^^^^^^^^^^^File"<site-packages>/pandas/_config/config.py", line135, in_get_optionkey=_get_single_key(pat,silent)^^^^^^^^^^^^^^^^^^^^^^^^^^^^File"<site-packages>/pandas/_config/config.py", line121, in_get_single_keyraiseOptionError(f"No such keys(s):{repr(pat)}")pandas._config.config.OptionError:No such keys(s): 'compute.use_bottleneck'The above exception was the direct cause of the following exception:Traceback (most recent call last):File"<stdin>", line1, in<module>File"/home/jq/pr/lazi/lazi/core/module.py", line102, in__setattr__spec.loader.exec_module(self,True)File"/home/jq/pr/lazi/lazi/core/loader.py", line115, inexec_moduleself.loader.exec_module(targetiftargetisnotNoneelsemodule)File"<site-packages>/pandas/__init__.py", line48, in<module>frompandas.core.apiimport(File"/home/jq/pr/lazi/lazi/core/module.py", line75, in__getattribute__spec.loader.exec_module(self,True)File"/home/jq/pr/lazi/lazi/core/loader.py", line115, inexec_moduleself.loader.exec_module(targetiftargetisnotNoneelsemodule)File"<site-packages>/pandas/core/api.py", line27, in<module>frompandas.core.arraysimportCategoricalFile"/home/jq/pr/lazi/lazi/core/module.py", line75, in__getattribute__spec.loader.exec_module(self,True)File"/home/jq/pr/lazi/lazi/core/loader.py", line115, inexec_moduleself.loader.exec_module(targetiftargetisnotNoneelsemodule)File"<site-packages>/pandas/core/arrays/__init__.py", line19, in<module>frompandas.core.arrays.sparseimportSparseArrayFile"/home/jq/pr/lazi/lazi/core/module.py", line75, in__getattribute__spec.loader.exec_module(self,True)File"/home/jq/pr/lazi/lazi/core/loader.py", line115, inexec_moduleself.loader.exec_module(targetiftargetisnotNoneelsemodule)File"<site-packages>/pandas/core/arrays/sparse/__init__.py", line1, in<module>frompandas.core.arrays.sparse.accessorimport(File"/home/jq/pr/lazi/lazi/core/module.py", line75, in__getattribute__spec.loader.exec_module(self,True)File"/home/jq/pr/lazi/lazi/core/loader.py", line115, inexec_moduleself.loader.exec_module(targetiftargetisnotNoneelsemodule)File"<site-packages>/pandas/core/arrays/sparse/accessor.py", line16, in<module>frompandas.core.arrays.sparse.arrayimportSparseArrayFile"/home/jq/pr/lazi/lazi/core/module.py", line75, in__getattribute__spec.loader.exec_module(self,True)File"/home/jq/pr/lazi/lazi/core/loader.py", line115, inexec_moduleself.loader.exec_module(targetiftargetisnotNoneelsemodule)File"<site-packages>/pandas/core/arrays/sparse/array.py", line101, in<module>frompandas.core.nanopsimportcheck_below_min_countFile"/home/jq/pr/lazi/lazi/core/module.py", line75, in__getattribute__spec.loader.exec_module(self,True)File"/home/jq/pr/lazi/lazi/core/loader.py", line136, inexec_moduleraiseLoader.Error(f"Error loading{name_}"ifnot__debug__elsemsg)fromelazi.core.loader.Loader.Error:[7F899C139260] EXEC DEAD [7F899C1382C0] pandas.core|nanops !!!! OptionError>>>_Unforunately... This isn't something that can be worked around without outer dependency tracking, which
generally results in entire packages getting loaded anyway.If you're more interested in just tracking imports with Lazi, use theNO_HOOKorNO_LAZYconfig variables (see below andlazi/conf/base.py).ConfigurationThelazi.confnamespace package contains configuration modules
that get autoloaded (in import order) bylazi.conf.conf.
It is fully decoupled from the rest of the codebase.As a result, it's possible configure Lazi by creatinglazi.confmodules in your project (within thelazi.confnamespace package),
and use conf modules provided by other packages.Configuration variables can also be set from the environment.It's also possible to manually change the configuration at runtime,
with the caveat that some variables may have already been used bylazi.core. To avoid this, configure Lazi before importing it:fromlazi.confimportconfconf.TRACE=1importlazi.auto# ...