Source code for duck.utils.importer

"""
Module, object and variable importation module.
"""
import sys
import importlib

from functools import lru_cache


[docs] def import_module_once(module_name, package: str = None): """ Import a module only once. """ mod = sys.modules.get(module_name, None) if not mod: mod = importlib.import_module(module_name, package=package) sys.modules[module_name] = mod return mod
[docs] def _is_partial_module(mod) -> bool: """ Best-effort check for a partially initialized module. """ try: mod_spec = getattr(mod, "__spec__", None) if mod_spec is None: return False return getattr(mod_spec, "_initializing", False) except Exception: return False
[docs] @lru_cache def x_import(object_path, package: str = None): """ Function to import an object or class from a path e.g. `os.path.Path` """ if object_path.count(".") < 1: return import_module_once(object_path, package=package) module_path, obj_name = object_path.rsplit(".", 1) module = import_module_once(module_path, package=package) try: return getattr(module, obj_name) except AttributeError as e: # Avoid recursive reload loops while the module is still initializing. if not _is_partial_module(module): raise e # On reload, module can be partially initialized; retry after reload once. try: module = importlib.reload(module) return getattr(module, obj_name) except Exception: raise e