from io import StringIO class Config: """represents an implementation of the ConfigInterface""" # DEFAULT_SECTION specifies the name of a section if no name provided DEFAULT_SECTION = 'default' # DEFAULT_COMMENT defines what character(s) indicate a comment `#` DEFAULT_COMMENT = '#' # DEFAULT_COMMENT_SEM defines what alternate character(s) indicate a comment `;` DEFAULT_COMMENT_SEM = ';' # DEFAULT_MULTI_LINE_SEPARATOR defines what character indicates a multi-line content DEFAULT_MULTI_LINE_SEPARATOR = '\\' _data = dict() def __init__(self): self._data = dict() @staticmethod def new_config(conf_name): c = Config() c._parse(conf_name) return c @staticmethod def new_config_from_text(text): c = Config() f = StringIO(text) c._parse_buffer(f) return c def add_config(self, section, option, value): if section == '': section = self.DEFAULT_SECTION if section not in self._data.keys(): self._data[section] = {} self._data[section][option] = value def _parse(self, fname): with open(fname, 'r', encoding='utf-8') as f: self._parse_buffer(f) def _parse_buffer(self, f): section = '' line_num = 0 buf = [] can_write = False while True: if can_write: self._write(section, line_num, buf) can_write = False line_num = line_num + 1 line = f.readline() if not line: if len(buf) > 0: self._write(section, line_num, buf) break line = line.strip() if '' == line or self.DEFAULT_COMMENT == line[0:1] or self.DEFAULT_COMMENT_SEM == line[0:1]: can_write = True continue elif '[' == line[0:1] and ']' == line[-1]: if len(buf) > 0: self._write(section, line_num, buf) can_write = False section = line[1:-1] else: p = '' if self.DEFAULT_MULTI_LINE_SEPARATOR == line[-1]: p = line[0:-1].strip() p = p + ' ' else: p = line can_write = True buf.append(p) def _write(self, section, line_num, b): buf = "".join(b) if len(buf) <= 0: return option_val = buf.split('=', 1) if len(option_val) != 2: raise RuntimeError('parse the content error : line {} , {} = ?'.format(line_num, option_val[0])) option = option_val[0].strip() value = option_val[1].strip() self.add_config(section, option, value) del b[:] def get_bool(self, key): """lookups up the value using the provided key and converts the value to a bool.""" return self.get(key).capitalize() == "True" def get_int(self, key): """lookups up the value using the provided key and converts the value to a int""" return int(self.get(key)) def get_float(self, key): """lookups up the value using the provided key and converts the value to a float""" return float(self.get(key)) def get_string(self, key): """lookups up the value using the provided key and converts the value to a string""" return self.get(key) def get_strings(self, key): """lookups up the value using the provided key and converts the value to an array of string""" value = self.get(key) if value == "": return None return value.split(",") def set(self, key, value): if len(key) == 0: raise RuntimeError("key is empty") keys = key.lower().split('::') if len(keys) >= 2: section = keys[0] option = keys[1] else: section = "" option = keys[0] self.add_config(section, option, value) def get(self, key): """section.key or key""" keys = key.lower().split('::') if len(keys) >= 2: section = keys[0] option = keys[1] else: section = self.DEFAULT_SECTION option = keys[0] if section in self._data.keys(): if option in self._data[section].keys(): return self._data[section][option] return ''