Skip to content

lazy_import_utils

LazyImporter

Bases: ModuleType

Replace a module's global namespace with me to support lazy imports of submodules and members.

Source code in omnigibson/utils/lazy_import_utils.py
class LazyImporter(ModuleType):
    """Replace a module's global namespace with me to support lazy imports of submodules and members."""

    def __init__(self, module_name, module):
        super().__init__("lazy_" + module_name)
        self._module_path = module_name
        self._module = module
        self._not_module = set()
        self._submodules = {}

    def __getattr__(self, name: str):
        # First, try the argument as a module name.
        if name not in self._not_module:
            submodule = self._get_module(name)
            if submodule:
                return submodule
            else:
                # Record module not found so that we don't keep looking.
                self._not_module.add(name)

        # If it's not a module name, try it as a member of this module.
        try:
            return getattr(self._module, name)
        except:
            raise AttributeError(
                f"module {self.__name__} has no attribute {name}"
            ) from None

    def _get_module(self, module_name: str):
        """Recursively create and return a LazyImporter for the given module name."""

        # Get the fully qualified module name by prepending self._module_path
        if self._module_path:
            module_name = f"{self._module_path}.{module_name}"

        if module_name in self._submodules:
            return self._submodules[module_name]

        try:
            wrapper = LazyImporter(module_name, importlib.import_module(module_name))
            self._submodules[module_name] = wrapper
            return wrapper
        except ModuleNotFoundError:
            return None