"""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", "currency": { "RUB": "RUB;Russian ruble;Russian Federation;8;" \ "1к,5к,10к,50к,1₽,2₽,5₽,10₽;1,5,10,50,100,200,500,1000", "SRUB": "SRUB;Russian ruble (short);No 1 and 5 kopek;6;" \ "10к,50к,1₽,2₽,5₽,10₽;10,50,100,200,500,1000", "BYN": "BYN;Belarusian ruble;Belarus;8;" \ "1к,2к,5к,10к,20к,50к,1р,2р;1,2,5,10,20,50,100,200", "UAH": "UAH;Ukrainian hryvnia;Ukraine;10;" \ "1к,2к,5к,10к,25к,50к,₴1,₴2,₴5,₴10;1,2,5,10,25,50,100,200,500,1000", "USD": "USD;US Dollar;United States of America;6;" \ "1¢,5¢,10¢,25¢,50¢,$1;1,5,10,25,50,100", "EUR": "EUR;Euro;European Union;8;" \ "1c,2c,5c,10c,20c,50c,€1,€2;1,2,5,10,20,50,100,200", "GBP": "GBP;Pound sterling;United Kingdom;9;" \ "1p,2p,5p,10p,20p,25p,50p,£1,£2;1,2,5,10,20,25,50,100,200" } } 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] == "#" or line[0] == "\n": continue key, value = line[:-1].split(" = ") if key.find(".") != -1: k0, k1 = key.split(".") if not k0 in self._configuration: self._configuration[k0] = dict() 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(): if type(value) is dict: for subkey, subvalue in value.items(): cf.write(f"{key}.{subkey} = {subvalue}\n") else: cf.write(f"{key} = {value}\n") @property def items(self) -> dict: return self._configuration 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