Skip to content

Configuration Extension API

Extension point. These modules define canonical configuration lifecycle. Use them when adding config fields or routing behavior; do not make them a dependency of an external application without accepting internal change risk.

Module map

Module Non-private entry points Responsibility
core.config.editable Config, option TypedDicts Pre-allocation composition, inspection, validated updates, and remote overrides.
core.config.loader load_raw_config, load_config, load_config_omega, resolve_config, save_config YAML/JSON loading, canonical layering, runtime backend normalization, and config persistence.
core.config.migrate / validate migrate_config, validate_config Legacy ingestion and canonical schema/topology checks.
core.config.accessors get_*, set_* helpers Runtime-safe access to system, split, data, component, train, and VQA settings.
core.config.runtime_adapter namespace conversion/adaptation helpers Convert canonical mappings to runtime attribute access.

save_config() writes a config file. Config.from_pretrained() and any Hugging Face config source use network/authentication. All other loaders read from the local config path supplied by the caller.

Canonical config loading.

load_raw_config(path)

Source code in opensportslib/core/config/loader.py
def load_raw_config(path: str | Path) -> dict[str, Any]:
    config_path = Path(path)
    suffix = config_path.suffix.lower()
    if suffix in _YAML_SUFFIXES:
        return _load_composed_yaml(config_path)
    if suffix == ".json":
        with open(config_path, "r", encoding="utf-8") as handle:
            return json.load(handle)
    raise ValueError("Unsupported config format. Use YAML or JSON.")

load_config(config_path, *, validate=True, as_namespace=True)

Source code in opensportslib/core/config/loader.py
def load_config(
    config_path: str | Path,
    *,
    validate: bool = True,
    as_namespace: bool = True,
) -> Any:
    raw = load_raw_config(config_path)
    canonical = migrate_config(raw, as_namespace=False)
    canonical = _normalize_cpu_loader_backend(canonical)
    assert_no_legacy_aliases(canonical)

    if validate:
        from .validate import validate_config

        validate_config(canonical)
    return maybe_namespace(canonical, as_namespace=as_namespace)

load_config_omega(path, *, validate=True, as_namespace=True)

Source code in opensportslib/core/config/loader.py
def load_config_omega(
    path: str | Path,
    *,
    validate: bool = True,
    as_namespace: bool = True,
) -> Any:
    return load_config(
        path,
        validate=validate,
        as_namespace=as_namespace,
    )

resolve_config(config, *, as_namespace=True)

Source code in opensportslib/core/config/loader.py
def resolve_config(
    config: Any,
    *,
    as_namespace: bool = True,
) -> Any:
    payload = namespace_to_plain_dict(config)
    canonical = migrate_config(payload, as_namespace=False)
    canonical = _normalize_cpu_loader_backend(canonical)
    assert_no_legacy_aliases(canonical)
    return maybe_namespace(canonical, as_namespace=as_namespace)

save_config(config_obj, path)

Source code in opensportslib/core/config/loader.py
def save_config(config_obj: Any, path: str | Path) -> None:
    payload = namespace_to_plain_dict(config_obj)
    with open(path, "w", encoding="utf-8") as handle:
        if yaml is not None:
            yaml.safe_dump(payload, handle, sort_keys=False)
            return

        from omegaconf import OmegaConf

        handle.write(OmegaConf.to_yaml(OmegaConf.create(payload), resolve=False))

Version-neutral migration entrypoints.

migrate_config(config, *, as_namespace=False)

Source code in opensportslib/core/config/migrate.py
def migrate_config(config: Any, *, as_namespace: bool = False) -> Any:
    payload = namespace_to_plain_dict(config)
    if is_canonical_schema(payload):
        migrated = payload
    elif is_legacy_schema(payload):
        migrated = migrate_legacy_to_canonical(payload)
    else:
        raise ValueError("Unsupported config schema. Only legacy input and canonical schema are supported.")
    return maybe_namespace(migrated, as_namespace=as_namespace)

Canonical config validation.

validate_config(config_or_path)

Source code in opensportslib/core/config/validate.py
def validate_config(config_or_path: str | dict[str, Any]) -> dict[str, Any]:
    if isinstance(config_or_path, str):
        raw = load_raw_config(config_or_path)
    else:
        raw = config_or_path

    canonical = migrate_config(raw, as_namespace=False)
    _validate_canonical(canonical)
    return canonical

Accessor families

Accessors are intentionally grouped instead of duplicating every leaf setting: get_system_* / set_system_*, get_split_* / set_split_*, get_data_*, get_component_*, get_train_*, and get_vqa_*. Add a new accessor only when a setting is shared across task modules; task-only config consumption belongs in that task’s implementation.

Canonical config access helpers for runtime code.

get_loader_backend(cfg)

Source code in opensportslib/core/config/accessors.py
def get_loader_backend(cfg: Any) -> str:
    data = _as_dict(getattr(cfg, "DATA", None))
    common = _as_dict(data.get("common"))
    runtime = _as_dict(common.get("runtime"))
    backend = runtime.get("loader_backend", "opencv")
    return str(backend).lower()

set_loader_backend(cfg, backend)

Source code in opensportslib/core/config/accessors.py
def set_loader_backend(cfg: Any, backend: str) -> None:
    data = getattr(cfg, "DATA", None)
    if data is None:
        data = SimpleNamespace()
        setattr(cfg, "DATA", data)

    common = _ensure_child(data, "common")
    runtime = _ensure_child(common, "runtime")
    if isinstance(runtime, dict):
        runtime["loader_backend"] = str(backend).lower()
    else:
        setattr(runtime, "loader_backend", str(backend).lower())

get_split_cfg(cfg, split)

Source code in opensportslib/core/config/accessors.py
def get_split_cfg(cfg: Any, split: str) -> SimpleNamespace:
    data = _as_dict(getattr(cfg, "DATA", None))
    common = _as_dict(data.get("common"))
    splits = _as_dict(common.get("splits"))
    split_cfg = _as_dict(splits.get(split))

    if not split_cfg and split in data and isinstance(data[split], dict):
        split_cfg = _as_dict(data[split])

    return SimpleNamespace(**split_cfg)

get_split_dataloader_cfg(cfg, split)

Source code in opensportslib/core/config/accessors.py
def get_split_dataloader_cfg(cfg: Any, split: str) -> SimpleNamespace:
    split_cfg = get_split_cfg(cfg, split)
    dataloader = getattr(split_cfg, "dataloader", None)
    if dataloader is None:
        return SimpleNamespace()
    if isinstance(dataloader, dict):
        return SimpleNamespace(**dataloader)
    return dataloader

get_split_annotation_path(cfg, split)

Source code in opensportslib/core/config/accessors.py
def get_split_annotation_path(cfg: Any, split: str) -> str | None:
    split_cfg = get_split_cfg(cfg, split)
    return getattr(split_cfg, "annotation_path", None)

set_split_annotation_path(cfg, split, path)

Source code in opensportslib/core/config/accessors.py
def set_split_annotation_path(cfg: Any, split: str, path: str) -> None:
    data = getattr(cfg, "DATA", None)
    if data is None:
        data = SimpleNamespace()
        setattr(cfg, "DATA", data)

    common = _ensure_child(data, "common")
    splits = _ensure_child(common, "splits")
    split_cfg = _ensure_child(splits, split)

    if isinstance(split_cfg, dict):
        split_cfg["annotation_path"] = path
    else:
        setattr(split_cfg, "annotation_path", path)

get_data_classes(cfg)

Source code in opensportslib/core/config/accessors.py
def get_data_classes(cfg: Any) -> list[str]:
    data = _as_dict(getattr(cfg, "DATA", None))
    common = _as_dict(data.get("common"))
    return classes_to_ordered_list(common.get("classes", []))

get_data_modality(cfg)

Source code in opensportslib/core/config/accessors.py
def get_data_modality(cfg: Any) -> str:
    input_cfg = get_input_cfg(cfg)
    modality = input_cfg.get("modality") or input_cfg.get("representation") or "video"
    return str(modality)

get_component_by_kind(cfg, kind)

Source code in opensportslib/core/config/accessors.py
def get_component_by_kind(cfg: Any, kind: str) -> dict[str, Any] | None:
    model = _as_dict(getattr(cfg, "MODEL", None))
    components = _as_dict(model.get("components"))
    for component in components.values():
        comp = _as_dict(component)
        if comp.get("kind") == kind:
            return comp
    return None

get_component_name_by_kind(cfg, kind)

Source code in opensportslib/core/config/accessors.py
def get_component_name_by_kind(cfg: Any, kind: str) -> str | None:
    comp = get_component_by_kind(cfg, kind)
    if not comp:
        return None
    source = _as_dict(comp.get("source"))
    return source.get("name")

get_component_params_by_kind(cfg, kind)

Source code in opensportslib/core/config/accessors.py
def get_component_params_by_kind(cfg: Any, kind: str) -> dict[str, Any]:
    comp = get_component_by_kind(cfg, kind)
    if not comp:
        return {}
    params = _as_dict(comp.get("params"))
    overrides = _as_dict(comp.get("overrides"))
    out = dict(params)
    out.update(overrides)
    name = _as_dict(comp.get("source")).get("name")
    if name is not None and "type" not in out:
        out["type"] = name
    return out

get_model_family(cfg)

Source code in opensportslib/core/config/accessors.py
def get_model_family(cfg: Any) -> str:
    model = _as_dict(getattr(cfg, "MODEL", None))
    metadata = _as_dict(model.get("metadata"))
    family = metadata.get("legacy_type") or metadata.get("family")
    if family:
        return str(family)

    task = str(getattr(cfg, "TASK", "")).lower()
    trainer_type = get_train_trainer_type(cfg).lower()
    if task == "localization":
        if trainer_type == "trainer_e2e":
            return "E2E"
        if trainer_type == "trainer_calf":
            return "ContextAware"
        if trainer_type == "trainer_pooling":
            return "LearnablePooling"

    return "custom"

get_runner_type(cfg)

Source code in opensportslib/core/config/accessors.py
def get_runner_type(cfg: Any) -> str:
    model = _as_dict(getattr(cfg, "MODEL", None))
    metadata = _as_dict(model.get("metadata"))
    runner = _as_dict(metadata.get("runner"))
    runner_type = runner.get("type")
    if runner_type:
        return str(runner_type)

    trainer_type = get_train_trainer_type(cfg).lower()
    if trainer_type == "trainer_e2e":
        return "runner_e2e"
    if trainer_type == "trainer_calf":
        return "runner_CALF"
    if trainer_type == "trainer_pooling":
        return "runner_pooling"
    if trainer_type == "vqa":
        return "runner_vqa"
    return "runner_classification"