Source code for absfuyu.config

"""
Absfuyu: Configuration
----------------------
Package configuration module

Version: 5.1.0
Date updated: 10/03/2025 (dd/mm/yyyy)
"""

# Module level
# ---------------------------------------------------------------------------
__all__ = [
    "ABSFUYU_CONFIG",
    "Config",
    "CONFIG_PATH",
    # "Setting"
]


# Library
# ---------------------------------------------------------------------------
from importlib.resources import files
from pathlib import Path
from typing import Any, TypedDict

from absfuyu.core import BaseClass
from absfuyu.util.json_method import JsonFile

# Setting
# ---------------------------------------------------------------------------
CONFIG_PATH = files("absfuyu.config").joinpath("config.json")
_SPACE_REPLACE = "-"  # Replace " " character in setting name


# Type hint
# ---------------------------------------------------------------------------
class SettingDictFormat(TypedDict):
    """
    Format for the ``setting`` section in ``config``

    :param default: Default value for the setting
    :param help: Description for the setting
    :param value: Current value of the setting
    """

    default: Any
    help: str
    value: Any


class ConfigFormat(TypedDict):
    """
    Config file format

    :param setting: setting section
    :type setting: dict[str, SettingDictFormat]
    :param version: version section
    :type version: VersionDictFormat
    """

    setting: dict[str, SettingDictFormat]


# Class
# ---------------------------------------------------------------------------
class Setting(BaseClass):
    """Setting"""

    def __init__(self, name: str, value: Any, default: Any, help_: str = "") -> None:
        """
        :param name: Name of the setting
        :param value: Value of the setting
        :param default: Default value of the setting
        :param help: Description of the setting
        """
        self.name = name
        self.value = value
        self.default = default
        self.help = help_

    def __str__(self) -> str:
        return f"{self.__class__.__name__}({self.name}: {self.value})"

    @classmethod
    def from_dict(cls, dict_data: dict[str, SettingDictFormat]):
        """
        Convert ``dict`` into ``Setting`` (``len==1`` only)
        """
        name: str = list(dict_data.keys())[0]
        _val: SettingDictFormat = list(dict_data.values())[0]
        value: Any = _val["value"]
        default: Any = _val["default"]
        help_: str = _val["help"]
        return cls(name, value, default, help_)

    def reset(self) -> None:
        """
        Reset setting to default value
        (``Setting.value = Setting.default``)
        """
        self.value = self.default

    def update_value(self, value: Any) -> None:
        """Update current value"""
        self.value = value

    def to_dict(self) -> dict[str, SettingDictFormat]:
        """
        Convert ``Setting`` into ``dict``
        """
        output: dict[str, SettingDictFormat] = {
            self.name: {"default": self.default, "help": self.help, "value": self.value}
        }
        return output


[docs] class Config(BaseClass): """ Config handling """ def __init__(self, config_file: Path, name: str | None = None) -> None: """ config_file: Path to `.json` config file """ self.config_path: Path = config_file self.json_engine: JsonFile = JsonFile(self.config_path) if name is None: self.name = self.config_path.name else: self.name = name # Data self.settings: list[Setting] = None # type: ignore self._fetch_data() # Load data def __str__(self) -> str: return f"{self.__class__.__name__}({self.config_path.name})" # Data prepare and export def _fetch_data(self) -> None: """Load data from ``self.config_file`` file""" data: dict = self.json_engine.load_json() settings: dict[str, SettingDictFormat] = data.get("setting") # type: ignore self.settings = [Setting.from_dict({k: v}) for k, v in settings.items()] def _prepare_data(self) -> ConfigFormat: """Prepare data to save config""" settings = dict() for setting in self.settings: settings.update(setting.to_dict()) out: ConfigFormat = {"setting": settings} return out
[docs] def save(self) -> None: """Save config to ``.json`` file""" self.json_engine.update_data(self._prepare_data()) # type: ignore self.json_engine.save_json()
# Setting method @property def setting_list(self) -> list[str]: """List of name of available settings""" return [setting.name for setting in self.settings] def _get_setting(self, name: str): """Get setting""" name = name.strip().lower().replace(" ", _SPACE_REPLACE) if name in self.setting_list: for setting in self.settings: if setting.name.startswith(name): return setting else: raise ValueError(f"Setting list: {self.setting_list}")
[docs] def reset_config(self) -> None: """Reset all settings to default value""" [setting.reset() for setting in self.settings] # type: ignore self.save()
[docs] def show_settings(self) -> list[Setting]: """ Returns a list of available settings (wrapper for ``Config.settings``) """ return self.settings
[docs] def change_setting(self, name: str, value: Any) -> None: """ Change ``Setting`` (if available) Parameters ---------- name : str Name of the setting value : Any Value of the setting """ name = name.strip().lower().replace(" ", _SPACE_REPLACE) if name in self.setting_list: for setting in self.settings: if setting.name.startswith(name): setting.update_value(value) break else: raise ValueError(f"Setting list: {self.setting_list}") self.save()
[docs] def toggle_setting(self, name: str) -> None: """ Special ``change_setting()`` method. Turn on/off if ``type(<setting>) is bool`` Parameters ---------- name : str Name of the setting """ # Get setting setting = self._get_setting(name) setting_value: bool = setting.value # Change value try: self.change_setting(name, not setting_value) except Exception: raise SystemExit("This setting is not type: bool") # noqa: B904
[docs] def add_setting(self, name: str, value: Any, default: Any, help_: str = "") -> None: """ Add ``Setting`` if not exist Parameters ---------- name : str Name of the setting value : Any Value of the setting default : Any Default value of the setting help_ : str Description of the setting (Default: ``None``) """ name = name.strip().lower().replace(" ", _SPACE_REPLACE) new_setting = Setting(name, value, default, help_) if new_setting not in self.settings: self.settings.append(new_setting) self.save()
[docs] def del_setting(self, name: str) -> None: """ Delete ``Setting`` Parameters ---------- name : str Name of the setting """ name = name.strip().lower().replace(" ", _SPACE_REPLACE) self.settings = [x for x in self.settings if x.name != name] self.save()
[docs] def welcome(self) -> None: """Run first-run script (if any)""" self.change_setting("first-run", False)
# Init # --------------------------------------------------------------------------- ABSFUYU_CONFIG = Config(CONFIG_PATH) # type: ignore