importloc


Nameimportloc JSON
Version 0.3.1 PyPI version JSON
download
home_pageNone
SummaryImport Python objects from arbitrary locations specified by string
upload_time2025-02-06 19:19:44
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseMIT
keywords import import-module import-object import-string python
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # importloc
<!-- docsub: begin -->
<!-- docsub: include docs/desc.md -->
> *Import Python objects from arbitrary locations specified by string.*
<!-- docsub: end -->

<!-- docsub: begin -->
<!-- docsub: include docs/badges.md -->
[![license](https://img.shields.io/github/license/makukha/importloc.svg)](https://github.com/makukha/importloc/blob/main/LICENSE)
[![pypi](https://img.shields.io/pypi/v/importloc.svg#v0.3.1)](https://pypi.python.org/pypi/importloc)
[![python versions](https://img.shields.io/pypi/pyversions/importloc.svg)](https://pypi.org/project/importloc)
[![tests](https://raw.githubusercontent.com/makukha/importloc/v0.3.1/docs/_static/badge-tests.svg)](https://github.com/makukha/importloc)
[![coverage](https://raw.githubusercontent.com/makukha/importloc/v0.3.1/docs/_static/badge-coverage.svg)](https://github.com/makukha/importloc)
[![tested with multipython](https://img.shields.io/badge/tested_with-multipython-x)](https://github.com/makukha/multipython)
[![uses docsub](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/makukha/docsub/refs/heads/main/docs/badge/v1.json)](https://github.com/makukha/docsub)
[![mypy](https://img.shields.io/badge/type_checked-mypy-%231674b1)](http://mypy.readthedocs.io)
[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/ruff)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
<!-- docsub: end -->


<!-- docsub: begin -->
<!-- docsub: include docs/features.md -->
# 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
<!-- docsub: end -->


# Installation

```shell
$ pip install importloc
```


# Usage

<!-- docsub: begin #readme -->
<!-- docsub: include docs/usage.md -->
* Various locations
    <!-- docsub: begin -->
    <!-- docsub: x usage toc tests/test_usage.py 'L[0-9]' -->
    * [Import from file](#import-from-file)
    * [Import from module](#import-from-module)
    * [Distinguish file and module locations](#distinguish-file-and-module-locations)
    <!-- docsub: end -->
* Various targets
    <!-- docsub: begin -->
    <!-- docsub: x usage toc tests/test_usage.py 'T[0-9]' -->
    * [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)
    <!-- docsub: end -->
* Custom module name
    <!-- docsub: begin -->
    <!-- docsub: x usage toc tests/test_usage.py 'N[0-9]' -->
    * [Use different module name](#use-different-module-name)
    * [Generate module name at run time](#generate-module-name-at-run-time)
    <!-- docsub: end -->
* What if module is already imported?
    <!-- docsub: begin -->
    <!-- docsub: x usage toc tests/test_usage.py 'R[0-9]' -->
    * [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)
    <!-- docsub: end -->
* What if object does not exist?
    <!-- docsub: begin -->
    <!-- docsub: x usage toc tests/test_usage.py 'O[0-9]' -->
    * [Missing object causes `AttributeError`](#missing-object-causes-attribute-error)
    <!-- docsub: end -->


## Quick start

The main and most used entity is `Location`.

```python
from importloc import Location
```


## Various locations

<!-- docsub: begin -->
<!-- docsub: x usage section tests/test_usage.py 'L[0-9]' -->
### Import from file

```python
Location('app/config.py:conf').load()
```

_Example_
```pycon
>>> loc = Location('app/config.py:conf')
>>> loc
<PathLocation 'app/config.py' obj='conf'>
>>> loc.load()
<config.Config object at 0x...>
```

### Import from module

```python
Location('app.__main__:cli').load()
```

_Example_
```pycon
>>> loc = Location('app.__main__:cli')
>>> loc
<ModuleLocation 'app.__main__' obj='cli'>
>>> loc.load()
<function cli at 0x...>
```

### Distinguish file and module locations

```python
Location('./config.py:conf').load()
```

_Example_
```pycon
>>> 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`.

```pycon
>>> loc = Location('./config.py:conf')
>>> loc
<PathLocation 'config.py' obj='conf'>
>>> loc.load()
<config.Config object at 0x...>
```

<!-- docsub: end -->


## Various targets

<!-- docsub: begin -->
<!-- docsub: x usage section tests/test_usage.py 'T[0-9]' -->
### Import nested class

```python
Location('app/config.py:Config.Nested').load()
```

_Example_
```pycon
>>> 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

```python
Location('app/config.py').load()
```

_Example_
```pycon
>>> loc = Location('app/config.py')
>>> loc
<PathLocation 'app/config.py'>
>>> loc.load()
<module 'config' from '...'>
```

### Use `Path` object when loading module

```python
Location(Path('config.py')).load()
```

_Example_
```pycon
>>> from pathlib import Path
>>> loc = Location(Path('config.py'))
>>> loc
<PathLocation 'config.py'>
>>> loc.load()
<module 'config' from '...'>
```

### Import all instances of some type

```python
get_instances(Location('app.__main__').load(), Callable)
```

_Example_
```pycon
>>> 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

```python
get_subclasses(Location('app.errors').load(), Exception)
```

_Example_
```pycon
>>> 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'>]
```

<!-- docsub: end -->


## Custom module name

<!-- docsub: begin -->
<!-- docsub: x usage section tests/test_usage.py 'N[0-9]' -->
### Use different module name

```python
Location('...').load(modname='app_main')
```

_Example_
```pycon
>>> Location('app/config.py:Config').load(modname='app_main')
<class 'app_main.Config'>
```

### Generate module name at run time

```python
Location('...').load(modname=random_name)
```

_Example_
```pycon
>>> from importloc import random_name
>>> Location('app/config.py:Config').load(modname=random_name)
<class 'u....Config'>
```

<!-- docsub: end -->


## 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).

<!-- docsub: begin -->
<!-- docsub: x usage section tests/test_usage.py 'R[0-9]' -->
### Module name conflict raises error by default

```python
Location('...').load()
```

_Example_
```pycon
>>> 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

```python
Location('...').load(on_conflict='reuse')
```

_Example_
```pycon
>>> 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

```python
Location('...').load(on_conflict='reload')
```

_Example_
```pycon
>>> 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

```python
Location('...').load(on_conflict='replace')
```

_Example_
```pycon
>>> 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

```python
Location('...').load(on_conflict='rename', rename=random_name)
```

_Example_
```pycon
>>> 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

```python
Location('...').load(modname='...', on_conflict='rename', rename=random_name)
```

_Example_
```pycon
>>> 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 ...>
```

<!-- docsub: end -->


## What if object does not exist?

<!-- docsub: begin -->
<!-- docsub: x usage section tests/test_usage.py 'O[0-9]' -->
### Missing object causes `AttributeError`

When module was imported but requested object does not exist, `AttributeError`
is raised.

_Example_
```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
```

<!-- docsub: end -->

<!-- docsub: end #readme -->

# See also

* [Similar implementations](https://importloc.readthedocs.io/en/latest/alternatives.html)
* [Project changelog](https://github.com/makukha/importloc/tree/main/CHANGELOG.md)

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "importloc",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "import, import-module, import-object, import-string, python",
    "author": null,
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/98/b4/435ce77fb255e5d341de926bf81ccd2b8defe3a0c604b4f8e82660c6eb8f/importloc-0.3.1.tar.gz",
    "platform": null,
    "description": "# importloc\n<!-- docsub: begin -->\n<!-- docsub: include docs/desc.md -->\n> *Import Python objects from arbitrary locations specified by string.*\n<!-- docsub: end -->\n\n<!-- docsub: begin -->\n<!-- docsub: include docs/badges.md -->\n[![license](https://img.shields.io/github/license/makukha/importloc.svg)](https://github.com/makukha/importloc/blob/main/LICENSE)\n[![pypi](https://img.shields.io/pypi/v/importloc.svg#v0.3.1)](https://pypi.python.org/pypi/importloc)\n[![python versions](https://img.shields.io/pypi/pyversions/importloc.svg)](https://pypi.org/project/importloc)\n[![tests](https://raw.githubusercontent.com/makukha/importloc/v0.3.1/docs/_static/badge-tests.svg)](https://github.com/makukha/importloc)\n[![coverage](https://raw.githubusercontent.com/makukha/importloc/v0.3.1/docs/_static/badge-coverage.svg)](https://github.com/makukha/importloc)\n[![tested with multipython](https://img.shields.io/badge/tested_with-multipython-x)](https://github.com/makukha/multipython)\n[![uses docsub](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/makukha/docsub/refs/heads/main/docs/badge/v1.json)](https://github.com/makukha/docsub)\n[![mypy](https://img.shields.io/badge/type_checked-mypy-%231674b1)](http://mypy.readthedocs.io)\n[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/ruff)\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)\n<!-- docsub: end -->\n\n\n<!-- docsub: begin -->\n<!-- docsub: include docs/features.md -->\n# Features\n\n* Minimalistic fully typed package\n* Import from files or named modules\n* Import deeply nested objects\n* Import all instances or all subclasses\n* Configurable module name conflict resolution\n* Atomicity: on import error, new module is removed, and previous, if any, is restored\n<!-- docsub: end -->\n\n\n# Installation\n\n```shell\n$ pip install importloc\n```\n\n\n# Usage\n\n<!-- docsub: begin #readme -->\n<!-- docsub: include docs/usage.md -->\n* Various locations\n    <!-- docsub: begin -->\n    <!-- docsub: x usage toc tests/test_usage.py 'L[0-9]' -->\n    * [Import from file](#import-from-file)\n    * [Import from module](#import-from-module)\n    * [Distinguish file and module locations](#distinguish-file-and-module-locations)\n    <!-- docsub: end -->\n* Various targets\n    <!-- docsub: begin -->\n    <!-- docsub: x usage toc tests/test_usage.py 'T[0-9]' -->\n    * [Import nested class](#import-nested-class)\n    * [Import module as a whole](#import-module-as-a-whole)\n    * [Use `Path` object when loading module](#use-path-object-when-loading-module)\n    * [Import all instances of some type](#import-all-instances-of-some-type)\n    * [Import all subclasses](#import-all-subclasses)\n    <!-- docsub: end -->\n* Custom module name\n    <!-- docsub: begin -->\n    <!-- docsub: x usage toc tests/test_usage.py 'N[0-9]' -->\n    * [Use different module name](#use-different-module-name)\n    * [Generate module name at run time](#generate-module-name-at-run-time)\n    <!-- docsub: end -->\n* What if module is already imported?\n    <!-- docsub: begin -->\n    <!-- docsub: x usage toc tests/test_usage.py 'R[0-9]' -->\n    * [Module name conflict raises error by default](#module-name-conflict-raises-error-by-default)\n    * [Reuse module that is already imported](#reuse-module-that-is-already-imported)\n    * [Reload module that is already imported](#reload-module-that-is-already-imported)\n    * [Replace old module with imported one](#replace-old-module-with-imported-one)\n    * [Load module under different generated name](#load-module-under-different-generated-name)\n    * [Combine override and rename](#combine-override-and-rename)\n    <!-- docsub: end -->\n* What if object does not exist?\n    <!-- docsub: begin -->\n    <!-- docsub: x usage toc tests/test_usage.py 'O[0-9]' -->\n    * [Missing object causes `AttributeError`](#missing-object-causes-attribute-error)\n    <!-- docsub: end -->\n\n\n## Quick start\n\nThe main and most used entity is `Location`.\n\n```python\nfrom importloc import Location\n```\n\n\n## Various locations\n\n<!-- docsub: begin -->\n<!-- docsub: x usage section tests/test_usage.py 'L[0-9]' -->\n### Import from file\n\n```python\nLocation('app/config.py:conf').load()\n```\n\n_Example_\n```pycon\n>>> loc = Location('app/config.py:conf')\n>>> loc\n<PathLocation 'app/config.py' obj='conf'>\n>>> loc.load()\n<config.Config object at 0x...>\n```\n\n### Import from module\n\n```python\nLocation('app.__main__:cli').load()\n```\n\n_Example_\n```pycon\n>>> loc = Location('app.__main__:cli')\n>>> loc\n<ModuleLocation 'app.__main__' obj='cli'>\n>>> loc.load()\n<function cli at 0x...>\n```\n\n### Distinguish file and module locations\n\n```python\nLocation('./config.py:conf').load()\n```\n\n_Example_\n```pycon\n>>> loc = Location('config.py:conf')\n>>> loc\n<ModuleLocation 'config.py' obj='conf'>\n>>> loc.load()\nTraceback (most recent call last):\n    ...\nModuleNotFoundError: No module named 'config.py'...\n```\n\nUse relative path (similar to Docker bind mount). Path separator will result in\n`PathLocation` instead of `ModuleLocation`.\n\n```pycon\n>>> loc = Location('./config.py:conf')\n>>> loc\n<PathLocation 'config.py' obj='conf'>\n>>> loc.load()\n<config.Config object at 0x...>\n```\n\n<!-- docsub: end -->\n\n\n## Various targets\n\n<!-- docsub: begin -->\n<!-- docsub: x usage section tests/test_usage.py 'T[0-9]' -->\n### Import nested class\n\n```python\nLocation('app/config.py:Config.Nested').load()\n```\n\n_Example_\n```pycon\n>>> loc = Location('app/config.py:Config.Nested')\n>>> loc\n<PathLocation 'app/config.py' obj='Config.Nested'>\n>>> loc.load()\n<class 'config.Config.Nested'>\n```\n\n### Import module as a whole\n\n```python\nLocation('app/config.py').load()\n```\n\n_Example_\n```pycon\n>>> loc = Location('app/config.py')\n>>> loc\n<PathLocation 'app/config.py'>\n>>> loc.load()\n<module 'config' from '...'>\n```\n\n### Use `Path` object when loading module\n\n```python\nLocation(Path('config.py')).load()\n```\n\n_Example_\n```pycon\n>>> from pathlib import Path\n>>> loc = Location(Path('config.py'))\n>>> loc\n<PathLocation 'config.py'>\n>>> loc.load()\n<module 'config' from '...'>\n```\n\n### Import all instances of some type\n\n```python\nget_instances(Location('app.__main__').load(), Callable)\n```\n\n_Example_\n```pycon\n>>> from collections.abc import Callable\n>>> from importloc import get_instances\n>>> loc = Location('app.__main__')\n>>> loc\n<ModuleLocation 'app.__main__'>\n>>> get_instances(loc.load(), Callable)\n[<function cli at 0x...>]\n```\n\n### Import all subclasses\n\n```python\nget_subclasses(Location('app.errors').load(), Exception)\n```\n\n_Example_\n```pycon\n>>> from importloc import get_subclasses\n>>> loc = Location('app.errors')\n>>> loc\n<ModuleLocation 'app.errors'>\n>>> get_subclasses(loc.load(), Exception)\n[<class 'app.errors.Error1'>, <class 'app.errors.Error2'>]\n```\n\n<!-- docsub: end -->\n\n\n## Custom module name\n\n<!-- docsub: begin -->\n<!-- docsub: x usage section tests/test_usage.py 'N[0-9]' -->\n### Use different module name\n\n```python\nLocation('...').load(modname='app_main')\n```\n\n_Example_\n```pycon\n>>> Location('app/config.py:Config').load(modname='app_main')\n<class 'app_main.Config'>\n```\n\n### Generate module name at run time\n\n```python\nLocation('...').load(modname=random_name)\n```\n\n_Example_\n```pycon\n>>> from importloc import random_name\n>>> Location('app/config.py:Config').load(modname=random_name)\n<class 'u....Config'>\n```\n\n<!-- docsub: end -->\n\n\n## What if module is already imported?\n\nThe module name conflict can be resolved with one the methods:\n\n* ``reuse`` existing module imported before\n* ``reload`` existing module\n* ``replace`` existing module\n* ``rename`` new module (try to import under new name)\n* ``raise`` exception (default)\n\nFor details, see documentation on [ConflictResolution](https://importloc.readthedocs.io/en/latest/api.html#ConflictResolution).\n\n<!-- docsub: begin -->\n<!-- docsub: x usage section tests/test_usage.py 'R[0-9]' -->\n### Module name conflict raises error by default\n\n```python\nLocation('...').load()\n```\n\n_Example_\n```pycon\n>>> Location('app/config.py:Config').load()\n<class 'config.Config'>\n>>> Location('app/config.py:Config').load()\nTraceback (most recent call last):\n    ...\nimportloc.exc.ModuleNameConflict: Module \"config\" is already imported\n```\n\n### Reuse module that is already imported\n\n```python\nLocation('...').load(on_conflict='reuse')\n```\n\n_Example_\n```pycon\n>>> C = Location('app/config.py:Config').load()\n>>> C\n<class 'config.Config'>\n>>> old_id = id(C)\n>>> C = Location('app/config.py:Config').load(on_conflict='reuse')\n>>> C\n<class 'config.Config'>\n>>> # C is the same object:\n>>> id(C) == old_id\nTrue\n```\n\n### Reload module that is already imported\n\n```python\nLocation('...').load(on_conflict='reload')\n```\n\n_Example_\n```pycon\n>>> import sys\n>>> C = Location('app/config.py:Config').load()\n>>> C\n<class 'config.Config'>\n>>> old_id = id(C)\n>>> mod_id = id(sys.modules['config'])\n>>> C = Location('app/config.py:Config').load(on_conflict='reload')\n>>> C\n<class 'config.Config'>\n>>> # module object remains the same after reloading:\n>>> id(sys.modules['config']) == mod_id\nTrue\n>>> # C is the new object from reloaded module:\n>>> id(C) == old_id\nFalse\n```\n\n### Replace old module with imported one\n\n```python\nLocation('...').load(on_conflict='replace')\n```\n\n_Example_\n```pycon\n>>> import sys\n>>> C = Location('app/config.py:Config').load()\n>>> C\n<class 'config.Config'>\n>>> mod_id = id(sys.modules['config'])\n>>> C = Location('app/config.py:Config').load(on_conflict='replace')\n>>> C\n<class 'config.Config'>\n>>> # module object is the new one:\n>>> id(sys.modules['config']) == mod_id\nFalse\n```\n\n### Load module under different generated name\n\n```python\nLocation('...').load(on_conflict='rename', rename=random_name)\n```\n\n_Example_\n```pycon\n>>> from importloc import random_name\n>>> Location('app/config.py').load()\n<module 'config' from ...>\n>>> Location('app/config.py').load(on_conflict='rename', rename=random_name)\n<module 'u...'>\n```\n\n### Combine override and rename\n\n```python\nLocation('...').load(modname='...', on_conflict='rename', rename=random_name)\n```\n\n_Example_\n```pycon\n>>> from importloc import random_name\n>>> Location('app/config.py').load(modname='app_config')\n<module 'app_config' from ...>\n>>> Location('app/config.py').load(\n...     modname='app_config', on_conflict='rename', rename=random_name\n... )\n<module 'u...' from ...>\n```\n\n<!-- docsub: end -->\n\n\n## What if object does not exist?\n\n<!-- docsub: begin -->\n<!-- docsub: x usage section tests/test_usage.py 'O[0-9]' -->\n### Missing object causes `AttributeError`\n\nWhen module was imported but requested object does not exist, `AttributeError`\nis raised.\n\n_Example_\n```pycon\n>>> Location('app/config.py:unknown').load()\nTraceback (most recent call last):\n    ...\nAttributeError: object has no attribute 'unknown'\n>>> # due to import atomicity, module 'config' was removed\n>>> import sys\n>>> 'config' in sys.modules\nFalse\n```\n\n<!-- docsub: end -->\n\n<!-- docsub: end #readme -->\n\n# See also\n\n* [Similar implementations](https://importloc.readthedocs.io/en/latest/alternatives.html)\n* [Project changelog](https://github.com/makukha/importloc/tree/main/CHANGELOG.md)\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Import Python objects from arbitrary locations specified by string",
    "version": "0.3.1",
    "project_urls": {
        "Changelog": "https://github.com/makukha/importloc/releases",
        "Documentation": "https://importloc.readthedocs.io",
        "Homepage": "https://github.com/makukha/importloc",
        "Issues": "https://github.com/makukha/importloc/issues",
        "Repository": "https://github.com/makukha/importloc"
    },
    "split_keywords": [
        "import",
        " import-module",
        " import-object",
        " import-string",
        " python"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5e02867c521489bf0da6189cac33fd28349e697e353fcd52db0e8c75af19c9a7",
                "md5": "ed43e3051681fcf3e9c802b02ae9a01e",
                "sha256": "84f5baaf7f02a488125e722a7e1d15cd5150dfd1287a77085e5aa0e55fdd4d03"
            },
            "downloads": -1,
            "filename": "importloc-0.3.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "ed43e3051681fcf3e9c802b02ae9a01e",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 11858,
            "upload_time": "2025-02-06T19:19:43",
            "upload_time_iso_8601": "2025-02-06T19:19:43.009861Z",
            "url": "https://files.pythonhosted.org/packages/5e/02/867c521489bf0da6189cac33fd28349e697e353fcd52db0e8c75af19c9a7/importloc-0.3.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "98b4435ce77fb255e5d341de926bf81ccd2b8defe3a0c604b4f8e82660c6eb8f",
                "md5": "0449e32dc425668dbe57047f3f2f97d0",
                "sha256": "2c4fb82bbeb41c176f2a0bb52cc36b1c94fa01fa0a5e6ca2567254cb12648a0d"
            },
            "downloads": -1,
            "filename": "importloc-0.3.1.tar.gz",
            "has_sig": false,
            "md5_digest": "0449e32dc425668dbe57047f3f2f97d0",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 92831,
            "upload_time": "2025-02-06T19:19:44",
            "upload_time_iso_8601": "2025-02-06T19:19:44.350595Z",
            "url": "https://files.pythonhosted.org/packages/98/b4/435ce77fb255e5d341de926bf81ccd2b8defe3a0c604b4f8e82660c6eb8f/importloc-0.3.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-02-06 19:19:44",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "makukha",
    "github_project": "importloc",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "tox": true,
    "lcname": "importloc"
}
        
Elapsed time: 0.45547s