Source code for leads.config.template

from json import dumps as _dumps
from typing import override as _override, Literal as _Literal, Any as _Any

from leads.data import Serializable
from leads.types import SupportedConfig as _SupportedConfig


[docs] class ConfigTemplate(Serializable): def __init__(self, base: dict[str, _SupportedConfig]) -> None: """ All custom attributes should be public (not named after "_"). Writable attributes should start with "w_" such as "w_debug_level". :param base: the base dictionary """ self._d: dict[str, _SupportedConfig] = self.fix_dict(base) self._frozen: bool = False self.w_debug_level: _Literal["DEBUG", "INFO", "WARN", "ERROR"] = "DEBUG" self.data_seq_size: int = 100 self.num_laps_timed: int = 3 self.refresh()
[docs] def fix_dict(self, d: dict[str, _Any]) -> dict[str, _SupportedConfig]: """ Fix the types of every element in the dictionary. :param d: the input dictionary :return: the fixed dictionary """ return {k: self.fix_type(v) for k, v in d.items()}
[docs] def fix_type(self, value: _Any) -> _SupportedConfig: """ Replace lists with tuples and check for illegal types. :param value: the input value :return: the fixed value where :exception TypeError: the type of the value is illegal """ if isinstance(value, (tuple, list)): return tuple(self.fix_type(i) for i in value) if not isinstance(value, (bool, int, float, str, type(None))): raise TypeError(f"Unsupported value type: {value}") return value
[docs] def __getitem__(self, name: str) -> _SupportedConfig | None: return self.get(name)
[docs] def __setitem__(self, name: str, value: _SupportedConfig) -> None: self.set(name, value)
[docs] @_override def __setattr__(self, name: str, value: _SupportedConfig) -> None: if self._writable(name): super().__setattr__(name, value if name.startswith("_") else self.fix_type(value))
[docs] @_override def __str__(self) -> str: """ Convert to a JSON string. :return: the JSON string """ return _dumps(self.to_dict())
[docs] @_override def to_dict(self) -> dict[str, _SupportedConfig]: return self._d.copy()
[docs] def _writable(self, name: str) -> bool: """ :param name: the configuration name :return: True: writable; False: readonly """ return not hasattr(self, "_frozen") or not self._frozen or name.startswith("w_")
[docs] def set(self, name: str, value: _SupportedConfig) -> None: """ Set the value with the given name in the dictionary. :param name: the dictionary key :param value: the value to set """ if self._writable(name): self._d[name] = self.fix_type(value) self.refresh()
[docs] def get(self, name: str, default: _SupportedConfig | None = None) -> _SupportedConfig | None: """ Get the value of a given name from the dictionary. :param name: the dictionary key :param default: the default value if the value does not exist :return: the value if it exists or else the default value """ return self._d.get(name, default)
[docs] def refresh(self) -> None: """ Write the dictionary into the instance attributes. """ for name in dir(self): if not name.startswith("_") and (v := self._d.get(name)) is not None: if self._writable(name): setattr(self, name, v) self._frozen = True