"""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_FILE_CONTENT = \ """# A default currency's ISO code. default-currency = SRUB # A set of predefined currencies. # Format is following: # ;;;{},{}; # "{}" is used as a placeholder for where to put digits. currency.RUB = RUB;Russian ruble;8;{}коп.,{}₽;1,5,10,50,100,200,500,1000 currency.SRUB = SRUB;Russian ruble (no 1 and 5 kopek);6;{}коп.,{}₽;10,50,100,200,500,1000 currency.BYN = BYN;Belarusian ruble;8;{}коп.,{}р.;1,2,5,10,20,50,100,200 currency.UAH = UAH;Ukrainian hryvnia;10;{}коп.,₴{};1,2,5,10,25,50,100,200,500,1000 currency.USD = USD;US Dollar;6;{}¢,${};1,5,10,25,50,100 currency.EUR = EUR;Euro;8;{}c,{}€;1,2,5,10,20,50,100,200 currency.GBP = GBP;Pound sterling;9;{}p,£{};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) -> None: self._configuration_file = configuration_file self._configuration = dict() if exists(self._configuration_file): self.load() else: raise FileNotFoundError() def load(self) -> None: for line in open(self._configuration_file, 'r'): if line[0] in ['#', '\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 @staticmethod def write_default_to_file(self, path: str = DEFAULT_CONFIGURATION_FILE) -> None: """Writes default configuration to a file. Overrides existing.""" with open(path, 'w') as cf: cf.write(DEFAULT_CONFIGURATION_FILE_CONTENT) @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