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