Source code for pygada_runtime.module

"""Package containing everything for accessing Python modules.

Gada takes advantage of how Python packages are installed in
the **PYTHONPATH** for dynamically discovering and loading
installed nodes.

So it heavily relies on **pkgutil** and **importlib** for
accessing and getting informations on installed packages.
"""
from __future__ import annotations

__all__ = [
    "module_name",
    "module_path",
    "gada_yml_path",
    "load_gada_yml",
    "iter_modules",
    "walk_modules",
]
import os
from types import ModuleType
from typing import TYPE_CHECKING, Iterable
import pkgutil
import importlib
import yaml

if TYPE_CHECKING:
    from typing import Optional, Callable, Union
    from pkgutil import ModuleInfo

    ModuleLike = Union[ModuleInfo, ModuleType, str]


[docs]def module_name(mod: ModuleLike, /) -> str: """Get the name of a module. :param mod: a module-like object """ if isinstance(mod, str): mod = importlib.import_module(mod) if isinstance(mod, ModuleType): return mod.__package__ # type: ignore return mod.name
[docs]def module_path(mod: ModuleLike, /) -> str: """Get the absolute path to a module. :param mod: a module-like object """ if isinstance(mod, str): mod = importlib.import_module(mod) if isinstance(mod, ModuleType): path = os.path.dirname(mod.__file__) else: mod_path = mod.module_finder.path # type: ignore path = os.path.join(mod_path, mod.name.split(".")[-1]) return os.path.abspath(path)
[docs]def gada_yml_path(mod: ModuleLike, /) -> str: """Get the absolute path to the **gada.yml** file of a module. :param mod: a module-like object """ return os.path.join(module_path(mod), "gada.yml")
[docs]def load_gada_yml(mod: ModuleLike, /) -> dict: """Load the **gada.yml** file of a module. :param mod: a module-like object """ with open(gada_yml_path(mod), "r", encoding="utf8") as f: return yaml.safe_load(f)
def _iter_modules( fun: Callable[[Optional[Iterable[str]], str], Iterable[ModuleInfo]], mod: Optional[ModuleLike] = None, ) -> Iterable[ModuleInfo]: """Yield modules containing a **gada.yml** file. :param mod: a module-like object """ path = [module_path(mod)] if mod is not None else None prefix = f"{module_name(mod)}." if mod is not None else "" for item in fun(path, prefix): if os.path.exists(gada_yml_path(item)): yield item
[docs]def iter_modules(mod: Optional[ModuleLike] = None) -> Iterable[ModuleInfo]: """Yield top-level modules containing a **gada.yml** file. This function only returns top-level modules installed in the **PYTHONPATH**. See :func:`walk_modules` for a fully recursive version. :param mod: a module-like object """ return _iter_modules(pkgutil.iter_modules, mod)
[docs]def walk_modules(mod: Optional[ModuleLike] = None) -> Iterable[ModuleInfo]: """Yield all modules containing a **gada.yml** file recursively. This function recursively analyze the modules installed in the **PYTHONPATH** to return not only the top-level modules, but also the submodules containing a **gada.yml** file. See :func:`iter_modules` for a non recursive version. :param mod: a module-like object """ return _iter_modules(pkgutil.walk_packages, mod)