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