{"id":24665682,"url":"https://github.com/makukha/importloc","last_synced_at":"2026-02-18T09:01:53.372Z","repository":{"id":272651261,"uuid":"917008760","full_name":"makukha/importloc","owner":"makukha","description":"Import Python objects from arbitrary locations","archived":false,"fork":false,"pushed_at":"2025-02-16T08:05:41.000Z","size":371,"stargazers_count":2,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-27T18:23:10.725Z","etag":null,"topics":["import","import-module","python","python3"],"latest_commit_sha":null,"homepage":"http://importloc.readthedocs.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/makukha.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-01-15T07:15:18.000Z","updated_at":"2025-11-26T02:52:57.000Z","dependencies_parsed_at":"2025-01-15T21:38:58.808Z","dependency_job_id":"97b47b28-5e73-4814-9eb5-5396e9112a99","html_url":"https://github.com/makukha/importloc","commit_stats":null,"previous_names":["makukha/importloc"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/makukha/importloc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makukha%2Fimportloc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makukha%2Fimportloc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makukha%2Fimportloc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makukha%2Fimportloc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/makukha","download_url":"https://codeload.github.com/makukha/importloc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makukha%2Fimportloc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29574065,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T08:38:15.585Z","status":"ssl_error","status_checked_at":"2026-02-18T08:38:14.917Z","response_time":162,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["import","import-module","python","python3"],"created_at":"2025-01-26T07:13:11.309Z","updated_at":"2026-02-18T09:01:53.355Z","avatar_url":"https://github.com/makukha.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# importloc\n\u003c!-- docsub: begin --\u003e\n\u003c!-- docsub: include docs/desc.md --\u003e\n\u003e *Import Python objects from arbitrary locations specified by string.*\n\u003c!-- docsub: end --\u003e\n\n\u003c!-- docsub: begin --\u003e\n\u003c!-- docsub: include docs/badges.md --\u003e\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\u003c!-- docsub: end --\u003e\n\n\n\u003c!-- docsub: begin --\u003e\n\u003c!-- docsub: include docs/features.md --\u003e\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\u003c!-- docsub: end --\u003e\n\n\n# Installation\n\n```shell\n$ pip install importloc\n```\n\n\n# Usage\n\n\u003c!-- docsub: begin #readme --\u003e\n\u003c!-- docsub: include docs/usage.md --\u003e\n* Various locations\n    \u003c!-- docsub: begin --\u003e\n    \u003c!-- docsub: x toc tests/test_usage.py 'L[0-9]' --\u003e\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    \u003c!-- docsub: end --\u003e\n* Various targets\n    \u003c!-- docsub: begin --\u003e\n    \u003c!-- docsub: x toc tests/test_usage.py 'T[0-9]' --\u003e\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    \u003c!-- docsub: end --\u003e\n* Custom module name\n    \u003c!-- docsub: begin --\u003e\n    \u003c!-- docsub: x toc tests/test_usage.py 'N[0-9]' --\u003e\n    * [Use different module name](#use-different-module-name)\n    * [Generate module name at run time](#generate-module-name-at-run-time)\n    \u003c!-- docsub: end --\u003e\n* What if module is already imported?\n    \u003c!-- docsub: begin --\u003e\n    \u003c!-- docsub: x toc tests/test_usage.py 'R[0-9]' --\u003e\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    \u003c!-- docsub: end --\u003e\n* What if object does not exist?\n    \u003c!-- docsub: begin --\u003e\n    \u003c!-- docsub: x toc tests/test_usage.py 'O[0-9]' --\u003e\n    * [Missing object causes `AttributeError`](#missing-object-causes-attribute-error)\n    \u003c!-- docsub: end --\u003e\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\u003c!-- docsub: begin --\u003e\n\u003c!-- docsub: x cases tests/test_usage.py 'L[0-9]' --\u003e\n## Import from file\n\n```python\nLocation('app/config.py:conf').load()\n```\n\n```pycon\n\u003e\u003e\u003e loc = Location('app/config.py:conf')\n\u003e\u003e\u003e loc\n\u003cPathLocation 'app/config.py' obj='conf'\u003e\n\u003e\u003e\u003e loc.load()\n\u003cconfig.Config object at 0x...\u003e\n```\n\n## Import from module\n\n```python\nLocation('app.__main__:cli').load()\n```\n\n```pycon\n\u003e\u003e\u003e loc = Location('app.__main__:cli')\n\u003e\u003e\u003e loc\n\u003cModuleLocation 'app.__main__' obj='cli'\u003e\n\u003e\u003e\u003e loc.load()\n\u003cfunction cli at 0x...\u003e\n```\n\n## Distinguish file and module locations\n\n```python\nLocation('./config.py:conf').load()\n```\n\n```pycon\n\u003e\u003e\u003e loc = Location('config.py:conf')\n\u003e\u003e\u003e loc\n\u003cModuleLocation 'config.py' obj='conf'\u003e\n\u003e\u003e\u003e 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\u003e\u003e\u003e loc = Location('./config.py:conf')\n\u003e\u003e\u003e loc\n\u003cPathLocation 'config.py' obj='conf'\u003e\n\u003e\u003e\u003e loc.load()\n\u003cconfig.Config object at 0x...\u003e\n```\n\n\u003c!-- docsub: end --\u003e\n\n\n## Various targets\n\n\u003c!-- docsub: begin --\u003e\n\u003c!-- docsub: x cases tests/test_usage.py 'T[0-9]' --\u003e\n## Import nested class\n\n```python\nLocation('app/config.py:Config.Nested').load()\n```\n\n```pycon\n\u003e\u003e\u003e loc = Location('app/config.py:Config.Nested')\n\u003e\u003e\u003e loc\n\u003cPathLocation 'app/config.py' obj='Config.Nested'\u003e\n\u003e\u003e\u003e loc.load()\n\u003cclass 'config.Config.Nested'\u003e\n```\n\n## Import module as a whole\n\n```python\nLocation('app/config.py').load()\n```\n\n```pycon\n\u003e\u003e\u003e loc = Location('app/config.py')\n\u003e\u003e\u003e loc\n\u003cPathLocation 'app/config.py'\u003e\n\u003e\u003e\u003e loc.load()\n\u003cmodule 'config' from '...'\u003e\n```\n\n## Use `Path` object when loading module\n\n```python\nLocation(Path('config.py')).load()\n```\n\n```pycon\n\u003e\u003e\u003e from pathlib import Path\n\u003e\u003e\u003e loc = Location(Path('config.py'))\n\u003e\u003e\u003e loc\n\u003cPathLocation 'config.py'\u003e\n\u003e\u003e\u003e loc.load()\n\u003cmodule 'config' from '...'\u003e\n```\n\n## Import all instances of some type\n\n```python\nget_instances(Location('app.__main__').load(), Callable)\n```\n\n```pycon\n\u003e\u003e\u003e from collections.abc import Callable\n\u003e\u003e\u003e from importloc import get_instances\n\u003e\u003e\u003e loc = Location('app.__main__')\n\u003e\u003e\u003e loc\n\u003cModuleLocation 'app.__main__'\u003e\n\u003e\u003e\u003e get_instances(loc.load(), Callable)\n[\u003cfunction cli at 0x...\u003e]\n```\n\n## Import all subclasses\n\n```python\nget_subclasses(Location('app.errors').load(), Exception)\n```\n\n```pycon\n\u003e\u003e\u003e from importloc import get_subclasses\n\u003e\u003e\u003e loc = Location('app.errors')\n\u003e\u003e\u003e loc\n\u003cModuleLocation 'app.errors'\u003e\n\u003e\u003e\u003e get_subclasses(loc.load(), Exception)\n[\u003cclass 'app.errors.Error1'\u003e, \u003cclass 'app.errors.Error2'\u003e]\n```\n\n\u003c!-- docsub: end --\u003e\n\n\n## Custom module name\n\n\u003c!-- docsub: begin --\u003e\n\u003c!-- docsub: x cases tests/test_usage.py 'N[0-9]' --\u003e\n## Use different module name\n\n```python\nLocation('...').load(modname='app_main')\n```\n\n```pycon\n\u003e\u003e\u003e Location('app/config.py:Config').load(modname='app_main')\n\u003cclass 'app_main.Config'\u003e\n```\n\n## Generate module name at run time\n\n```python\nLocation('...').load(modname=random_name)\n```\n\n```pycon\n\u003e\u003e\u003e from importloc import random_name\n\u003e\u003e\u003e Location('app/config.py:Config').load(modname=random_name)\n\u003cclass 'u....Config'\u003e\n```\n\n\u003c!-- docsub: end --\u003e\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\u003c!-- docsub: begin --\u003e\n\u003c!-- docsub: x cases tests/test_usage.py 'R[0-9]' --\u003e\n## Module name conflict raises error by default\n\n```python\nLocation('...').load()\n```\n\n```pycon\n\u003e\u003e\u003e Location('app/config.py:Config').load()\n\u003cclass 'config.Config'\u003e\n\u003e\u003e\u003e 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```pycon\n\u003e\u003e\u003e C = Location('app/config.py:Config').load()\n\u003e\u003e\u003e C\n\u003cclass 'config.Config'\u003e\n\u003e\u003e\u003e old_id = id(C)\n\u003e\u003e\u003e C = Location('app/config.py:Config').load(on_conflict='reuse')\n\u003e\u003e\u003e C\n\u003cclass 'config.Config'\u003e\n\u003e\u003e\u003e # C is the same object:\n\u003e\u003e\u003e 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```pycon\n\u003e\u003e\u003e import sys\n\u003e\u003e\u003e C = Location('app/config.py:Config').load()\n\u003e\u003e\u003e C\n\u003cclass 'config.Config'\u003e\n\u003e\u003e\u003e old_id = id(C)\n\u003e\u003e\u003e mod_id = id(sys.modules['config'])\n\u003e\u003e\u003e C = Location('app/config.py:Config').load(on_conflict='reload')\n\u003e\u003e\u003e C\n\u003cclass 'config.Config'\u003e\n\u003e\u003e\u003e # module object remains the same after reloading:\n\u003e\u003e\u003e id(sys.modules['config']) == mod_id\nTrue\n\u003e\u003e\u003e # C is the new object from reloaded module:\n\u003e\u003e\u003e 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```pycon\n\u003e\u003e\u003e import sys\n\u003e\u003e\u003e C = Location('app/config.py:Config').load()\n\u003e\u003e\u003e C\n\u003cclass 'config.Config'\u003e\n\u003e\u003e\u003e mod_id = id(sys.modules['config'])\n\u003e\u003e\u003e C = Location('app/config.py:Config').load(on_conflict='replace')\n\u003e\u003e\u003e C\n\u003cclass 'config.Config'\u003e\n\u003e\u003e\u003e # module object is the new one:\n\u003e\u003e\u003e 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```pycon\n\u003e\u003e\u003e from importloc import random_name\n\u003e\u003e\u003e Location('app/config.py').load()\n\u003cmodule 'config' from ...\u003e\n\u003e\u003e\u003e Location('app/config.py').load(on_conflict='rename', rename=random_name)\n\u003cmodule 'u...'\u003e\n```\n\n## Combine override and rename\n\n```python\nLocation('...').load(modname='...', on_conflict='rename', rename=random_name)\n```\n\n```pycon\n\u003e\u003e\u003e from importloc import random_name\n\u003e\u003e\u003e Location('app/config.py').load(modname='app_config')\n\u003cmodule 'app_config' from ...\u003e\n\u003e\u003e\u003e Location('app/config.py').load(\n...     modname='app_config', on_conflict='rename', rename=random_name\n... )\n\u003cmodule 'u...' from ...\u003e\n```\n\n\u003c!-- docsub: end --\u003e\n\n\n## What if object does not exist?\n\n\u003c!-- docsub: begin --\u003e\n\u003c!-- docsub: x cases tests/test_usage.py 'O[0-9]' --\u003e\n## Missing object causes `AttributeError`\n\nWhen module was imported but requested object does not exist, `AttributeError`\nis raised.\n\n```pycon\n\u003e\u003e\u003e Location('app/config.py:unknown').load()\nTraceback (most recent call last):\n    ...\nAttributeError: object has no attribute 'unknown'\n\u003e\u003e\u003e # due to import atomicity, module 'config' was removed\n\u003e\u003e\u003e import sys\n\u003e\u003e\u003e 'config' in sys.modules\nFalse\n```\n\n\u003c!-- docsub: end --\u003e\n\n\u003c!-- docsub: end #readme --\u003e\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","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakukha%2Fimportloc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmakukha%2Fimportloc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakukha%2Fimportloc/lists"}