importpy


Nameimportpy JSON
Version 0.1.1 PyPI version JSON
download
home_pagehttps://github.com/waveware4ai/importpy
SummaryDynamic, lazy-style module importer for Python.
upload_time2025-07-12 08:43:05
maintainerNone
docs_urlNone
author14mhz
requires_python>=3.8
licenseApache-2.0
keywords import package dynamic lazy module
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # importpy
Dynamic, lazy-style module importer for Python. It lets you import individual .py files directly at the module level, while still replicating standard package semantics (including automatic \_\_init\_\_.py execution) and resolving relative-import issues in nested directories—no changes to sys.path required. Use it to override Python’s built-in import mechanism only when you need that extra flexibility.
  
```
root package
    │
    ├─── __init__.py
    │
    ├─── packageA/
    │       │
    │       ├─── __init__.py
    │       ├─── moduleA1.py
    │       └─── moduleA2.py
    │       
    ├─── packageB/
    │       │
    │       ├───── packageC/
    │       │         │
    │       │         ├─── __init__.py
    │       │         ├─── moduleC1.py
    │       │         └─── moduleC2.py
    │       │
    │       ├─── __init__.py
    │       ├─── moduleB1.py
    │       └─── moduleB2.py
```
Now you can import regardless of path.  
For example, you can import moduleB1 of packageB from moduleA1 of packageA as follows.  
```
moduleA1.py of packageA
moduleB1 = importpy('../packageB/moduleB1.py')
```
likewise, can import moduleA2 of packageA from moduleC2 of packageC as follows.  
Of course, absolute paths are also possible.  
```
moduleC2.py of packageC
moduleA1 = importpy('../../packageA/moduleA2.py')
or
moduleA1 = importpy('c:/program files/python/project/test/package_root/packageA/moduleA2.py')
```
```
moduleC2.py of packageC
member1, member2, classC = importpy('../../packageA/moduleA2.py', 'member1', 'member2', 'classC')
```
I came up with this approach because I usually put unit tests in '\_\_main\_\_' of each module.  
Additionally, modules imported in this way can be executed independently regardless of the package structure. That's it....  

# History
2025/07/11 v0.1.0 : initial released  
2025/07/13 v0.1.1 : some minor bug fix, support pytest  

# Installation (pip install)
```python
python -m pip install importpy
or
python -m pip install git+https://github.com/waveware4ai/importpy
```
# Requirements
```python
Python 3.8+
No external dependencies
```
# Features
* Basic Features
    + importing modules using relative paths  
    + importing modules using absolute paths  
    + importing member functions from modules  
    + support lazy-import avoid circular importing  
    + support to import functions from module, like from x import y ...
* Import Logic  
    + caller location is traced via inspect  
    + relative path is resolved automatically  
    + module name is derived from the file path (e.g. utils/web.py → utils.web)  
    + result is cached in-memory  
# Testing
```
python -m pytest -v ./importpy/test

importpy\test\test_importpy.py::test_import_module PASSED                                   [  7%]
importpy\test\test_importpy.py::test_import_attr_single PASSED                              [ 15%]
importpy\test\test_importpy.py::test_import_attr_multiple PASSED                            [ 23%]
importpy\test\test_importpy.py::test_import_star_attribute PASSED                           [ 30%]
importpy\test\test_importpy.py::test_import_star_includes_expected_attributes PASSED        [ 38%]
importpy\test\test_importpy.py::test_import_attr_missing PASSED                             [ 46%]
importpy\test\test_importpy.py::test_import_args_invalid PASSED                             [ 53%]
importpy\test\test_importpy.py::test_import_absolute_path_loading PASSED                    [ 61%]
importpy\test\test_importpy.py::test_import_invalid_file_path PASSED                        [ 69%]
importpy\test\test_importpy.py::test_import_caching_behavior PASSED                         [ 76%]
importpy\test\test_importpy.py::test_import_lazy_loader_flag PASSED                         [ 84%]
importpy\test\test_importpy.py::test_import_occur_cyclic_importing PASSED                   [ 92%]
importpy\test\test_importpy.py::test_import_avoid_cyclic_importing PASSED                   [100%]
```
# Examples
```python
import importpy
# simple relative import
aaaa = importpy('aaaa.py') # same to below
aaaa = importpy('./aaaa.py')

# wildcard import
bbbb = importpy('../util/test/bbbb.py') # same to below
bbbb = importpy('../util/test/bbbb.py', '*') 

# absolute path
cccc = importpy('/home/user/project/cccc.py')
cccc = importpy('C:/program files/python/project/cccc.py') 

# turn on/off lazy-loading
lazy_on = importpy('lazy_on.py', use_lazy = True) # default action
lazyoff = importpy('lazyoff.py', use_lazy = False)

# import specific attributes
a_member_of_x, b_member_of_x = importpy('./pathto/x.py', 'a_member_of_x', 'b_member_of_x') 
module_x, a_member_of_x, b_member_of_x = importpy('./pathto/x.py', '*', 'a_member_of_x', 'b_member_of_x')  # wildcard include module x

# class import
ClassA, ClassB = importpy('./pathto/impl.py', 'ClassA', 'ClassB')
```
The following perform the same role:  
```python
import aaaa
aaaa = importpy('aaaa.py')
```
```python
from x import a_member_of_x, b_member_of_x
a_member_of_x, b_member_of_x = importpy('x.py', 'a_member_of_x', 'b_member_of_x') 
```
```python
from impl import ClassA, ClassB, funcX
ClassA, ClassB, funcX = importpy('impl.py', 'ClassA', 'ClassB', 'funcX')
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/waveware4ai/importpy",
    "name": "importpy",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "import, package, dynamic, lazy, module",
    "author": "14mhz",
    "author_email": "14mhz <14mhz@hanmail.net>",
    "download_url": "https://files.pythonhosted.org/packages/26/6a/4aad1abc4ac6d2d99a1ccf8b0355e00f97c7696f81c6f672ddcdfc23d29f/importpy-0.1.1.tar.gz",
    "platform": null,
    "description": "# importpy\r\nDynamic, lazy-style module importer for Python. It lets you import individual .py files directly at the module level, while still replicating standard package semantics (including automatic \\_\\_init\\_\\_.py execution) and resolving relative-import issues in nested directories\u2014no changes to sys.path required. Use it to override Python\u2019s built-in import mechanism only when you need that extra flexibility.\r\n  \r\n```\r\nroot package\r\n    \u2502\r\n    \u251c\u2500\u2500\u2500 __init__.py\r\n    \u2502\r\n    \u251c\u2500\u2500\u2500 packageA/\r\n    \u2502       \u2502\r\n    \u2502       \u251c\u2500\u2500\u2500 __init__.py\r\n    \u2502       \u251c\u2500\u2500\u2500 moduleA1.py\r\n    \u2502       \u2514\u2500\u2500\u2500 moduleA2.py\r\n    \u2502       \r\n    \u251c\u2500\u2500\u2500 packageB/\r\n    \u2502       \u2502\r\n    \u2502       \u251c\u2500\u2500\u2500\u2500\u2500 packageC/\r\n    \u2502       \u2502         \u2502\r\n    \u2502       \u2502         \u251c\u2500\u2500\u2500 __init__.py\r\n    \u2502       \u2502         \u251c\u2500\u2500\u2500 moduleC1.py\r\n    \u2502       \u2502         \u2514\u2500\u2500\u2500 moduleC2.py\r\n    \u2502       \u2502\r\n    \u2502       \u251c\u2500\u2500\u2500 __init__.py\r\n    \u2502       \u251c\u2500\u2500\u2500 moduleB1.py\r\n    \u2502       \u2514\u2500\u2500\u2500 moduleB2.py\r\n```\r\nNow you can import regardless of path.  \r\nFor example, you can import moduleB1 of packageB from moduleA1 of packageA as follows.  \r\n```\r\nmoduleA1.py of packageA\r\nmoduleB1 = importpy('../packageB/moduleB1.py')\r\n```\r\nlikewise, can import moduleA2 of packageA from moduleC2 of packageC as follows.  \r\nOf course, absolute paths are also possible.  \r\n```\r\nmoduleC2.py of packageC\r\nmoduleA1 = importpy('../../packageA/moduleA2.py')\r\nor\r\nmoduleA1 = importpy('c:/program files/python/project/test/package_root/packageA/moduleA2.py')\r\n```\r\n```\r\nmoduleC2.py of packageC\r\nmember1, member2, classC = importpy('../../packageA/moduleA2.py', 'member1', 'member2', 'classC')\r\n```\r\nI came up with this approach because I usually put unit tests in '\\_\\_main\\_\\_' of each module.  \r\nAdditionally, modules imported in this way can be executed independently regardless of the package structure. That's it....  \r\n\r\n# History\r\n2025/07/11 v0.1.0 : initial released  \r\n2025/07/13 v0.1.1 : some minor bug fix, support pytest  \r\n\r\n# Installation (pip install)\r\n```python\r\npython -m pip install importpy\r\nor\r\npython -m pip install git+https://github.com/waveware4ai/importpy\r\n```\r\n# Requirements\r\n```python\r\nPython 3.8+\r\nNo external dependencies\r\n```\r\n# Features\r\n* Basic Features\r\n    + importing modules using relative paths  \r\n    + importing modules using absolute paths  \r\n    + importing member functions from modules  \r\n    + support lazy-import avoid circular importing  \r\n    + support to import functions from module, like from x import y ...\r\n* Import Logic  \r\n    + caller location is traced via inspect  \r\n    + relative path is resolved automatically  \r\n    + module name is derived from the file path (e.g. utils/web.py \u2192 utils.web)  \r\n    + result is cached in-memory  \r\n# Testing\r\n```\r\npython -m pytest -v ./importpy/test\r\n\r\nimportpy\\test\\test_importpy.py::test_import_module PASSED                                   [  7%]\r\nimportpy\\test\\test_importpy.py::test_import_attr_single PASSED                              [ 15%]\r\nimportpy\\test\\test_importpy.py::test_import_attr_multiple PASSED                            [ 23%]\r\nimportpy\\test\\test_importpy.py::test_import_star_attribute PASSED                           [ 30%]\r\nimportpy\\test\\test_importpy.py::test_import_star_includes_expected_attributes PASSED        [ 38%]\r\nimportpy\\test\\test_importpy.py::test_import_attr_missing PASSED                             [ 46%]\r\nimportpy\\test\\test_importpy.py::test_import_args_invalid PASSED                             [ 53%]\r\nimportpy\\test\\test_importpy.py::test_import_absolute_path_loading PASSED                    [ 61%]\r\nimportpy\\test\\test_importpy.py::test_import_invalid_file_path PASSED                        [ 69%]\r\nimportpy\\test\\test_importpy.py::test_import_caching_behavior PASSED                         [ 76%]\r\nimportpy\\test\\test_importpy.py::test_import_lazy_loader_flag PASSED                         [ 84%]\r\nimportpy\\test\\test_importpy.py::test_import_occur_cyclic_importing PASSED                   [ 92%]\r\nimportpy\\test\\test_importpy.py::test_import_avoid_cyclic_importing PASSED                   [100%]\r\n```\r\n# Examples\r\n```python\r\nimport importpy\r\n# simple relative import\r\naaaa = importpy('aaaa.py') # same to below\r\naaaa = importpy('./aaaa.py')\r\n\r\n# wildcard import\r\nbbbb = importpy('../util/test/bbbb.py') # same to below\r\nbbbb = importpy('../util/test/bbbb.py', '*') \r\n\r\n# absolute path\r\ncccc = importpy('/home/user/project/cccc.py')\r\ncccc = importpy('C:/program files/python/project/cccc.py') \r\n\r\n# turn on/off lazy-loading\r\nlazy_on = importpy('lazy_on.py', use_lazy = True) # default action\r\nlazyoff = importpy('lazyoff.py', use_lazy = False)\r\n\r\n# import specific attributes\r\na_member_of_x, b_member_of_x = importpy('./pathto/x.py', 'a_member_of_x', 'b_member_of_x') \r\nmodule_x, a_member_of_x, b_member_of_x = importpy('./pathto/x.py', '*', 'a_member_of_x', 'b_member_of_x')  # wildcard include module x\r\n\r\n# class import\r\nClassA, ClassB = importpy('./pathto/impl.py', 'ClassA', 'ClassB')\r\n```\r\nThe following perform the same role:  \r\n```python\r\nimport aaaa\r\naaaa = importpy('aaaa.py')\r\n```\r\n```python\r\nfrom x import a_member_of_x, b_member_of_x\r\na_member_of_x, b_member_of_x = importpy('x.py', 'a_member_of_x', 'b_member_of_x') \r\n```\r\n```python\r\nfrom impl import ClassA, ClassB, funcX\r\nClassA, ClassB, funcX = importpy('impl.py', 'ClassA', 'ClassB', 'funcX')\r\n```\r\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "Dynamic, lazy-style module importer for Python. ",
    "version": "0.1.1",
    "project_urls": {
        "Home": "https://github.com/waveware4ai/importpy",
        "Homepage": "https://github.com/waveware4ai/importpy",
        "Source": "https://github.com/waveware4ai/importpy"
    },
    "split_keywords": [
        "import",
        " package",
        " dynamic",
        " lazy",
        " module"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "14f09656659f2dbcc29134f141e8c6c44285c9bd7b35bd8df8224262f5c5eb94",
                "md5": "5ab24cb710db598f3458cfed9f033455",
                "sha256": "5523d070d59b66ddf0ac4c31979e6d8163460df9b3d4065f54b00155691c6eda"
            },
            "downloads": -1,
            "filename": "importpy-0.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5ab24cb710db598f3458cfed9f033455",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 9927,
            "upload_time": "2025-07-12T08:43:04",
            "upload_time_iso_8601": "2025-07-12T08:43:04.442083Z",
            "url": "https://files.pythonhosted.org/packages/14/f0/9656659f2dbcc29134f141e8c6c44285c9bd7b35bd8df8224262f5c5eb94/importpy-0.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "266a4aad1abc4ac6d2d99a1ccf8b0355e00f97c7696f81c6f672ddcdfc23d29f",
                "md5": "180db4d22196813cac8f9d56e6b68701",
                "sha256": "b262408864d26c92cfe8aa74737001954a2e40c9227c97605278d31b5f160d93"
            },
            "downloads": -1,
            "filename": "importpy-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "180db4d22196813cac8f9d56e6b68701",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 9692,
            "upload_time": "2025-07-12T08:43:05",
            "upload_time_iso_8601": "2025-07-12T08:43:05.723704Z",
            "url": "https://files.pythonhosted.org/packages/26/6a/4aad1abc4ac6d2d99a1ccf8b0355e00f97c7696f81c6f672ddcdfc23d29f/importpy-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-12 08:43:05",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "waveware4ai",
    "github_project": "importpy",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "importpy"
}
        
Elapsed time: 0.44501s