Mercurial and Git clients can push and pull from this alias URL to interact with this repository. You can change to which repository an alias points by going to the Aliases link on the project page.
# Copyright (c) 2001, 2002, 2003 Python Software Foundation# Copyright (c) 2004 Paramjit Oberoi <param.cs.wisc.edu># All Rights Reserved. See LICENSE-PSF & LICENSE for details."""Access and/or modify INI files* Compatiable with ConfigParser* Preserves order of sections & options* Preserves comments/blank lines/etc* More conveninet access to dataExample: >>> from StringIO 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!' >>> print cfg # configure foo-application [foo] bar1 = qualia bar2 = 1977 newopt = hi! [foo-ext] special = 1"""# An ini parser that supports ordered sections/options# Also supports updates, while preserving structure# Backward-compatiable with ConfigParserimport re
import config
-from sets import Setfrom ConfigParser import DEFAULTSECT, ParsingError, MissingSectionHeaderError
class LineType(object):
line=Nonedef__init__(self,line=None):iflineisnotNone:self.line=line.strip('\n')# Return the original line for unmodified objects# Otherwise construct using the current attribute valuesdef__str__(self):ifself.lineisnotNone:returnself.lineelse:returnself.to_string()# If an attribute is modified after initialization# set line to None since it is no longer accurate.def__setattr__(self,name,value):ifhasattr(self,name):self.__dict__['line']=Noneself.__dict__[name]=valuedefto_string(self):raiseException('This method must be overridden in derived classes')classSectionLine(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=nameself.comment=commentself.comment_separator=comment_separatorself.comment_offset=comment_offsetdefto_string(self):out='['+self.name+']'ifself.commentisnotNone:# try to preserve indentation of commentsout=(out+' ').ljust(self.comment_offset)out=out+self.comment_separator+self.commentreturnoutdefparse(cls,line):m=cls.regex.match(line.rstrip())ifmisNone:returnNonereturncls(m.group('name'),m.group('comment'),m.group('csep'),m.start('csep'),line)parse=classmethod(parse)classOptionLine(LineType):def__init__(self,name,value,separator=' = ',comment=None,comment_separator=None,comment_offset=-1,line=None):super(OptionLine,self).__init__(line)self.name=nameself.value=valueself.separator=separatorself.comment=commentself.comment_separator=comment_separatorself.comment_offset=comment_offsetdefto_string(self):out='%s%s%s'%(self.name,self.separator,self.value)ifself.commentisnotNone:# try to preserve indentation of commentsout=(out+' ').ljust(self.comment_offset)out=out+self.comment_separator+self.commentreturnoutregex=re.compile(r'^(?P<name>[^:=\s[][^:=]*)'r'(?P<sep>[:=]\s*)'r'(?P<value>.*)$')defparse(cls,line):m=cls.regex.match(line.rstrip())ifmisNone:returnNonename=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(';')ifcoff!=-1andvalue[coff-1].isspace():comment=value[coff+1:]csep=value[coff]value=value[:coff].rstrip()coff=m.start('value')+coffelse:comment=Nonecsep=Nonecoff=-1returncls(name,value,sep,comment,csep,coff,line)parse=classmethod(parse)classCommentLine(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=commentself.separator=separatordefto_string(self):returnself.separator+self.commentdefparse(cls,line):m=cls.regex.match(line.rstrip())ifmisNone:returnNonereturncls(m.group('comment'),m.group('csep'),line)parse=classmethod(parse)classEmptyLine(LineType):# could make this a singletondefto_string(self):return''defparse(cls,line):ifline.strip():returnNonereturncls(line)parse=classmethod(parse)classContinuationLine(LineType):regex=re.compile(r'^\s+(?P<value>.*)$')def__init__(self,value,value_offset=8,line=None):super(ContinuationLine,self).__init__(line)self.value=valueself.value_offset=value_offsetdefto_string(self):return' '*self.value_offset+self.valuedefparse(cls,line):m=cls.regex.match(line.rstrip())ifmisNone:returnNonereturncls(m.group('value'),m.start('value'),line)parse=classmethod(parse)classLineContainer(object):def__init__(self,d=None):self.contents=[]self.orgvalue=Noneifd:ifisinstance(d,list):self.extend(d)else:self.add(d)defadd(self,x):self.contents.append(x)defextend(self,x):foriinx:self.add(i)defget_name(self):returnself.contents[0].namedefset_name(self,data):self.contents[0].name=datadefget_value(self):ifself.orgvalueisnotNone:returnself.orgvalueeliflen(self.contents)==1:returnself.contents[0].valueelse:return'\n'.join([str(x.value)forxinself.contentsifnotisinstance(x,(CommentLine,EmptyLine))])defset_value(self,data):self.orgvalue=datalines=str(data).split('\n')linediff=len(lines)-len(self.contents)iflinediff>0:for_inrange(linediff):self.add(ContinuationLine(''))eliflinediff<0:self.contents=self.contents[:linediff]fori,vinenumerate(lines):self.contents[i].value=vname=property(get_name,set_name)value=property(get_value,set_value)def__str__(self):s=[str(x)forxinself.contents]return'\n'.join(s)deffinditer(self,key):forxinself.contents[::-1]:ifhasattr(x,'name')andx.name==key:yieldxdeffind(self,key):forxinself.finditer(key):returnxraiseKeyError(key)def_make_xform_property(myattrname,srcattrname=None):private_attrname=myattrname+'value'private_srcname=myattrname+'source'ifsrcattrnameisNone:srcattrname=myattrnamedefgetfn(self):srcobj=getattr(self,private_srcname)ifsrcobjisnotNone:returngetattr(srcobj,srcattrname)else:returngetattr(self,private_attrname)defsetfn(self,value):srcobj=getattr(self,private_srcname)ifsrcobjisnotNone:setattr(srcobj,srcattrname,value)else:setattr(self,private_attrname,value)returnproperty(getfn,setfn)classINISection(config.ConfigNamespace):_lines=None_options=None_defaults=None_optionxformvalue=None_optionxformsource=Nonedef__init__(self,lineobj,defaults=None,optionxformvalue=None,optionxformsource=None):self._lines=[lineobj]self._defaults=defaultsself._optionxformvalue=optionxformvalueself._optionxformsource=optionxformsourceself._options={}_optionxform=_make_xform_property('_optionxform')def__getitem__(self,key):ifkey=='__name__':returnself._lines[-1].nameifself._optionxform:key=self._optionxform(key)try:returnself._options[key].valueexceptKeyError:ifself._defaultsandkeyinself._defaults._options:returnself._defaults._options[key].valueelse:raisedef__setitem__(self,key,value):ifself._optionxform:xkey=self._optionxform(key)else:xkey=keyifxkeynotinself._options:# create a dummy object - value may have multiple linesobj=LineContainer(OptionLine(key,''))self._lines[-1].add(obj)self._options[xkey]=obj# the set_value() function in LineContainer# automatically handles multi-line valuesself._options[xkey].value=valuedef__delitem__(self,key):ifself._optionxform:key=self._optionxform(key)forlinself._lines:remaining=[]foroinl.contents:ifisinstance(o,LineContainer):n=o.nameifself._optionxform:n=self._optionxform(n)ifkey!=n:remaining.append(o)else:remaining.append(o)l.contents=remaining del self._options[key]
def __iter__(self):
- d = Set()
+ d = set()
for l in self._lines:
for x in l.contents:
if isinstance(x, LineContainer):
ifself._optionxform:ans=self._optionxform(x.name)else:ans=x.nameifansnotind:yieldansd.add(ans)ifself._defaults:forxinself._defaults:ifxnotind:yieldxd.add(x)defnew_namespace(self,name):raiseException('No sub-sections allowed',name)defmake_comment(line):returnCommentLine(line.rstrip())defreadline_iterator(f):"""iterate over a file by only using the file object's readline method"""have_newline=FalsewhileTrue:line=f.readline()ifnotline:ifhave_newline:yield""returnifline.endswith('\n'):have_newline=Trueelse:have_newline=FalseyieldlineclassINIConfig(config.ConfigNamespace):_data=None_sections=None_defaults=None_optionxformvalue=None_optionxformsource=None_sectionxformvalue=None_sectionxformsource=None_parse_exc=Nonedef__init__(self,fp=None,defaults=None,parse_exc=True,optionxformvalue=str.lower,optionxformsource=None,sectionxformvalue=None,sectionxformsource=None):self._data=LineContainer()self._parse_exc=parse_excself._optionxformvalue=optionxformvalueself._optionxformsource=optionxformsourceself._sectionxformvalue=sectionxformvalueself._sectionxformsource=sectionxformsourceself._sections={}ifdefaultsisNone:defaults={}self._defaults=INISection(LineContainer(),optionxformsource=self)forname,valueindefaults.iteritems():self._defaults[name]=valueiffpisnotNone:self.readfp(fp)_optionxform=_make_xform_property('_optionxform','optionxform')_sectionxform=_make_xform_property('_sectionxform','optionxform')def__getitem__(self,key):ifkey==DEFAULTSECT:returnself._defaultsifself._sectionxform:key=self._sectionxform(key)returnself._sections[key]def__setitem__(self,key,value):raiseException('Values must be inside sections',key,value)def__delitem__(self,key):ifself._sectionxform:key=self._sectionxform(key)forlineinself._sections[key]._lines:self._data.contents.remove(line) del self._sections[key]
def __iter__(self):
- d = Set()
+ d = set()
for x in self._data.contents:
if isinstance(x, LineContainer):
if x.name not in d:
yieldx.named.add(x.name)defnew_namespace(self,name):ifself._data.contents:self._data.add(EmptyLine())obj=LineContainer(SectionLine(name))self._data.add(obj)ifself._sectionxform:name=self._sectionxform(name)ifnameinself._sections:ns=self._sections[name]ns._lines.append(obj)else:ns=INISection(obj,defaults=self._defaults,optionxformsource=self)self._sections[name]=nsreturnnsdef__str__(self):returnstr(self._data)_line_types=[EmptyLine,CommentLine,SectionLine,OptionLine,ContinuationLine]def_parse(self,line):forlinetypeinself._line_types:lineobj=linetype.parse(line)iflineobj:returnlineobjelse:# can't parse linereturnNonedefreadfp(self,fp):cur_section=Nonecur_option=Nonecur_section_name=Nonecur_option_name=Nonepending_lines=[]try:fname=fp.nameexceptAttributeError:fname='<???>'linecount=0exc=Noneline=Noneforlineinreadline_iterator(fp):lineobj=self._parse(line)linecount+=1ifnotcur_sectionandnotisinstance(lineobj,(CommentLine,EmptyLine,SectionLine)):ifself._parse_exc:raiseMissingSectionHeaderError(fname,linecount,line)else:lineobj=make_comment(line)iflineobjisNone:ifself._parse_exc:ifexcisNone:exc=ParsingError(fname)exc.append(linecount,line)lineobj=make_comment(line)ifisinstance(lineobj,ContinuationLine):ifcur_option:cur_option.extend(pending_lines)pending_lines=[]cur_option.add(lineobj)else:# illegal continuation line - convert to commentifself._parse_exc:ifexcisNone:exc=ParsingError(fname)exc.append(linecount,line)lineobj=make_comment(line)ifisinstance(lineobj,OptionLine):cur_section.extend(pending_lines)pending_lines=[]cur_option=LineContainer(lineobj)cur_section.add(cur_option)ifself._optionxform:cur_option_name=self._optionxform(cur_option.name)else:cur_option_name=cur_option.nameifcur_section_name==DEFAULTSECT:optobj=self._defaultselse:optobj=self._sections[cur_section_name]optobj._options[cur_option_name]=cur_optionifisinstance(lineobj,SectionLine):self._data.extend(pending_lines)pending_lines=[]cur_section=LineContainer(lineobj)self._data.add(cur_section)cur_option=Nonecur_option_name=Noneifcur_section.name==DEFAULTSECT:self._defaults._lines.append(cur_section)cur_section_name=DEFAULTSECTelse:ifself._sectionxform:cur_section_name=self._sectionxform(cur_section.name)else:cur_section_name=cur_section.nameifnotself._sections.has_key(cur_section_name):self._sections[cur_section_name]= \
INISection(cur_section,defaults=self._defaults,optionxformsource=self)else:self._sections[cur_section_name]._lines.append(cur_section)ifisinstance(lineobj,(CommentLine,EmptyLine)):pending_lines.append(lineobj)self._data.extend(pending_lines)iflineandline[-1]=='\n':self._data.add(EmptyLine())ifexc:raiseexc
Attach a Trello Card
Add a tag
Your session has expired
You are no longer logged in. Please log in and try your request again.
Filter RSS Feed
This RSS feed URL allows you to see the contents of your current filter using any feed reader.
This link includes a special authentication token. If you share the URL with anyone else, they can see this RSS feed's activity. You can disable these tokens when needed.
Your current filter is unsaved; changing it won't affect this RSS feed.