El primer método parecía la forma más fácil y segura.
Pero, después de ver el código fuente de ConfigParser, crea un dict incorporado vacío, y luego copia todos los valores del "segundo parámetro" uno por uno. Eso significa que no usará el tipo OrderedDict. Un trabajo fácil puede ser sobrecargar la clase CreateParser.
class OrderedRawConfigParser(ConfigParser.RawConfigParser):
def __init__(self, defaults=None):
self._defaults = type(defaults)() ## will be correct with all type of dict.
self._sections = type(defaults)()
if defaults:
for key, value in defaults.items():
self._defaults[self.optionxform(key)] = value
Deja solo un defecto abierto ... es decir, en ConfigParser.items(). odict no admite update
y comparison
con valores normales.
Solución (sobrecargar esta función también):
def items(self, section):
try:
d2 = self._sections[section]
except KeyError:
if section != DEFAULTSECT:
raise NoSectionError(section)
d2 = type(self._section)() ## Originally: d2 = {}
d = self._defaults.copy()
d.update(d2) ## No more unsupported dict-odict incompatibility here.
if "__name__" in d:
del d["__name__"]
return d.items()
Otra solución al problema de artículos es modificar la función odict.OrderedDict.update
- tal vez es más fácil que éste, pero lo dejo a ti.
PD: Implementé esta solución, pero no funciona. Si descubro que ConfigParser sigue mezclando el orden de las entradas, lo reportaré.
PS2: Resuelto. La función de lector de ConfigParser es bastante idiota. De todos modos, sólo una línea tuvo que ser cambiado - y algunos otros por una sobrecarga en un archivo externo:
def _read(self, fp, fpname):
cursect = None
optname = None
lineno = 0
e = None
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:
cursect[optname] = "%s\n%s" % (cursect[optname], value)
else:
mo = self.SECTCRE.match(line)
if mo:
sectname = mo.group('header')
if sectname in self._sections:
cursect = self._sections[sectname]
## Add ConfigParser for external overloading
elif sectname == ConfigParser.DEFAULTSECT:
cursect = self._defaults
else:
## The tiny single modification needed
cursect = type(self._sections)() ## cursect = {'__name__':sectname}
cursect['__name__'] = sectname
self._sections[sectname] = cursect
optname = None
elif cursect is None:
raise ConfigParser.MissingSectionHeaderError(fpname, lineno, line)
## Add ConfigParser for external overloading.
else:
mo = self.OPTCRE.match(line)
if mo:
optname, vi, optval = mo.group('option', 'vi', 'value')
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 = ''
optname = self.optionxform(optname.rstrip())
cursect[optname] = optval
else:
if not e:
e = ConfigParser.ParsingError(fpname)
## Add ConfigParser for external overloading
e.append(lineno, repr(line))
if e:
raise e
Confía en mí, no me escribió esta cosa. Lo copié y pegué por completo desde ConfigParser.py
¿En general, qué hacer?
- Descargar odict.py de uno de los enlaces sugerido previamente
- importarlo.
- Copie y pegue estos códigos en sus utilidades favoritas.py (que creará la clase
OrderedRawConfigParser
para usted)
cfg = utils.OrderedRawConfigParser(odict.OrderedDict())
- use cfg como siempre. se mantendrá ordenado.
- Siéntate, fuma una havanna, relájate.
PS3: El problema que he resuelto aquí es solo en Python 2.5. En 2.6 ya hay una solución para eso. Crearon un segundo parámetro personalizado en la función __init__
, que es un dict_type personalizado.
Así que esta solución sólo se necesita el 2,5
favor ver mi respuesta para un cuarto, trabajando, solución. –