2012-02-02 13 views
7

tengo fichero de configuración,Python Config analizador comentario lea junto con el valor

[local] 
    variable1 : val1 ;#comment1 
    variable2 : val2 ;#comment2 

código como este sólo lee el valor de la clave:

class Config(object): 
    def __init__(self): 
     self.config = ConfigParser.ConfigParser() 
     self.config.read('config.py') 

    def get_path(self): 
     return self.config.get('local', 'variable1') 

if __name__ == '__main__': 
    c = Config() 
    print c.get_path() 

pero también quiero leer el comentario presentes a lo largo con el valor, cualquier sugerencia a este respecto será muy útil.

+0

actualizó la pregunta, se trataba de un error tipográfico, los comentarios en el archivo se está utilizando; personaje seguido de # personaje – avasal

Respuesta

2

Sus únicas soluciones es escribir otro ConfigParser anulando el método _read(). En su ConfigParser, debe eliminar todas las verificaciones sobre la eliminación de comentarios. Esta es una solución peligrosa, pero debería funcionar.

class ValuesWithCommentsConfigParser(ConfigParser.ConfigParser): 

    def _read(self, fp, fpname): 
     from ConfigParser import DEFAULTSECT, MissingSectionHeaderError, ParsingError 

     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 
      # comment or blank line? 
      if line.strip() == '' or line[0] in '#;': 
       continue 
      if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR": 
       # no leading whitespace 
       continue 
       # continuation line? 
      if line[0].isspace() and cursect is not None and optname: 
       value = line.strip() 
       if value: 
        cursect[optname].append(value) 
      # a section header or option header? 
      else: 
       # is it a section header? 
       mo = self.SECTCRE.match(line) 
       if mo: 
        sectname = mo.group('header') 
        if sectname in self._sections: 
         cursect = self._sections[sectname] 
        elif sectname == DEFAULTSECT: 
         cursect = self._defaults 
        else: 
         cursect = self._dict() 
         cursect['__name__'] = sectname 
         self._sections[sectname] = cursect 
         # So sections can't start with a continuation line 
        optname = None 
       # no section header in the file? 
       elif cursect is None: 
        raise MissingSectionHeaderError(fpname, lineno, line) 
       # an option line? 
       else: 
        mo = self._optcre.match(line) 
        if mo: 
         optname, vi, optval = mo.group('option', 'vi', 'value') 
         optname = self.optionxform(optname.rstrip()) 
         # This check is fine because the OPTCRE cannot 
         # match if it would set optval to None 
         if optval is not None: 
          optval = optval.strip() 
          # allow empty values 
          if optval == '""': 
           optval = '' 
          cursect[optname] = [optval] 
         else: 
          # valueless option handling 
          cursect[optname] = optval 
        else: 
         # a non-fatal parsing error occurred. set up the 
         # exception but keep going. the exception will be 
         # raised at the end of the file and will contain a 
         # list of all bogus lines 
         if not e: 
          e = ParsingError(fpname) 
         e.append(lineno, repr(line)) 
      # if any parsing errors occurred, raise an exception 
     if e: 
      raise e 

     # join the multi-line values collected while reading 
     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): 
        options[name] = '\n'.join(val) 

En el ValuesWithCommentsConfigParser i fijo algunas importaciones y suprimen las secciones apropiadas del código.

Usando el mismo config.ini de mi previous answer, puedo probar que el código anterior es correcto.

config = ValuesWithCommentsConfigParser() 
config.read('config.ini') 
assert config.get('local', 'variable1') == 'value1 ; comment1' 
assert config.get('local', 'variable2') == 'value2 # comment2' 
+1

Gracias funciona como un encanto ... para mi caso :) – avasal

8

Por desgracia, esto no se realiza fácilmente en el caso general. Los comentarios son supuesto que el analizador debe ignorar.

En su caso específico, es fácil, porque # solo sirve como un carácter de comentario si comienza una línea. Entonces, el valor de variable1 será "val1 #comment1". Supongo que utilice algo como esto, sólo es menos frágil:

val1_line = c.get('local', 'var1') 
val1, comment = val1_line.split(' #') 

Si se necesita el valor de un 'comentario', probablemente no es un comentario apropiado? Considere agregar claves explícitas para los 'comentarios', así:

[local] 
    var1: 108.5j 
    var1_comment: remember, the flux capacitor capacitance is imaginary! 
+0

Acepto - si el comentario es de interés, entonces realmente no debería ser un comentario. – pojo

+0

le gustó su respuesta así que +1, pero desafortunadamente, no puedo modificar el archivo de configuración :( – avasal

+0

Después de un poco de exploración, he actualizado la respuesta, tal vez sea más útil ahora. – 9000

2

Accordiing la documentación ConfigParser module, archivos

de configuración pueden incluir comentarios, con el prefijo caracteres específicos (# y;). Los comentarios pueden aparecer por sí solos en una línea vacía , o pueden ingresarse en líneas con valores o nombres de sección . En el último caso, deben ir precedidos por un carácter en blanco para ser reconocido como un comentario. (Para compatibilidad hacia atrás, solamente; pone en marcha un comentario en línea, mientras que # no lo hace.)

Si desea leer el "comentario" con el valor, se puede omitir el espacio en blanco antes del carácter ; o utilizar el #. Pero en este caso las cadenas comment1 y comment2 se vuelven parte del valor y ya no se consideran comentarios.

Un mejor enfoque sería el uso de un nombre de propiedad diferente, como variable1_comment, o para definir otra sección en la configuración dedicada a los comentarios:

[local] 
    variable1 = value1 
[comments] 
    variable1 = comment1 

La primera solución requiere que se genere una nueva clave usando otro (es decir, calcule variable1_comment desde variable1), el otro le permite usar la misma clave para diferentes secciones en el archivo de configuración.

A partir de Python 2.7.2, siempre es posible leer un comentario a lo largo de la línea si utiliza el carácter #. Como dicen los documentos, es por compatibilidad con versiones anteriores.El siguiente código debería funcionar sin problemas:

config = ConfigParser.ConfigParser() 
config.read('config.ini') 
assert config.get('local', 'variable1') == 'value1' 
assert config.get('local', 'variable2') == 'value2 # comment2' 

para la config.ini siguiente archivo:

[local] 
variable1 = value1 ; comment1 
variable2 = value2 # comment2 

Si se adopta esta solución, recuerde que debe analizar manualmente el resultado de get() de los valores y los comentarios.

+0

el archivo de configuración viene a mí como una entrada de otra fuente que no puedo controlar .. – avasal

+0

He hecho una prueba y he corregido mi respuesta – frm

+0

actualicé la pregunta, era un error tipográfico, los comentarios en el archivo están usando el carácter ';' – avasal

1

según los manuales: Líneas que comienzan con '#' o ';' se ignoran y se pueden usar para proporcionar comentarios.

por lo que el valor de variable1 es "val1 # comment1" .El comentario es parte del valor

puede comprobar su configuración si se pone un Introduzca su comentario antes de