Skip to content

climate_ref.cli._config_access #

Helpers for reading and updating dotted configuration keys.

ConfigKeyError #

Bases: KeyError

Raised when a dotted configuration key cannot be resolved.

Source code in packages/climate-ref/src/climate_ref/cli/_config_access.py
class ConfigKeyError(KeyError):
    """Raised when a dotted configuration key cannot be resolved."""

    def __init__(self, key: str, segment: str) -> None:
        super().__init__(key)
        self.key = key
        self.segment = segment

available_keys(config, prefix='') #

Return all dotted scalar configuration keys.

Source code in packages/climate-ref/src/climate_ref/cli/_config_access.py
def available_keys(config: object, prefix: str = "") -> list[str]:
    """Return all dotted scalar configuration keys."""
    keys: list[str] = []
    for field in _field_map(config).values():
        value = getattr(config, field.name)
        dotted = f"{prefix}.{field.name}" if prefix else field.name
        if is_structured(value, field):
            if attrs.has(value.__class__) and not isinstance(value, Path):
                keys.extend(available_keys(value, dotted))
        else:
            keys.append(dotted)
    return keys

coerce_value(field, raw) #

Coerce a CLI string to the type required by an attrs field.

Source code in packages/climate-ref/src/climate_ref/cli/_config_access.py
def coerce_value(field: Attribute[Any], raw: str) -> Any:
    """Coerce a CLI string to the type required by an attrs field."""
    if _is_bool_type(field.type):
        value: Any = _parse_bool(raw)
    elif field.type is Path:
        value = Path(raw)
    else:
        value = raw

    if field.converter is not None:
        return cast(Callable[[Any], Any], field.converter)(value)

    if field.type is None:
        return value
    return _converter_defaults_relaxed.structure(value, field.type)

default_value(parent, field) #

Return the attrs default for a field without reading the current value.

Source code in packages/climate-ref/src/climate_ref/cli/_config_access.py
def default_value(parent: object, field: Attribute[Any]) -> Any:
    """Return the attrs default for a field without reading the current value."""
    default = field.default
    if default is NOTHING:
        raise ValueError(f"Configuration key {field.name!r} has no default")

    if hasattr(default, "factory") and hasattr(default, "takes_self"):
        default_factory = cast(Any, default)
        if default_factory.takes_self:
            value = default_factory.factory(parent)
        else:
            value = default_factory.factory()
    else:
        value = default

    if field.converter is not None:
        return cast(Callable[[Any], Any], field.converter)(value)
    return value

env_var_for(parent, field) #

Return the environment variable that overrides a field, if any.

Source code in packages/climate-ref/src/climate_ref/cli/_config_access.py
def env_var_for(parent: object, field: Attribute[Any]) -> str | None:
    """Return the environment variable that overrides a field, if any."""
    env_name = field.metadata.get("env")
    if not env_name:
        return None
    prefix = getattr(parent, "_prefix", None)
    if not prefix:
        return None
    return f"{prefix}_{env_name}"

is_structured(value, field) #

Return whether a field is too structured for scalar CLI set/unset.

Source code in packages/climate-ref/src/climate_ref/cli/_config_access.py
def is_structured(value: Any, field: Attribute[Any]) -> bool:
    """Return whether a field is too structured for scalar CLI set/unset."""
    if isinstance(value, dict | list | tuple | set):
        return True
    if attrs.has(value.__class__) and not isinstance(value, Path):
        return True

    origin = get_origin(field.type)
    if origin in {dict, list, tuple, set}:
        return True
    return isinstance(value, Sequence) and not isinstance(value, str | bytes | bytearray)

resolve_key(config, dotted) #

Resolve a dotted key to its parent object, attrs field and current value.

Source code in packages/climate-ref/src/climate_ref/cli/_config_access.py
def resolve_key(config: object, dotted: str) -> tuple[object, Attribute[Any], Any]:
    """Resolve a dotted key to its parent object, attrs field and current value."""
    if not dotted:
        raise ConfigKeyError(dotted, dotted)

    current = config
    parts = dotted.split(".")
    for index, part in enumerate(parts):
        fields = _field_map(current)
        field = fields.get(part)
        if field is None:
            raise ConfigKeyError(dotted, part)

        value = getattr(current, field.name)
        if index == len(parts) - 1:
            return current, field, value
        current = value

    raise ConfigKeyError(dotted, dotted)  # pragma: no cover