from importlib.util import module_from_spec, spec_from_file_location import logging from os import getcwd, walk from pathlib import Path from types import ModuleType from typing import List, Union logger = logging.getLogger(__name__) # Import functions # Took from https://stackoverflow.com/a/57892961 def get_py_files(src: Union[str, Path]) -> List[str]: cwd = getcwd() # Current Working directory py_files = [] for root, dirs, files in walk(src): py_files.extend( Path(f"{cwd}/{root}/{file}") for file in files if file.endswith(".py") ) return py_files def dynamic_import(module_name: str, py_path: str) -> Union[ModuleType, None]: try: module_spec = spec_from_file_location(module_name, py_path) if module_spec is None: raise RuntimeError( f"Module spec from module name {module_name} and path {py_path} is None" ) module = module_from_spec(module_spec) if module_spec.loader is None: logger.warning( "Could not load extension %s due to spec loader being None.", module_name, ) return module_spec.loader.exec_module(module) return module except SyntaxError: logger.warning( "Could not load extension %s due to invalid syntax. Check logs/errors.log for details.", module_name, ) return except Exception as exc: logger.warning("Could not load extension %s due to %s", module_name, exc) return def dynamic_import_from_src(src: Union[str, Path], star_import=False) -> None: my_py_files = get_py_files(src) for py_file in my_py_files: module_name = Path(py_file).stem logger.debug("Importing %s extension...", module_name) imported_module = dynamic_import(module_name, py_file) if imported_module != None: if star_import: for obj in dir(imported_module): globals()[obj] = imported_module.__dict__[obj] else: globals()[module_name] = imported_module logger.info("Successfully loaded %s extension", module_name) return