2010-02-03 26 views
11

estoy usando ConfigParser para cargar los datos de un archivo de configuración de la siguiente manera:Cómo excluir DEFAULT de Python ConfigParser .items()?

test.conf:

[myfiles] 
fileone: %(datadir)s/somefile.foo 
filetwo: %(datadir)s/nudderfile.foo 

load.py:

import ConfigParser 

config = ConfigParser.ConfigParser({'datadir': '/tmp'}) 
config.read('test.conf') 

print config.items('myfiles') 
print config.get('myfiles', 'datadir') 

salida :

$ python load.py 
[('datadir', '/tmp'), ('filetwo', '/tmp/nudderfile.foo'), ('fileone', '/tmp/somefile.foo')] 
/tmp 

Me sorprende que los valores predeterminados para la sustitución de variables ('datadir', '/tmp') aparezcan como parte de. items() y .get() devuelve, como si fueran valores en el archivo de configuración. ¿Se espera este comportamiento? Cualquier solución alternativa, de modo que simplemente puedo iterar .items() sin obtener los valores de diccionario predeterminados allí, pero aún utilizando la interpolación mágica?

Referencia: http://docs.python.org/library/configparser.html

Gracias!

Actualización: Se ha señalado que este es el comportamiento esperado: los valores predeterminados son como cualquier otro par nombre/valor en el archivo de configuración. Del mismo modo, los pares de nombre/valor en el archivo de configuración también están disponibles para "interpolación mágica", por lo que si defino:

foo: bar 
zap: %(foo)snowl 

Voy a [... ('zap': 'barnowl')]

Eso es bastante limpio, pero todavía estoy preguntándome si puedo lograr lo que quiero lograr: iterar sobre los pares nombre/valor en mis archivos de configuración, con la interpolación de variables, sin los valores predeterminados.

Mi situación específica es esta: quise inicializar el objeto config con algo como {basedir: '/foo/bar'}, ya que las rutas absolutas a ciertos archivos varían según la instalación. Entonces necesito pasar ese objeto de configuración y tener varias otras clases iterar a través de los archivos. No quiero que todas las clases que lean la configuración tengan que saber que se inicializó con ciertos valores predeterminados y que debe ignorarlos, ya que no son archivos reales. es posible? ¿Alguna manera de ocultar los valores predeterminados de .item() y .get() pero todavía tienen interpolación? ¡Gracias!

+2

No puedo entender por qué este es el comportamiento por defecto, y mucho menos por qué no hay manera de apagarlo. –

Respuesta

1

Prueba esto:

config = ConfigParser.ConfigParser({'blahblahblah': 'blah'}) 
config.read('test.conf') 

La clave blahblahblah también aparecerá en items, no porque es una plantilla en el archivo .ini, pero debido a que ha especificado como un defecto. Así es como ConfigParser trata los valores predeterminados: si no puede encontrarlos en el archivo, asigna sus valores predeterminados.

Me parece que tiene una confusión simple de conceptos aquí.

+0

Gracias por la aclaración. De modo que el diccionario predeterminado se usa * tanto * para proporcionar valores predeterminados para ciertas claves, como para la "interpolación mágica" de variables incrustadas en el archivo de configuración. Además, las variables definidas en el archivo de configuración también se usan para "interpolación mágica", por lo que si defino: foo: bar zap:% (foo) Snowl voy a conseguir [... ('zap ':' barnowl ')] Eso es bastante bueno, pero aún me pregunto si puedo lograr lo que quiero lograr: iterar sobre los pares nombre/valor en mis archivos de configuración, con la interpolación de variables, sin los valores predeterminados. – user264902

4

En general, he encontrado que la clase configparser.Configparser es muy útil, pero también deficiente. Others have, too.

Sin embargo, puede tener subclases y se extendió, a veces bien, a veces no tan bien (= muy dependiente de la implementación)

Aquí hay una solución para su problema, a prueba en python3:

class ConfigParser(configparser.ConfigParser): 
    """Can get options() without defaults 
    """ 
    def options(self, section, no_defaults=False, **kwargs): 
     if no_defaults: 
      try: 
       return list(self._sections[section].keys()) 
      except KeyError: 
       raise NoSectionError(section) 
     else: 
      return super().options(section, **kwargs) 

Este es uno de los malos ejemplos, ya que está copiando parcialmente the source code de options(). Sería mejor si la clase base del configurador RawConfigParser proporcionara un captador interno de las opciones _options(self, section) que incorporaría el modelo de excepción, y un options() que haría uso de eso. Luego, en la creación de subclases podríamos reutilizar el _options().

Para Python 2, creo que el único cambio es la llamada super() al super(ConfigParser,self).

continuación, puede utilizar:

print config.options('myfiles', no_defaults=True) 

Y también utilizar esa lista para repetir.

+0

Está en el camino correcto, sin embargo, le preguntó sobre .items(), no .options(). Creo que esto lo llevará allí. –

+0

Entendí que su pregunta era cómo "iterar sobre los pares nombre/valor en mis archivos de configuración, con la interpolación de variables, sin los valores predeterminados". Y eso es lo que hace el código anterior. Para mí esa es una respuesta exacta. Desafortunadamente, como suele ser el caso, el póster de la pregunta no parece estar activo. De lo contrario, podríamos hacer que él decida si eso es aceptable para una respuesta o no. – cfi

+0

Sí, la pregunta se repite y necesita atención. Utiliza .items en el código y en la última oración. Él pregunta por los pares nombre/val, que es lo que hace .items. Opciones simplemente devuelve claves. Tu respuesta me ayudó a anular los elementos, así que gracias. –

2

¿No puedes filtrar los valores predeterminados?

ej .:

filtered_items = [x for x in config.items('myfiles') if x[0] not in config.defaults()]

Cuestiones relacionadas