Skip to content

Instantly share code, notes, and snippets.

@cloudnull
Last active February 10, 2016 03:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cloudnull/0a2ca74cffd52bae488d to your computer and use it in GitHub Desktop.
Save cloudnull/0a2ca74cffd52bae488d to your computer and use it in GitHub Desktop.
Multi-key ConfigParse for both read and write
class MultiKeydDict(dict):
def __setitem__(self, key, value):
if key in self:
if isinstance(self[key], set):
items = self[key]
items.add(str(value))
super(MultiKeydDict, self).__setitem__(key, items)
else:
items = [str(value), str(self[key])]
super(MultiKeydDict, self).__setitem__(key, set(items))
else:
return dict.__setitem__(self, key, value)
class ConfigTemplateParser(ConfigParser.RawConfigParser):
def _write(self, fp, section, item, entry):
if section:
if (item is not None) or (self._optcre == self.OPTCRE):
fp.write(entry)
else:
fp.write(entry)
def _write_check(self, fp, key, value, section=False):
if isinstance(value, set):
for item in value:
item = str(item).replace('\n', '\n\t')
entry = "%s = %s\n" % (key, item)
self._write(fp, section, item, entry)
else:
if isinstance(value, list):
_value = [str(i.replace('\n', '\n\t')) for i in value]
entry = '%s = %s\n' % (key, ','.join(_value))
else:
entry = '%s = %s\n' % (key, str(value).replace('\n', '\n\t'))
self._write(fp, section, value, entry)
def write(self, fp):
if self._defaults:
fp.write("[%s]\n" % 'DEFAULT')
for key, value in self._defaults.items():
self._write_check(fp, key=key, value=value)
else:
fp.write("\n")
for section in self._sections:
fp.write("[%s]\n" % section)
for key, value in self._sections[section].items():
self._write_check(fp, key=key, value=value, section=True)
else:
fp.write("\n")
def _read(self, fp, fpname):
cursect = None # None, or a dictionary
optname = None
lineno = 0
e = None # None, or an exception
while True:
line = fp.readline()
if not line:
break
lineno = lineno + 1
if line.strip() == '' or line[0] in '#;':
continue
if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR":
continue
if line[0].isspace() and cursect is not None and optname:
value = line.strip()
if value:
if isinstance(cursect[optname], set):
_temp_item = list(cursect[optname])
del cursect[optname]
cursect[optname] = _temp_item
elif isinstance(cursect[optname], (str, unicode)):
_temp_item = [cursect[optname]]
del cursect[optname]
cursect[optname] = _temp_item
cursect[optname].append(value)
else:
mo = self.SECTCRE.match(line)
if mo:
sectname = mo.group('header')
if sectname in self._sections:
cursect = self._sections[sectname]
elif sectname == 'DEFAULT':
cursect = self._defaults
else:
cursect = self._dict()
cursect['__name__'] = sectname
self._sections[sectname] = cursect
optname = None
elif cursect is None:
raise MissingSectionHeaderError(fpname, lineno, line)
else:
mo = self._optcre.match(line)
if mo:
optname, vi, optval = mo.group('option', 'vi', 'value')
optname = self.optionxform(optname.rstrip())
if optval is not None:
if vi in ('=', ':') and ';' in optval:
pos = optval.find(';')
if pos != -1 and optval[pos-1].isspace():
optval = optval[:pos]
optval = optval.strip()
if optval == '""':
optval = ''
cursect[optname] = optval
else:
if not e:
e = ParsingError(fpname)
e.append(lineno, repr(line))
if e:
raise e
all_sections = [self._defaults]
all_sections.extend(self._sections.values())
for options in all_sections:
for name, val in options.items():
if isinstance(val, list):
_temp_item = '\n'.join(val)
del options[name]
options[name] = _temp_item
@cloudnull
Copy link
Author

Override using multi-key config type is done using sets

o = """                                          
things:
  - 1
  - 2
other: !!set
  ? a
  ? b
"""

yaml.load(o)
{'other': {'a', 'b'}, 'things': [1, 2]}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment