https://github.com/makukha/importloc
Import Python objects from arbitrary locations
https://github.com/makukha/importloc
import import-module python python3
Last synced: 4 months ago
JSON representation
Import Python objects from arbitrary locations
- Host: GitHub
- URL: https://github.com/makukha/importloc
- Owner: makukha
- License: mit
- Created: 2025-01-15T07:15:18.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-02-16T08:05:41.000Z (over 1 year ago)
- Last Synced: 2025-11-27T18:23:10.725Z (7 months ago)
- Topics: import, import-module, python, python3
- Language: Python
- Homepage: http://importloc.readthedocs.io
- Size: 362 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# importloc
> *Import Python objects from arbitrary locations specified by string.*
[](https://github.com/makukha/importloc/blob/main/LICENSE)
[](https://pypi.python.org/pypi/importloc)
[](https://pypi.org/project/importloc)
[](https://github.com/makukha/importloc)
[](https://github.com/makukha/importloc)
[](https://github.com/makukha/multipython)
[](https://github.com/makukha/docsub)
[](http://mypy.readthedocs.io)
[](https://github.com/astral-sh/ruff)
[](https://github.com/astral-sh/ruff)
# 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
```shell
$ pip install importloc
```
# Usage
* Various locations
* [Import from file](#import-from-file)
* [Import from module](#import-from-module)
* [Distinguish file and module locations](#distinguish-file-and-module-locations)
* Various targets
* [Import nested class](#import-nested-class)
* [Import module as a whole](#import-module-as-a-whole)
* [Use `Path` object when loading module](#use-path-object-when-loading-module)
* [Import all instances of some type](#import-all-instances-of-some-type)
* [Import all subclasses](#import-all-subclasses)
* Custom module name
* [Use different module name](#use-different-module-name)
* [Generate module name at run time](#generate-module-name-at-run-time)
* What if module is already imported?
* [Module name conflict raises error by default](#module-name-conflict-raises-error-by-default)
* [Reuse module that is already imported](#reuse-module-that-is-already-imported)
* [Reload module that is already imported](#reload-module-that-is-already-imported)
* [Replace old module with imported one](#replace-old-module-with-imported-one)
* [Load module under different generated name](#load-module-under-different-generated-name)
* [Combine override and rename](#combine-override-and-rename)
* What if object does not exist?
* [Missing object causes `AttributeError`](#missing-object-causes-attribute-error)
## Quick start
The main and most used entity is `Location`.
```python
from importloc import Location
```
## Various locations
## Import from file
```python
Location('app/config.py:conf').load()
```
```pycon
>>> loc = Location('app/config.py:conf')
>>> loc
>>> loc.load()
```
## Import from module
```python
Location('app.__main__:cli').load()
```
```pycon
>>> loc = Location('app.__main__:cli')
>>> loc
>>> loc.load()
```
## Distinguish file and module locations
```python
Location('./config.py:conf').load()
```
```pycon
>>> loc = Location('config.py:conf')
>>> loc
>>> 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`.
```pycon
>>> loc = Location('./config.py:conf')
>>> loc
>>> loc.load()
```
## Various targets
## Import nested class
```python
Location('app/config.py:Config.Nested').load()
```
```pycon
>>> loc = Location('app/config.py:Config.Nested')
>>> loc
>>> loc.load()
```
## Import module as a whole
```python
Location('app/config.py').load()
```
```pycon
>>> loc = Location('app/config.py')
>>> loc
>>> loc.load()
```
## Use `Path` object when loading module
```python
Location(Path('config.py')).load()
```
```pycon
>>> from pathlib import Path
>>> loc = Location(Path('config.py'))
>>> loc
>>> loc.load()
```
## Import all instances of some type
```python
get_instances(Location('app.__main__').load(), Callable)
```
```pycon
>>> from collections.abc import Callable
>>> from importloc import get_instances
>>> loc = Location('app.__main__')
>>> loc
>>> get_instances(loc.load(), Callable)
[]
```
## Import all subclasses
```python
get_subclasses(Location('app.errors').load(), Exception)
```
```pycon
>>> from importloc import get_subclasses
>>> loc = Location('app.errors')
>>> loc
>>> get_subclasses(loc.load(), Exception)
[, ]
```
## Custom module name
## Use different module name
```python
Location('...').load(modname='app_main')
```
```pycon
>>> Location('app/config.py:Config').load(modname='app_main')
```
## Generate module name at run time
```python
Location('...').load(modname=random_name)
```
```pycon
>>> from importloc import random_name
>>> Location('app/config.py:Config').load(modname=random_name)
```
## What if module is already imported?
The module name conflict can be resolved with one the methods:
* ``reuse`` existing module imported before
* ``reload`` existing module
* ``replace`` existing module
* ``rename`` new module (try to import under new name)
* ``raise`` exception (default)
For details, see documentation on [ConflictResolution](https://importloc.readthedocs.io/en/latest/api.html#ConflictResolution).
## Module name conflict raises error by default
```python
Location('...').load()
```
```pycon
>>> Location('app/config.py:Config').load()
>>> 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
```python
Location('...').load(on_conflict='reuse')
```
```pycon
>>> C = Location('app/config.py:Config').load()
>>> C
>>> old_id = id(C)
>>> C = Location('app/config.py:Config').load(on_conflict='reuse')
>>> C
>>> # C is the same object:
>>> id(C) == old_id
True
```
## Reload module that is already imported
```python
Location('...').load(on_conflict='reload')
```
```pycon
>>> import sys
>>> C = Location('app/config.py:Config').load()
>>> C
>>> old_id = id(C)
>>> mod_id = id(sys.modules['config'])
>>> C = Location('app/config.py:Config').load(on_conflict='reload')
>>> C
>>> # 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
```python
Location('...').load(on_conflict='replace')
```
```pycon
>>> import sys
>>> C = Location('app/config.py:Config').load()
>>> C
>>> mod_id = id(sys.modules['config'])
>>> C = Location('app/config.py:Config').load(on_conflict='replace')
>>> C
>>> # module object is the new one:
>>> id(sys.modules['config']) == mod_id
False
```
## Load module under different generated name
```python
Location('...').load(on_conflict='rename', rename=random_name)
```
```pycon
>>> from importloc import random_name
>>> Location('app/config.py').load()
>>> Location('app/config.py').load(on_conflict='rename', rename=random_name)
```
## Combine override and rename
```python
Location('...').load(modname='...', on_conflict='rename', rename=random_name)
```
```pycon
>>> from importloc import random_name
>>> Location('app/config.py').load(modname='app_config')
>>> Location('app/config.py').load(
... modname='app_config', on_conflict='rename', rename=random_name
... )
```
## What if object does not exist?
## Missing object causes `AttributeError`
When module was imported but requested object does not exist, `AttributeError`
is raised.
```pycon
>>> 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
* [Similar implementations](https://importloc.readthedocs.io/en/latest/alternatives.html)
* [Project changelog](https://github.com/makukha/importloc/tree/main/CHANGELOG.md)