87 lines
3.2 KiB
Python
87 lines
3.2 KiB
Python
"""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",
|
||
"DEFAULT_CONFIGURATION_FILE"]
|
||
|
||
|
||
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:
|
||
# <ISO>;<CURRENCY NAME>;<COINS COUNT>;{}<FRACTION SYMBOL>,{}<CURRENCY SYMBOL>;<FACE VALUES>
|
||
# "{}" 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;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', encoding='utf8'):
|
||
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', encoding='utf8') 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
|