importloc
Import Python objects from arbitrary locations specified by string.
Features
- Minimalistic fully typed package
- Import from files or named modules
- Import deeply nested objects
- Import all instances or all subclasses
- Configurable module name conflict resolution
- Atomicity: on import error, new module is removed, and previous, if any, is restored
Installation
$ pip install importloc
Usage
- Various locations
- Various targets
- Custom module name
- What if module is already imported?
- What if object does not exist?
Quick start
The main and most used entity is Location.
from importloc import Location
Various locations
Import from file
Location('app/config.py:conf').load()
Example
>>> loc = Location('app/config.py:conf')
>>> loc
<PathLocation 'app/config.py' obj='conf'>
>>> loc.load()
<config.Config object at 0x...>
Import from module
Location('app.__main__:cli').load()
Example
>>> loc = Location('app.__main__:cli')
>>> loc
<ModuleLocation 'app.__main__' obj='cli'>
>>> loc.load()
<function cli at 0x...>
Distinguish file and module locations
Location('./config.py:conf').load()
Example
>>> loc = Location('config.py:conf')
>>> loc
<ModuleLocation 'config.py' obj='conf'>
>>> loc.load()
Traceback (most recent call last):
...
ModuleNotFoundError: No module named 'config.py'...
Use relative path (similar to Docker bind mount). Path separator will result in
PathLocation instead of ModuleLocation.
>>> loc = Location('./config.py:conf')
>>> loc
<PathLocation 'config.py' obj='conf'>
>>> loc.load()
<config.Config object at 0x...>
Various targets
Import nested class
Location('app/config.py:Config.Nested').load()
Example
>>> loc = Location('app/config.py:Config.Nested')
>>> loc
<PathLocation 'app/config.py' obj='Config.Nested'>
>>> loc.load()
<class 'config.Config.Nested'>
Import module as a whole
Location('app/config.py').load()
Example
>>> loc = Location('app/config.py')
>>> loc
<PathLocation 'app/config.py'>
>>> loc.load()
<module 'config' from '...'>
Use Path object when loading module
Location(Path('config.py')).load()
Example
>>> from pathlib import Path
>>> loc = Location(Path('config.py'))
>>> loc
<PathLocation 'config.py'>
>>> loc.load()
<module 'config' from '...'>
Import all instances of some type
get_instances(Location('app.__main__').load(), Callable)
Example
>>> from collections.abc import Callable
>>> from importloc import get_instances
>>> loc = Location('app.__main__')
>>> loc
<ModuleLocation 'app.__main__'>
>>> get_instances(loc.load(), Callable)
[<function cli at 0x...>]
Import all subclasses
get_subclasses(Location('app.errors').load(), Exception)
Example
>>> from importloc import get_subclasses
>>> loc = Location('app.errors')
>>> loc
<ModuleLocation 'app.errors'>
>>> get_subclasses(loc.load(), Exception)
[<class 'app.errors.Error1'>, <class 'app.errors.Error2'>]
Custom module name
Use different module name
Location('...').load(modname='app_main')
Example
>>> Location('app/config.py:Config').load(modname='app_main')
<class 'app_main.Config'>
Generate module name at run time
Location('...').load(modname=random_name)
Example
>>> from importloc import random_name
>>> Location('app/config.py:Config').load(modname=random_name)
<class 'u....Config'>
What if module is already imported?
The module name conflict can be resolved with one the methods:
reuseexisting module imported beforereloadexisting modulereplaceexisting modulerenamenew module (try to import under new name)raiseexception (default)
For details, see documentation on ConflictResolution.
Module name conflict raises error by default
Location('...').load()
Example
>>> Location('app/config.py:Config').load()
<class 'config.Config'>
>>> Location('app/config.py:Config').load()
Traceback (most recent call last):
...
importloc.exc.ModuleNameConflict: Module "config" is already imported
Reuse module that is already imported
Location('...').load(on_conflict='reuse')
Example
>>> C = Location('app/config.py:Config').load()
>>> C
<class 'config.Config'>
>>> old_id = id(C)
>>> C = Location('app/config.py:Config').load(on_conflict='reuse')
>>> C
<class 'config.Config'>
>>> # C is the same object:
>>> id(C) == old_id
True
Reload module that is already imported
Location('...').load(on_conflict='reload')
Example
>>> import sys
>>> C = Location('app/config.py:Config').load()
>>> C
<class 'config.Config'>
>>> old_id = id(C)
>>> mod_id = id(sys.modules['config'])
>>> C = Location('app/config.py:Config').load(on_conflict='reload')
>>> C
<class 'config.Config'>
>>> # module object remains the same after reloading:
>>> id(sys.modules['config']) == mod_id
True
>>> # C is the new object from reloaded module:
>>> id(C) == old_id
False
Replace old module with imported one
Location('...').load(on_conflict='replace')
Example
>>> import sys
>>> C = Location('app/config.py:Config').load()
>>> C
<class 'config.Config'>
>>> mod_id = id(sys.modules['config'])
>>> C = Location('app/config.py:Config').load(on_conflict='replace')
>>> C
<class 'config.Config'>
>>> # module object is the new one:
>>> id(sys.modules['config']) == mod_id
False
Load module under different generated name
Location('...').load(on_conflict='rename', rename=random_name)
Example
>>> from importloc import random_name
>>> Location('app/config.py').load()
<module 'config' from ...>
>>> Location('app/config.py').load(on_conflict='rename', rename=random_name)
<module 'u...'>
Combine override and rename
Location('...').load(modname='...', on_conflict='rename', rename=random_name)
Example
>>> from importloc import random_name
>>> Location('app/config.py').load(modname='app_config')
<module 'app_config' from ...>
>>> Location('app/config.py').load(
... modname='app_config', on_conflict='rename', rename=random_name
... )
<module 'u...' from ...>
What if object does not exist?
Missing object causes AttributeError
When module was imported but requested object does not exist, AttributeError
is raised.
Example
>>> Location('app/config.py:unknown').load()
Traceback (most recent call last):
...
AttributeError: object has no attribute 'unknown'
>>> # due to import atomicity, module 'config' was removed
>>> import sys
>>> 'config' in sys.modules
False
See also
Metadata
Release files for importloc 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| importloc-0.3.1.tar.gz | 92.8 kB | Without provenance | Details for importloc-0.3.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| importloc-0.3.1-py3-none-any.whl | Python 3 | none | any | Details for importloc-0.3.1-py3-none-any.whl |
Total release size: 104.7 kB
Release files / importloc-0.3.1.tar.gz
| Download URL | importloc-0.3.1.tar.gz |
|---|---|
| Size | 92.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2c4fb82bbeb41c176f2a0bb52cc36b1c94fa01fa0a5e6ca2567254cb12648a0d
|
|
BLAKE2b-256 checksum How to use checksums |
98b4435ce77fb255e5d341de926bf81ccd2b8defe3a0c604b4f8e82660c6eb8f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.5.13
|
Release files / importloc-0.3.1-py3-none-any.whl
| Download URL | importloc-0.3.1-py3-none-any.whl |
|---|---|
| Size | 11.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
84f5baaf7f02a488125e722a7e1d15cd5150dfd1287a77085e5aa0e55fdd4d03
|
|
BLAKE2b-256 checksum How to use checksums |
5e02867c521489bf0da6189cac33fd28349e697e353fcd52db0e8c75af19c9a7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.5.13
|
Security for importloc 0.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.