def save(self, filename=None): if not filename: filename = self.filename if not filename: filename = sys.stdout if isinstance(filename, (str, text_type)): f = open(filename, 'wb') need_close = True else: f = filename need_close = False print_('#coding=%s' % self._encoding, file=f) for s in self.keys(): if s in self._env: continue section = self[s] section.dumps(f, convertors=self._convertors) if need_close: f.close()
def read(self, fobj, filename=''): encoding = None if isinstance(fobj, (str, text_type)): f = open(fobj, 'rb') text = f.read() f.close() else: text = fobj.read() text = text + b'\n' begin = 0 if text.startswith(codecs.BOM_UTF8): begin = 3 encoding = 'UTF-8' elif text.startswith(codecs.BOM_UTF16): begin = 2 encoding = 'UTF-16' if not encoding: try: text_type(text, 'UTF-8') encoding = 'UTF-8' except: encoding = defaultencoding self._encoding = encoding f = StringIO(text_type(text, 'utf-8')) f.seek(begin) lineno = 0 comments = [] section = None while 1: lastpos = f.tell() line = f.readline() lineno += 1 if not line: break line = line.strip() if line: if line.startswith(self._commentchar): if lineno == 1: #first comment line b = r_encoding.search(line[1:]) if b: self._encoding = b.groups()[0] continue comments.append(line) elif line.startswith('[') and line.endswith(']'): sec_name = line[1:-1].strip() #process include notation if sec_name.startswith('include:'): _filename = sec_name[8:].strip() _filename = os.path.abspath(_filename) if os.path.exists(_filename): old_encoding = self._encoding self.read(_filename) self._encoding = old_encoding else: import warnings warnings.warn(Warning("Can't find the file [%s], so just skip it" % _filename), stacklevel=2) continue info = RawValue(self._inifile, lineno, sec_name) section = self.add(sec_name, comments, info=info) comments = [] elif '=' in line: if section is None: raise Exception("No section found, please define it first in %s file" % self.filename) #if find <=, then it'll replace the old value for mutable variables #because the default behavior will merge list and dict pos = line.find('<=') if pos != -1: begin, end = pos, pos+2 replace_flag = True else: pos = line.find('=') begin, end = pos, pos+1 replace_flag = False keyname = line[:begin].strip() #check keyname if keyname in self._env: raise KeyError("Settings key %s is alread defined in env, please change it's name" % keyname) rest = line[end:].strip() #if key= then value will be set '' if rest == '': v = None else: f.seek(lastpos+end) try: value, iden_existed = self.__read_line(f) except Exception as e: print_exc() raise Exception("Parsing ini file error in %s:%d:%s" % (filename or self._inifile, lineno, line)) if self._lazy: if iden_existed: v = EvalValue(value, filename or self._inifile, lineno, line) else: v = value else: if self._raw: v = RawValue(self._inifile, lineno, value, replace_flag) else: try: v = eval_value(value, self.env(), self[sec_name], self._encoding) except Exception as e: print(e) print_exc() print_(dict(self)) raise Exception("Converting value (%s) error in %s:%d:%s" % (value, filename or self._inifile, lineno, line)) section.add(keyname, v, comments, replace=replace_flag) comments = [] else: comments.append(line)
def dumps(self, out, convertors=None): if self._comments: print_('\n'.join(self._comments), file=out) if self._root and self._root._raw: print_('%s [%s]' % (self._info, self._name), file=out) else: print_('[%s]' % self._name, file=out) for f in self.keys(): comments = self.comment(f) if comments: print_('\n'.join(comments), file=out) if self._root and self._root._raw: print_("%s %s%s" % (str(self[f]), f, self[f].value()), file=out) else: if self._field_flag.get(f, False): op = ' <= ' else: op = ' = ' buf = f + op + uni_prt(self[f], self._encoding, convertors=convertors) if len(buf) > 79: buf = f + op + uni_prt(self[f], self._encoding, True, convertors=convertors) print_(buf, file=out)