"""An implementation of a slightly advanced key=value configuration file. Commentary lines are started with # symbol. Keys and values are separated by ' = ' (spaces are necessary). Keys with . symbol are splited and right part is a nested dictionary. Example: # A commentary line default_something = 10 currency.RUB = ... Above example is translated as a following dictionary: { "default_something": 10, "currency": { "RUB": "..." } } """ from os import getenv from os.path import exists, join from platform import system from typing import Union __all__ = ["Configuration", "get_configuration_path"] def get_configuration_path() -> str: """Returns a path to where configuration is stored.""" if system() == "Linux": return getenv("XDG_CONFIG_HOME") or f"{getenv('HOME')}/.config" elif system() == "Windows": return getenv("APPDATA") DEFAULT_CONFIGURATION = { "default-currency": "SRUB" } DEFAULT_CONFIGURATION_FILE = join(get_configuration_path(), "piggybank.conf") class Configuration: def __init__(self, configuration_file: str = DEFAULT_CONFIGURATION_FILE, default_configuration: dict = DEFAULT_CONFIGURATION) -> None: self._configuration_file = configuration_file self._configuration = dict() if exists(self._configuration_file): self.load() elif not default_configuration is None: self._configuration = default_configuration self.save() def load(self) -> None: for line in open(self._configuration_file, 'r'): if line[0] == "#": continue key, value = line[:-1].split(" = ") if key.find(".") != -1: k0, k1 = key.split(".") self._configuration[k0] = {k1 : value} else: self._configuration[key] = value def save(self) -> None: with open(self._configuration_file, 'w') as cf: for key, value in self._configuration.items(): cf.write(f"{key} = {value}\n") def __getitem__(self, key: str) -> Union[int, str, bool]: return self._configuration[key] def __setitem__(self, key: str, value: Union[int, str, bool]) -> None: self._configuration[key] = value