Commit | Line | Data |
---|---|---|
8ee66edd FC |
1 | import sys |
2 | from logging import info | |
3 | from os import makedirs | |
4 | from os.path import dirname | |
addec9c9 | 5 | from collections.abc import Mapping |
8ee66edd | 6 | from configparser import ConfigParser |
bf77b5d5 | 7 | from ya2.utils.logics import LogicsTools |
8ee66edd FC |
8 | |
9 | ||
aed9737a | 10 | class DctFile: |
8ee66edd FC |
11 | |
12 | def __init__(self, fpath, default_dct=None, persistent=True): | |
8ee66edd | 13 | default_dct = default_dct or {} |
026d2510 | 14 | if sys.platform == 'darwin' and LogicsTools.in_build: |
8ee66edd FC |
15 | fpath = dirname(__file__) + '/' + fpath |
16 | self.fpath = fpath | |
17 | self.persistent = persistent | |
18 | try: | |
e65a09cf | 19 | # with open(fpath) as json: fdct = load(json) |
8ee66edd FC |
20 | config = ConfigParser() |
21 | config.read(fpath) | |
e65a09cf FC |
22 | fdct = {section: dict(config.items(section)) |
23 | for section in config.sections()} | |
8ee66edd FC |
24 | fdct = self.__typed_dct(fdct) |
25 | self.dct = self.__add_default(default_dct, fdct) | |
e65a09cf FC |
26 | except IOError: |
27 | self.dct = default_dct | |
8ee66edd FC |
28 | |
29 | @staticmethod | |
30 | def __typed_dct(dct): | |
31 | def convert_single_val(val): | |
e65a09cf FC |
32 | try: |
33 | return int(val) | |
8ee66edd | 34 | except ValueError: |
e65a09cf FC |
35 | try: |
36 | return float(val) | |
8ee66edd FC |
37 | except ValueError: |
38 | if not val or val[0] != '[': | |
39 | return val | |
40 | else: | |
41 | raise ValueError | |
e65a09cf | 42 | |
8ee66edd | 43 | def converted(val): |
e65a09cf FC |
44 | try: |
45 | return convert_single_val(val) | |
8ee66edd FC |
46 | except ValueError: |
47 | return [elm.strip() for elm in val[1:-1].split(',')] | |
48 | new_dct = {} | |
49 | for section, sec_dct in dct.items(): | |
50 | for key, val in sec_dct.items(): | |
51 | if section not in new_dct: | |
52 | new_dct[section] = {} | |
53 | new_dct[section][key] = converted(val) | |
54 | return new_dct | |
55 | ||
56 | @staticmethod | |
57 | def __add_default(dct, upd): | |
58 | for key, val in upd.items(): | |
59 | if isinstance(val, Mapping): | |
60 | dct[key] = DctFile.__add_default(dct.get(key, {}), val) | |
e65a09cf FC |
61 | else: |
62 | dct[key] = upd[key] | |
8ee66edd FC |
63 | return dct |
64 | ||
65 | @staticmethod | |
66 | def deepupdate(dct, new_dct): | |
67 | for key, val in new_dct.items(): | |
68 | if isinstance(val, Mapping): | |
69 | dct[key] = DctFile.deepupdate(dct.get(key, {}), val) | |
e65a09cf FC |
70 | else: |
71 | dct[key] = val | |
8ee66edd FC |
72 | return dct |
73 | ||
74 | def store(self): | |
75 | info('storing %s' % self.fpath) | |
76 | if not self.persistent: return | |
e65a09cf FC |
77 | # json_str = dumps(self.dct, sort_keys=True, indent=4, |
78 | # separators=(',', ': ')) | |
79 | # with open(self.fpath, 'w') as json: json.write(json_str) | |
8ee66edd FC |
80 | fdct = {} |
81 | for section, sec_dct in self.dct.items(): | |
82 | if section not in fdct: | |
83 | fdct[section] = {} | |
84 | for key, val in sec_dct.items(): | |
85 | if type(val) == list: | |
86 | fdct[section][key] = '[%s]' % ', '.join(val) | |
87 | else: | |
88 | fdct[section][key] = val | |
89 | config = ConfigParser() | |
90 | for key in self.dct: | |
91 | config[key] = fdct[key] | |
92 | if dirname(self.fpath): | |
93 | makedirs(dirname(self.fpath), exist_ok=True) | |
94 | with open(self.fpath, 'w') as ini_file: | |
95 | config.write(ini_file) | |
96 | ||
97 | def __getitem__(self, arg): return self.dct[arg] | |
98 | ||
99 | def __setitem__(self, arg, val): self.dct[arg] = val | |
100 | ||
101 | def __delitem__(self, arg): del self.dct[arg] |