#!/usr/bin/env python # -*- coding: utf-8 -*- """\ bug_configparser.py - configparser.ConfigParser.clean and .update ====== ==================== usage: bug_configparser.py ====== ==================== """ import sys try: from StringIO import StringIO except ImportError: from io import StringIO try: import configparser except ImportError: import ConfigParser as configparser def configparser_clear_compat(self): # ||:mth:|| """Python 3 compatible clear method.""" raise ValueError('Cannot remove the default section.') def configparser_update_compat(self, other=None, **kwds): # ||:mth:|| """Python 3 compatible update method.""" if other is None: other = () if hasattr(other, "items"): for key, value in other.items(): if key == 'DEFAULT': self.defaults().update(value) else: self._sections[key] = value elif hasattr(other, "keys"): for key in other.keys(): if key == 'DEFAULT': self.defaults().update(other[key]) else: self._sections[key] = other[key] else: for key, value in other: if key == 'DEFAULT': self.defaults().update(value) else: self._sections[key] = value for key, value in kwds.items(): if key == 'DEFAULT': self.defaults().update(value) else: self._sections[key] = value def configparser_clear(self): # ||:mth:|| """Python 3 makes this a purely non-sensical thing: >>> cfg = configparser.ConfigParser() >>> if not hasattr(configparser.ConfigParser, 'clear'): ... configparser.ConfigParser.clear = configparser_clear_compat >>> cfg.clear() #doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: Cannot remove the default section. This implementation deletes all sections except DEFAULT. Which is more like what is expected. >>> cfg = ConfigParser() >>> cfg.update({'DEFAULT': {'dkey': 'dval'}, 'section': {'skey': 'sval'}}) >>> state = StringIO() >>> cfg.write(state) >>> ign = sys.stdout.write(state.getvalue()) [DEFAULT] dkey = dval [section] skey = sval >>> cfg.clear() >>> state = StringIO() >>> cfg.write(state) >>> ign = sys.stdout.write(state.getvalue()) [DEFAULT] dkey = dval """ for section in self.sections(): del(self[section]) def configparser_update(self, other=None, **kwds): # ||:mth:|| """Python 3 implementation is counter-intuitive. It overwrites all sections except DEFAULT instead of updating them. >>> cfg = configparser.ConfigParser() >>> if not hasattr(configparser.ConfigParser, 'update'): ... configparser.ConfigParser.update = configparser_update_compat >>> cfg.update({'DEFAULT': {'dkey': 'dval'}, 'section': {'skey': 'sval'}}) >>> cfg.update({'DEFAULT': {'dkey1': 'dval1'}, 'section': {'skey1': 'sval1'}}) >>> cfg.update((('section', {'skey2': 'sval2'}), )) >>> cfg.update(section={'skey2': 'sval2'}) >>> state = StringIO() >>> cfg.write(state) >>> ign = sys.stdout.write(state.getvalue()) [DEFAULT] dkey = dval dkey1 = dval1 [section] skey2 = sval2 Since :meth:`read_dict` almost behaves like :meth:`update` should, it can simply be called from :meth:`update`. >>> cfg = ConfigParser() >>> cfg.update({'DEFAULT': {'dkey': 'dval'}, 'section': {'skey': 'sval'}}) >>> cfg.update({'DEFAULT': {'dkey1': 'dval1'}, 'section': {'skey1': 'sval1'}}) >>> cfg.update((('section', {'skey2': 'sval2'}), )) >>> cfg.update(section={'skey2': 'sval2'}) >>> state = StringIO() >>> cfg.write(state) >>> ign = sys.stdout.write(state.getvalue()) [DEFAULT] dkey = dval dkey1 = dval1 [section] skey = sval skey1 = sval1 skey2 = sval2 The reason can be found in _abcoll.py:: def update(*args, **kwds): ... if isinstance(other, Mapping): for key in other: self[key] = other[key] elif hasattr(other, "keys"): for key in other.keys(): self[key] = other[key] else: for key, value in other: self[key] = value for key, value in kwds.items(): self[key] = value """ if other is None: other = () for dict_ in configparser._default_dict(other), kwds: self.read_dict(dict_) try: configparser.ConfigParser()['section']['key'] = 'value' except KeyError: # Python 3.x class ConfigParser(configparser.ConfigParser): # ||:cls:|| # clear of MutableMapping is non-sensical in config context. clear = configparser_clear # update of MutableMapping is counter-intuitive. update = configparser_update except AttributeError: # Python 2.x class ConfigParser(configparser.ConfigParser): # ||:cls:|| clear = configparser_clear update = configparser_update def __delitem__(self, key): # |:mth:| del(self._sections[key]) def read_dict(self, dict_, source=''): # |:mth:| """ """ for sname, section in dict_.items(): sname = unicode(sname) if sname == 'DEFAULT': defaults = self.defaults() for key, value in section.items(): defaults[self.optionxform(key)] = value else: if not self.has_section(sname): self.add_section(sname) for key, value in section.items(): # if issequence(value): # value = '\n'.join([str(v) for v in value]) # else: # value = str(value) self.set(sname, key, unicode(str(value))) import doctest doctest.testmod() # (progn (forward-line 1) (snip-insert "py.t.ide" t t "py") (insert "\n")) # # :ide-menu: Emacs IDE Main Menu - Buffer @BUFFER@ # . M-x `eIDE-menu' (eIDE-menu "z") # :ide: COMPILE: Run with python3 w/o args # . (progn (save-buffer) (compile (concat "python3 ./" (file-name-nondirectory (buffer-file-name)) " "))) # :ide: COMPILE: Run w/o args # . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " "))) # # Local Variables: # mode: python # truncate-lines: t # End: