Source code for nbprint.config.hydra.loader

from logging import getLogger
from pathlib import Path
from typing import Any, List, cast

from ccflow import LazyRegistry
from lerna import compose, initialize_config_dir
from omegaconf import OmegaConf, open_dict
from typing_extensions import Self

__all__ = ("load_config",)

_logger = getLogger(__name__)


class _SharedLazyRegistry(LazyRegistry):
    def __deepcopy__(self, memo: dict[int, Any] | None = None) -> Self:
        if memo is not None:
            memo[id(self)] = self
        return self


[docs] def load_config( path: str | Path, overrides: List[str] | None = None, ) -> LazyRegistry: # convert to Path path = Path(path) if not isinstance(overrides, list): # maybe running via python, reset overrides = [] # prune any empty strings overrides = [o for o in overrides if o] # TODO: right now, nbprint runs off a specific config file, whereas # hydra takes a config dir and config name. For now we use the nbprint # style, so we adjust accordingly if path.suffix == ".yaml": config_dir = str(path.parent.absolute().resolve()) config_name = str(path.name) is_default = False else: # Use base config_dir = str((Path(__file__).parent).absolute().resolve()) config_name = "base.yaml" is_default = True with initialize_config_dir(config_dir=config_dir): if not is_default: cfg = compose(config_name=config_name, overrides=[], return_hydra_config=True) searchpaths = cfg["hydra"]["searchpath"] searchpaths.extend([config_dir]) overrides = [*overrides.copy(), f"hydra.searchpath=[{','.join(searchpaths)}]"] cfg = compose(config_name=config_name, overrides=overrides) if "nbprint" not in cfg: _logger.warning("No 'nbprint' config found in the provided configuration. Assuming entire config is for nbprint.") with open_dict(cfg): cfg.nbprint = cfg.copy() if "_target_" not in cfg.nbprint: with open_dict(cfg.nbprint): cfg.nbprint._target_ = "nbprint.Configuration" if "debug" not in cfg.nbprint: with open_dict(cfg.nbprint): cfg.nbprint.debug = False # bridge hydra and non-hydra if "name" not in cfg.nbprint: with open_dict(cfg.nbprint): cfg.nbprint.name = path.name.replace(".yaml", "").replace(".ipynb", "") # If its a notebook, parse it out and run directly # Read notebook contents and shove into config if path.suffix == ".ipynb": with open_dict(cfg): cfg.nbprint.notebook = path container = cast("dict[str, Any]", OmegaConf.to_container(cfg, resolve=True)) registry = _SharedLazyRegistry() # ccflow annotates cfg as DictConfig but loads plain containers too registry.load_config(cfg=container, overwrite=True) # ty: ignore[invalid-argument-type] if "callable" in container: callable_path = container["callable"] elif "callable" in container.get("nbprint", {}): callable_path = container["nbprint"]["callable"] else: callable_path = "nbprint" registry.add("callable", registry[callable_path.removeprefix("/")], overwrite=True) return registry