1 | #!/usr/bin/env python |
||
2 | # -*- coding: utf-8 -*- |
||
3 | |||
4 | import logging |
||
5 | logger = logging.getLogger(__name__) |
||
6 | logger.debug("%s loaded", __name__) |
||
7 | |||
8 | import os |
||
9 | |||
10 | import ConfigParser |
||
11 | import doorpi |
||
12 | |||
13 | from backward_compatibility import BACKWARD_COMPATIBILITY_KEYS |
||
14 | |||
15 | class ConfigObject(): |
||
16 | |||
17 | __sections = {} |
||
18 | _config_file = None |
||
19 | |||
20 | @property |
||
21 | def all(self): return self.__sections |
||
22 | |||
23 | @property |
||
24 | def config_file(self): return self._config_file |
||
25 | |||
26 | def __init__(self, config, config_file = None): |
||
27 | logger.debug("__init__") |
||
28 | self.get_from_config(config) |
||
29 | self._config_file = config_file |
||
30 | |||
31 | def __del__(self): |
||
32 | return self.destroy() |
||
33 | |||
34 | def destroy(self): |
||
35 | logger.debug("__del__") |
||
36 | #DoorPi().event_handler.unregister_source(__name__, True) |
||
37 | return True |
||
38 | |||
39 | @staticmethod |
||
40 | def find_config(configfile = None): |
||
41 | try: |
||
42 | open(configfile.name, 'r').close() |
||
43 | return configfile.name |
||
44 | except AttributeError: pass |
||
45 | except IOError: pass |
||
46 | |||
47 | default_files = [ |
||
48 | str(configfile), |
||
49 | doorpi.DoorPi().parse_string(str(configfile)), |
||
50 | os.path.join('!BASEPATH!', 'conf', 'doorpi.ini'), |
||
51 | os.path.join('!BASEPATH!', 'conf', 'doorpi.cfg') |
||
52 | ] |
||
53 | |||
54 | for possible_default_file in default_files: |
||
55 | try: |
||
56 | possible_default_file = doorpi.DoorPi().parse_string(possible_default_file) |
||
57 | open(possible_default_file, 'r').close() |
||
58 | return possible_default_file |
||
59 | except: pass |
||
60 | |||
61 | return None |
||
62 | |||
63 | @staticmethod |
||
64 | def load_config(configfile, search_for_defaults = True): |
||
65 | config = ConfigParser.ConfigParser(allow_no_value = True) |
||
66 | if search_for_defaults: configfile_name = ConfigObject.find_config(configfile) |
||
67 | else: configfile_name = configfile |
||
68 | |||
69 | if not configfile_name: |
||
70 | logger.error('No valid configfile found - use parameter --configfile "filename" to specify one') |
||
71 | return ConfigObject(config) |
||
72 | |||
73 | logger.info("use configfile: %s", configfile_name) |
||
74 | |||
75 | config.read(configfile_name) |
||
76 | return ConfigObject(config, configfile_name) |
||
77 | |||
78 | def save_config(self, configfile = ''): |
||
79 | if not configfile: configfile = self.config_file |
||
80 | if not configfile: configfile = self.find_config(configfile) |
||
81 | if not configfile: configfile = doorpi.DoorPi().parse_string(os.path.join('!BASEPATH!', 'conf', 'doorpi.ini')) |
||
82 | |||
83 | #if not configfile: return False |
||
84 | logger.debug("write configfile: %s", configfile) |
||
85 | try: |
||
86 | if not os.path.exists(os.path.dirname(configfile)): |
||
87 | logger.info('Path %s does not exist - creating it now', os.path.dirname(configfile)) |
||
88 | os.makedirs(os.path.dirname(configfile)) |
||
89 | cfgfile = open(configfile,'w') |
||
90 | config = ConfigParser.ConfigParser(allow_no_value = True) |
||
91 | for section in sorted(self.__sections.keys()): |
||
92 | config.add_section(section) |
||
93 | for key in sorted(self.__sections[section].keys()): |
||
94 | config.set(section, key, self.__sections[section][key]) |
||
95 | config.write(cfgfile) |
||
96 | cfgfile.close() |
||
97 | logger.info("write configfile was success: %s", configfile) |
||
98 | return True |
||
99 | except Exception as exp: |
||
100 | logger.exception(exp) |
||
101 | return False |
||
102 | |||
103 | def get_string_parsed(self, section, key, default = '', log = True): |
||
104 | raw_string = self.get_string(section, key, default, log) |
||
105 | parsed_string = doorpi.DoorPi().parse_string(raw_string) |
||
106 | logger.debug('parse string "%s" to "%s"', raw_string, parsed_string) |
||
107 | return parsed_string |
||
108 | |||
109 | def set_value(self, section, key, value, log = True, password = False): |
||
110 | if section not in self.__sections.keys(): |
||
111 | self.__sections[section] = {} |
||
112 | |||
113 | password_friendly_value = "*******" if key is 'password' or password else value |
||
114 | |||
115 | if key not in self.__sections[section].keys(): |
||
116 | if log: logger.debug("create new key %s in section %s with value '%s'", |
||
117 | key, section, password_friendly_value) |
||
118 | else: |
||
119 | if log: logger.debug("overwrite key %s in section %s from '%s' to '%s'", |
||
120 | key, section, self.__sections[section][key], password_friendly_value) |
||
121 | |||
122 | self.__sections[section][key] = value |
||
123 | return True |
||
124 | |||
125 | def rename_key(self, section, old_key, new_key, default = '', log = True): |
||
126 | if log: logging.debug('rename key from %s to %s in section %s', old_key, new_key, section) |
||
127 | old_value = self.get_string(section, old_key, default, log, store_if_not_exists = False) |
||
128 | self.set_value( |
||
129 | section = section, |
||
130 | key = new_key, |
||
131 | value = old_value, |
||
132 | log = log |
||
133 | ) |
||
134 | self.delete_key(section, old_key, log = log) |
||
135 | |||
136 | def delete_section(self, section, delete_empty_only = True, log = True): |
||
137 | if section in self.__sections and len(self.__sections[section]) > 0 and delete_empty_only: |
||
138 | logger.warning("could not delete section %s, because it's not empty.", section) |
||
139 | return False |
||
140 | |||
141 | try: |
||
142 | if len(self.__sections[section]) > 0 and delete_empty_only: |
||
143 | raise KeyError('section is not empty') |
||
144 | |||
145 | self.__sections.pop(section) |
||
146 | return True |
||
147 | except KeyError as exp: |
||
148 | if log: logger.warning('delete section %s failed: %s', section, exp) |
||
149 | return False |
||
150 | |||
151 | def delete_key(self, section, key, log = True): |
||
152 | try: |
||
153 | if log: logger.info('delete key %s from section %s', key, section) |
||
154 | self.__sections[section].pop(key) |
||
155 | self.delete_section(section, log = log) |
||
156 | |||
157 | return True |
||
158 | except KeyError as exp: |
||
159 | if log: logger.warning('delete key %s from section %s failed: %s', key, section, exp) |
||
160 | return False |
||
161 | |||
162 | def get_string(self, section, key, default = '', log = True, password = False, store_if_not_exists = True): |
||
163 | value = None |
||
164 | try: |
||
165 | old_section, old_key = BACKWARD_COMPATIBILITY_KEYS[section][key] |
||
166 | value = self.__sections[old_section][old_key] |
||
167 | self.delete_key(old_section, old_key, False) |
||
168 | self.__sections[section][key] = value |
||
169 | logger.warning('found %s - %s in BACKWARD_COMPATIBILITY_KEYS with %s - %s', section, key, old_section, old_key) |
||
170 | except KeyError: |
||
171 | try: |
||
172 | value = self.__sections[section][key] |
||
173 | except KeyError: |
||
174 | pass |
||
175 | |||
176 | if value is None: |
||
177 | #logger.trace('no value found - use default') |
||
178 | value = default |
||
179 | if store_if_not_exists: self.set_value(section, key, default, log, password) |
||
180 | |||
181 | if key.endswith('password') or password: |
||
182 | if log: logger.trace("get_string for key %s in section %s (default: %s) returns %s", key, section, default, '*******') |
||
183 | else: |
||
184 | if log: logger.trace("get_string for key %s in section %s (default: %s) returns %s", key, section, default, value) |
||
185 | return value |
||
186 | |||
187 | def get_float(self, section, key, default = -1, log = True, store_if_not_exists = True): |
||
188 | value = self.get_string(section, key, str(default), log = False, store_if_not_exists = store_if_not_exists) |
||
189 | if value is not '': value = float(value) |
||
190 | else: value = default |
||
191 | if log: logger.trace("get_integer for key %s in section %s (default: %s) returns %s", key, section, default, value) |
||
192 | return value |
||
193 | |||
194 | def get_integer(self, section, key, default = -1, log = True, store_if_not_exists = True): |
||
195 | value = self.get(section, key, str(default), log = False, store_if_not_exists = store_if_not_exists) |
||
196 | if value is not '': value = int(value) |
||
197 | else: value = default |
||
198 | if log: logger.trace("get_integer for key %s in section %s (default: %s) returns %s", key, section, default, value) |
||
199 | return value |
||
200 | |||
201 | def get_boolean(self, section, key, default = False, log = True, store_if_not_exists = True): |
||
202 | value = self.get(section, key, str(default), log = False, store_if_not_exists = store_if_not_exists) |
||
203 | value = value.lower() in ['true', 'yes', 'ja', '1'] |
||
204 | if log: logger.trace("get_boolean for key %s in section %s (default: %s) returns %s", key, section, default, value) |
||
205 | return value |
||
206 | |||
207 | def get_list(self, section, key, default = [], separator = ',', log = True, store_if_not_exists = True): |
||
208 | value = self.get(section, key, str(default), log = False, store_if_not_exists = store_if_not_exists) |
||
209 | if value is not '': value = value.split(separator) |
||
210 | else: value = default |
||
211 | if log: logger.trace("get_list for key %s in section %s (default: %s) returns %s", key, section, default, value) |
||
212 | return value |
||
213 | |||
214 | def get_sections(self, filter = '', log = True): |
||
0 ignored issues
–
show
|
|||
215 | return_list = [] |
||
216 | for section in self.__sections: |
||
217 | if filter in section: return_list.append(section) |
||
218 | if log: logger.trace("get_sections returns %s", return_list) |
||
219 | return return_list |
||
220 | |||
221 | def get_keys(self, section, filter = '', log = True): |
||
0 ignored issues
–
show
|
|||
222 | return_list = [] |
||
223 | if section not in self.__sections: |
||
224 | logging.warning("section %s not found in configfile", section) |
||
225 | else: |
||
226 | for key in self.__sections[section]: |
||
227 | if filter in key: return_list.append(key) |
||
228 | if log: logger.trace("get_keys for section %s returns %s", section, return_list) |
||
229 | return return_list |
||
230 | |||
231 | def get_from_config(self, config, log = True): |
||
232 | if log: logger.trace("get_from_config") |
||
233 | for section in config.sections(): |
||
234 | self.__sections[section] = {} |
||
235 | for key, value in config.items(section): |
||
236 | if key.startswith(';') or key.startswith('#'): continue |
||
237 | self.__sections[section][str(key)] = str(value) |
||
238 | |||
239 | get = get_string |
||
240 | get_bool = get_boolean |
||
241 | get_int = get_integer |
||
242 |
It is generally discouraged to redefine built-ins as this makes code very hard to read.