'How do I dynamically import a python module containing imports to sibling packages?
I'm developing a command line tool in python which takes a source directory and build directory as parameters. The tool should walk through all directories in the source dir, find .py files and check for class members of a specific class instance.
For example:
$ my-cli-tool --source-dir app/ --build-dir docs/
With the following file structure:
MyProj
├── app
│   ├── foo
│   │   └── foo.py
│   └── bar
│       └── bar.py  
└── docs
    └─ ...
foo.py:
def foo_method():
    pass
class foo:
    my_member = MyClass()
bar.py:
from app.foo.foo import foo_method
class bar:
    my_member = MyClass()
Results in:
No module named 'app'
And if I use relative imports instead it results in:
attempted relative import beyond top-level package
Expected result:
As the program is intended to be a pip package, I would like to make it as pain free as possible for the users to integrate my package. I would like this cli tool to be able to work out of the box with their preferred style of imports.
My code so far:
import inspect
import os
import sys
from importlib import util
from argparse import ArgumentParser
def dir_path(string):
    if os.path.isdir(string):
        return os.path.abspath(string)
    else:
        raise NotADirectoryError(string)
def import_module(file_name, file_path):
    spec = util.spec_from_file_location(file_name, file_path)
    module = util.module_from_spec(spec)
    sys.modules[spec.name] = module
    spec.loader.exec_module(module)
    return module
def main(args):
    parser = ArgumentParser(prog='my-cli-tool')
    parser.add_argument('--source-dir', type=dir_path, action='store', default=os.getcwd())
    parser.add_argument('--build-dir', type=dir_path, action='store', default=os.getcwd())
    args = parser.parse_args(args)
    for root, dirs, filenames in os.walk(args.source_dir):
        for file_name in filenames:
            if file_name.endswith('.py'):
                file_path = os.path.join(root, file_name)
                module = import_module(file_name, file_path)
                classes = [obj[1] for obj in inspect.getmembers(module) if inspect.isclass(obj[1])]
                result = []
                for class_ in classes:
                    for i in inspect.getmembers(class_):
                        if isinstance(i[1], MyClass):
                            result.append(getattr(class_, i[0]))
                return result # Then make something with the results....
							
						Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|
