A Python library that lets you delay module imports to when the import is used.
Project description
delayed-import
delayed-import is a Python library that lets you selectively change the behavior of import statements to delay the actual import action. It can be enabled/disabled per module and should work mostly transparently otherwise.
Installation
Install delayed-import with any Python package manager.
Motivation
Suppose you have a module mod1 that imports a library function, defines a function of its own, and optionally calls both on some user input when executed as a script:
import sys
from package1.package2 import func1
def func2(text: str) -> str:
return f"func2: {text}"
if __name__ == "__main__":
user_input = sys.argv[1]
print(func1(user_input))
print(func2(user_input))
When executing this as a script, it works as expected. But maybe another module would like to import mod1 as a library and only call func2. To do so, func1 must first be imported, which may depending on the structure of the containing packages entail a lot of extra work.
To make this module lighter to import, you could move the import of func1 to inside the if __name__ == "__main__": block. But this is not always an easy refactor and might lead to many repeated import statements. This library offers an alternative, by making the import delayed: this means that when you write the import statement, the name func1 is assigned a wrapper object that will resolve to the actual func1 when it is used. The lazy-object-proxy package is used for this.
The modified example would look like this:
import delayed_import
# Enable delayed imports in the current module and all submodules.
delayed_import.enable(__name__)
import sys
from package1.package2 import func1
def func2(text: str) -> str:
return f"func2: {text}"
if __name__ == "__main__":
user_input = sys.argv[1]
print(func1(user_input))
print(func2(user_input))
This code will function the same, except that the imports of package1 and package1.package2 are delayed until the moment they are used, when func1 is called. That means that if this file is imported as a module, they will not be imported at all. (Actually, the import of sys is similarly delayed, though it is likely already imported by this point.) It would be roughly equivalent to the following:
def func2(text: str) -> str:
return f"func2: {text}"
if __name__ == "__main__":
import sys
user_input = sys.argv[1]
from package1.package2 import func1
print(func1(user_input))
print(func2(user_input))
Usage
To use in a module, import the library and call enable with the module name:
import delayed_import
delayed_import.enable(__name__)
This makes all import statements that are executed in that module from that point on delayed. It is possible to later disable delayed imports by calling disable with the module name.
import delayed_import
delayed_import.enable(__name__)
# ...delayed imports...
delayed_import.disable(__name__)
# ...regular imports...
A block of imports can also be delayed by using enable as a context manager.
import delayed_import
with delayed_import.enable(__name__):
# ...delayed imports...
# ...regular imports...
When enabling delayed imports, this will also affect submodules, allowing you to enable/disable them for entire code trees at once. You can mix enabling and disabling, i.e. if a enables them, and a.b disables them, then in a.c they will be enabled and in a.b.d they will be disabled.
It is possible to enable delayed imports for any module, not just for the current one. However, since delayed imported objects are not equivalent to their non-delayed equivalents, it might be necessary to adjust the importing code to take this difference into account.
Caveats
The main caveats have to do with the wrapping of the imported objects. This means that the imported object is not actually the same object as the one in the imported module. However, lazy-object-proxy wraps the object pretty thouroughly, so this is rarely observable. The biggest difference is that referential equality will be broken. So the following will fail with an AssertionError:
import delayed_import
delayed_import.enable(__name__)
# x1 wraps x, to delay the import.
from package1 import x as x1
delayed_import.disable(__name__)
# x2 is the real x, since delayed imports are disabled.
from package1 import x as x2
# This will work...
assert x1 == x2
# ...but this will fail!
assert x1 is x2
Moreover, because a new wrapper is created for every import statement, importing the same object twice will also not compare equal with is.
Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please make sure to update tests as appropriate.
License
Acknowledgements
README template from https://www.makeareadme.com.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file delayed_import-0.1.0.tar.gz.
File metadata
- Download URL: delayed_import-0.1.0.tar.gz
- Upload date:
- Size: 12.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1389e1c6a06804d702e18216ba312d8e6ce1570c7c041c1550b6b4cd8d426b76
|
|
| MD5 |
96c3941bf9657afb51f0c03ee7549ad6
|
|
| BLAKE2b-256 |
73efdcbeb4e98c60891b9b8bd4ac690097c529ea7ff1bac6dfae1a6ee87b64e1
|
Provenance
The following attestation bundles were made for delayed_import-0.1.0.tar.gz:
Publisher:
python-publish.yml on nardi/python-delayed-import
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
delayed_import-0.1.0.tar.gz -
Subject digest:
1389e1c6a06804d702e18216ba312d8e6ce1570c7c041c1550b6b4cd8d426b76 - Sigstore transparency entry: 222947812
- Sigstore integration time:
-
Permalink:
nardi/python-delayed-import@2c991e1fea098454e13620d2ed45fab44f191259 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/nardi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@2c991e1fea098454e13620d2ed45fab44f191259 -
Trigger Event:
release
-
Statement type:
File details
Details for the file delayed_import-0.1.0-py3-none-any.whl.
File metadata
- Download URL: delayed_import-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b249a885f347a00a1ed64d3340842c45d154fc1216ec20134b0e762b27746b9
|
|
| MD5 |
82de4a18a701d11ef8b6147d8ce5831f
|
|
| BLAKE2b-256 |
fcd5fb603b40be4b3bf5d2dd31e4db3d0c5fe72b0d1a7ef7a9ebdf28e53f5bec
|
Provenance
The following attestation bundles were made for delayed_import-0.1.0-py3-none-any.whl:
Publisher:
python-publish.yml on nardi/python-delayed-import
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
delayed_import-0.1.0-py3-none-any.whl -
Subject digest:
3b249a885f347a00a1ed64d3340842c45d154fc1216ec20134b0e762b27746b9 - Sigstore transparency entry: 222947826
- Sigstore integration time:
-
Permalink:
nardi/python-delayed-import@2c991e1fea098454e13620d2ed45fab44f191259 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/nardi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@2c991e1fea098454e13620d2ed45fab44f191259 -
Trigger Event:
release
-
Statement type: