/
usr
/
lib
/
python3.6
/
site-packages
/
iniparse
/
/usr/lib/python3.6/site-packages/iniparse
mkdir
upload
Name
Size
Mode
Actions
__pycache__/
-
0755
rm
compat.py
12143
0644
edit
dl
rm
config.py
8321
0644
edit
dl
rm
configparser.py
271
0644
edit
dl
rm
ini.py
20742
0644
edit
dl
rm
utils.py
1274
0644
edit
dl
rm
__init__.py
1121
0644
edit
dl
rm
Edit:
/usr/lib/python3.6/site-packages/iniparse/ini.py
(20742B)
"""Access and/or modify INI files * Compatiable with ConfigParser * Preserves order of sections & options * Preserves comments/blank lines/etc * More conveninet access to data Example: >>> from six import StringIO >>> sio = StringIO('''# configure foo-application ... [foo] ... bar1 = qualia ... bar2 = 1977 ... [foo-ext] ... special = 1''') >>> cfg = INIConfig(sio) >>> print(cfg.foo.bar1) qualia >>> print(cfg['foo-ext'].special) 1 >>> cfg.foo.newopt = 'hi!' >>> cfg.baz.enabled = 0 >>> print(cfg) # configure foo-application [foo] bar1 = qualia bar2 = 1977 newopt = hi! [foo-ext] special = 1 <BLANKLINE> [baz] enabled = 0 """ # An ini parser that supports ordered sections/options # Also supports updates, while preserving structure # Backward-compatiable with ConfigParser import re from .configparser import DEFAULTSECT, ParsingError, MissingSectionHeaderError import six from . import config class LineType(object): line = None def __init__(self, line=None): if line is not None: self.line = line.strip('\n') # Return the original line for unmodified objects # Otherwise construct using the current attribute values def __str__(self): if self.line is not None: return self.line else: return self.to_string() # If an attribute is modified after initialization # set line to None since it is no longer accurate. def __setattr__(self, name, value): if hasattr(self,name): self.__dict__['line'] = None self.__dict__[name] = value def to_string(self): raise Exception('This method must be overridden in derived classes') class SectionLine(LineType): regex = re.compile(r'^\[' r'(?P<name>[^]]+)' r'\]\s*' r'((?P<csep>;|#)(?P<comment>.*))?$') def __init__(self, name, comment=None, comment_separator=None, comment_offset=-1, line=None): super(SectionLine, self).__init__(line) self.name = name self.comment = comment self.comment_separator = comment_separator self.comment_offset = comment_offset def to_string(self): out = '[' + self.name + ']' if self.comment is not None: # try to preserve indentation of comments out = (out+' ').ljust(self.comment_offset) out = out + self.comment_separator + self.comment return out def parse(cls, line): m = cls.regex.match(line.rstrip()) if m is None: return None return cls(m.group('name'), m.group('comment'), m.group('csep'), m.start('csep'), line) parse = classmethod(parse) class OptionLine(LineType): def __init__(self, name, value, separator=' = ', comment=None, comment_separator=None, comment_offset=-1, line=None): super(OptionLine, self).__init__(line) self.name = name self.value = value self.separator = separator self.comment = comment self.comment_separator = comment_separator self.comment_offset = comment_offset def to_string(self): out = '%s%s%s' % (self.name, self.separator, self.value) if self.comment is not None: # try to preserve indentation of comments out = (out+' ').ljust(self.comment_offset) out = out + self.comment_separator + self.comment return out regex = re.compile(r'^(?P<name>[^:=\s[][^:=]*)' r'(?P<sep>[:=]\s*)' r'(?P<value>.*)$') def parse(cls, line): m = cls.regex.match(line.rstrip()) if m is None: return None name = m.group('name').rstrip() value = m.group('value') sep = m.group('name')[len(name):] + m.group('sep') # comments are not detected in the regex because # ensuring total compatibility with ConfigParser # requires that: # option = value ;comment // value=='value' # option = value;1 ;comment // value=='value;1 ;comment' # # Doing this in a regex would be complicated. I # think this is a bug. The whole issue of how to # include ';' in the value needs to be addressed. # Also, '#' doesn't mark comments in options... coff = value.find(';') if coff != -1 and value[coff-1].isspace(): comment = value[coff+1:] csep = value[coff] value = value[:coff].rstrip() coff = m.start('value') + coff else: comment = None csep = None coff = -1 return cls(name, value, sep, comment, csep, coff, line) parse = classmethod(parse) def change_comment_syntax(comment_chars='%;#', allow_rem=False): comment_chars = re.sub(r'([\]\-\^])', r'\\\1', comment_chars) regex = r'^(?P<csep>[%s]' % comment_chars if allow_rem: regex += '|[rR][eE][mM]' regex += r')(?P<comment>.*)$' CommentLine.regex = re.compile(regex) class CommentLine(LineType): regex = re.compile(r'^(?P<csep>[;#]|[rR][eE][mM])' r'(?P<comment>.*)$') def __init__(self, comment='', separator='#', line=None): super(CommentLine, self).__init__(line) self.comment = comment self.separator = separator def to_string(self): return self.separator + self.comment def parse(cls, line): m = cls.regex.match(line.rstrip()) if m is None: return None return cls(m.group('comment'), m.group('csep'), line) parse = classmethod(parse) class EmptyLine(LineType): # could make this a singleton def to_string(self): return '' value = property(lambda _: '') def parse(cls, line): if line.strip(): return None return cls(line) parse = classmethod(parse) class ContinuationLine(LineType): regex = re.compile(r'^\s+(?P<value>.*)$') def __init__(self, value, value_offset=None, line=None): super(ContinuationLine, self).__init__(line) self.value = value if value_offset is None: value_offset = 8 self.value_offset = value_offset def to_string(self): return ' '*self.value_offset + self.value def parse(cls, line): m = cls.regex.match(line.rstrip()) if m is None: return None return cls(m.group('value'), m.start('value'), line) parse = classmethod(parse) class LineContainer(object): def __init__(self, d=None): self.contents = [] self.orgvalue = None if d: if isinstance(d, list): self.extend(d) else: self.add(d) def add(self, x): self.contents.append(x) def extend(self, x): for i in x: self.add(i) def get_name(self): return self.contents[0].name def set_name(self, data): self.contents[0].name = data def get_value(self): if self.orgvalue is not None: return self.orgvalue elif len(self.contents) == 1: return self.contents[0].value else: return '\n'.join([('%s' % x.value) for x in self.contents if not isinstance(x, CommentLine)]) def set_value(self, data): self.orgvalue = data lines = ('%s' % data).split('\n') # If there is an existing ContinuationLine, use its offset value_offset = None for v in self.contents: if isinstance(v, ContinuationLine): value_offset = v.value_offset break # Rebuild contents list, preserving initial OptionLine self.contents = self.contents[0:1] self.contents[0].value = lines[0] del lines[0] for line in lines: if line.strip(): self.add(ContinuationLine(line, value_offset)) else: self.add(EmptyLine()) name = property(get_name, set_name) value = property(get_value, set_value) def __str__(self): for c in self.contents: pass#print(c.__str__()) s = [x.__str__() for x in self.contents] return '\n'.join(s) def finditer(self, key): for x in self.contents[::-1]: if hasattr(x, 'name') and x.name==key: yield x def find(self, key): for x in self.finditer(key): return x raise KeyError(key) def _make_xform_property(myattrname, srcattrname=None): private_attrname = myattrname + 'value' private_srcname = myattrname + 'source' if srcattrname is None: srcattrname = myattrname def getfn(self): srcobj = getattr(self, private_srcname) if srcobj is not None: return getattr(srcobj, srcattrname) else: return getattr(self, private_attrname) def setfn(self, value): srcobj = getattr(self, private_srcname) if srcobj is not None: setattr(srcobj, srcattrname, value) else: setattr(self, private_attrname, value) return property(getfn, setfn) class INISection(config.ConfigNamespace): _lines = None _options = None _defaults = None _optionxformvalue = None _optionxformsource = None _compat_skip_empty_lines = set() def __init__(self, lineobj, defaults = None, optionxformvalue=None, optionxformsource=None): self._lines = [lineobj] self._defaults = defaults self._optionxformvalue = optionxformvalue self._optionxformsource = optionxformsource self._options = {} _optionxform = _make_xform_property('_optionxform') def _compat_get(self, key): # identical to __getitem__ except that _compat_XXX # is checked for backward-compatible handling if key == '__name__': return self._lines[-1].name if self._optionxform: key = self._optionxform(key) try: value = self._options[key].value del_empty = key in self._compat_skip_empty_lines except KeyError: if self._defaults and key in self._defaults._options: value = self._defaults._options[key].value del_empty = key in self._defaults._compat_skip_empty_lines else: raise if del_empty: value = re.sub('\n+', '\n', value) return value def _getitem(self, key): if key == '__name__': return self._lines[-1].name if self._optionxform: key = self._optionxform(key) try: return self._options[key].value except KeyError: if self._defaults and key in self._defaults._options: return self._defaults._options[key].value else: raise def __setitem__(self, key, value): if self._optionxform: xkey = self._optionxform(key) else: xkey = key if xkey in self._compat_skip_empty_lines: self._compat_skip_empty_lines.remove(xkey) if xkey not in self._options: # create a dummy object - value may have multiple lines obj = LineContainer(OptionLine(key, '')) self._lines[-1].add(obj) self._options[xkey] = obj # the set_value() function in LineContainer # automatically handles multi-line values self._options[xkey].value = value def __delitem__(self, key): if self._optionxform: key = self._optionxform(key) if key in self._compat_skip_empty_lines: self._compat_skip_empty_lines.remove(key) for l in self._lines: remaining = [] for o in l.contents: if isinstance(o, LineContainer): n = o.name if self._optionxform: n = self._optionxform(n) if key != n: remaining.append(o) else: remaining.append(o) l.contents = remaining del self._options[key] def __iter__(self): d = set() for l in self._lines: for x in l.contents: if isinstance(x, LineContainer): if self._optionxform: ans = self._optionxform(x.name) else: ans = x.name if ans not in d: yield ans d.add(ans) if self._defaults: for x in self._defaults: if x not in d: yield x d.add(x) def _new_namespace(self, name): raise Exception('No sub-sections allowed', name) def make_comment(line): return CommentLine(line.rstrip('\n')) def readline_iterator(f): """iterate over a file by only using the file object's readline method""" have_newline = False while True: line = f.readline() if not line: if have_newline: yield "" return if line.endswith('\n'): have_newline = True else: have_newline = False yield line def lower(x): return x.lower() class INIConfig(config.ConfigNamespace): _data = None _sections = None _defaults = None _optionxformvalue = None _optionxformsource = None _sectionxformvalue = None _sectionxformsource = None _parse_exc = None _bom = False def __init__(self, fp=None, defaults=None, parse_exc=True, optionxformvalue=lower, optionxformsource=None, sectionxformvalue=None, sectionxformsource=None): self._data = LineContainer() self._parse_exc = parse_exc self._optionxformvalue = optionxformvalue self._optionxformsource = optionxformsource self._sectionxformvalue = sectionxformvalue self._sectionxformsource = sectionxformsource self._sections = {} if defaults is None: defaults = {} self._defaults = INISection(LineContainer(), optionxformsource=self) for name, value in defaults.items(): self._defaults[name] = value if fp is not None: self._readfp(fp) _optionxform = _make_xform_property('_optionxform', 'optionxform') _sectionxform = _make_xform_property('_sectionxform', 'optionxform') def _getitem(self, key): if key == DEFAULTSECT: return self._defaults if self._sectionxform: key = self._sectionxform(key) return self._sections[key] def __setitem__(self, key, value): raise Exception('Values must be inside sections', key, value) def __delitem__(self, key): if self._sectionxform: key = self._sectionxform(key) for line in self._sections[key]._lines: self._data.contents.remove(line) del self._sections[key] def __iter__(self): d = set() d.add(DEFAULTSECT) for x in self._data.contents: if isinstance(x, LineContainer): if x.name not in d: yield x.name d.add(x.name) def _new_namespace(self, name): if self._data.contents: self._data.add(EmptyLine()) obj = LineContainer(SectionLine(name)) self._data.add(obj) if self._sectionxform: name = self._sectionxform(name) if name in self._sections: ns = self._sections[name] ns._lines.append(obj) else: ns = INISection(obj, defaults=self._defaults, optionxformsource=self) self._sections[name] = ns return ns def __str__(self): if self._bom: fmt = u'\ufeff%s' else: fmt = '%s' return fmt % self._data.__str__() __unicode__ = __str__ _line_types = [EmptyLine, CommentLine, SectionLine, OptionLine, ContinuationLine] def _parse(self, line): for linetype in self._line_types: lineobj = linetype.parse(line) if lineobj: return lineobj else: # can't parse line return None def _readfp(self, fp): cur_section = None cur_option = None cur_section_name = None cur_option_name = None pending_lines = [] pending_empty_lines = False try: fname = fp.name except AttributeError: fname = '<???>' linecount = 0 exc = None line = None for line in readline_iterator(fp): # Check for BOM on first line if linecount == 0 and isinstance(line, six.text_type): if line[0] == u'\ufeff': line = line[1:] self._bom = True lineobj = self._parse(line) linecount += 1 if not cur_section and not isinstance(lineobj, (CommentLine, EmptyLine, SectionLine)): if self._parse_exc: raise MissingSectionHeaderError(fname, linecount, line) else: lineobj = make_comment(line) if lineobj is None: if self._parse_exc: if exc is None: exc = ParsingError(fname) exc.append(linecount, line) lineobj = make_comment(line) if isinstance(lineobj, ContinuationLine): if cur_option: if pending_lines: cur_option.extend(pending_lines) pending_lines = [] if pending_empty_lines: optobj._compat_skip_empty_lines.add(cur_option_name) pending_empty_lines = False cur_option.add(lineobj) else: # illegal continuation line - convert to comment if self._parse_exc: if exc is None: exc = ParsingError(fname) exc.append(linecount, line) lineobj = make_comment(line) if isinstance(lineobj, OptionLine): if pending_lines: cur_section.extend(pending_lines) pending_lines = [] pending_empty_lines = False cur_option = LineContainer(lineobj) cur_section.add(cur_option) if self._optionxform: cur_option_name = self._optionxform(cur_option.name) else: cur_option_name = cur_option.name if cur_section_name == DEFAULTSECT: optobj = self._defaults else: optobj = self._sections[cur_section_name] optobj._options[cur_option_name] = cur_option if isinstance(lineobj, SectionLine): self._data.extend(pending_lines) pending_lines = [] pending_empty_lines = False cur_section = LineContainer(lineobj) self._data.add(cur_section) cur_option = None cur_option_name = None if cur_section.name == DEFAULTSECT: self._defaults._lines.append(cur_section) cur_section_name = DEFAULTSECT else: if self._sectionxform: cur_section_name = self._sectionxform(cur_section.name) else: cur_section_name = cur_section.name if cur_section_name not in self._sections: self._sections[cur_section_name] = \ INISection(cur_section, defaults=self._defaults, optionxformsource=self) else: self._sections[cur_section_name]._lines.append(cur_section) if isinstance(lineobj, (CommentLine, EmptyLine)): pending_lines.append(lineobj) if isinstance(lineobj, EmptyLine): pending_empty_lines = True self._data.extend(pending_lines) if line and line[-1]=='\n': self._data.add(EmptyLine()) if exc: raise exc
Save
cmd:
run