2012-02-02 5 views
7

Ho file di configurazione,Python Config parser commento leggere insieme a valore

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

codice come questo legge solo valore della chiave:

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() 

ma voglio anche leggere il commento presente lungo con il valore, qualsiasi suggerimento a riguardo sarà molto utile.

+0

aggiornato la domanda, si trattava di un errore di battitura, i messaggi nel file è in uso; carattere seguito da # carattere – avasal

risposta

2

Le uniche soluzioni è quello di scrivere un altro ConfigParser che ignora il metodo _read(). Nel tuo ConfigParser dovresti eliminare tutti i controlli sulla rimozione dei commenti. Questa è una soluzione pericolosa , ma dovrebbe funzionare.

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) 

Nel ValuesWithCommentsConfigParser Ho sistemato alcune importazioni e cancellato le apposite sezioni di codice.

Utilizzando lo stesso config.ini dal mio previous answer, posso provare che il codice precedente è corretto.

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

Grazie funziona come un fascino ... per il mio caso :) – avasal

8

Ahimè, questo non è fatto facilmente nel caso generale. I commenti sono supposti da ignorare dal parser.

Nel caso specifico, è semplice, perché # funge solo da carattere di commento se inizia una riga. Quindi il valore di variabile1 sarà "val1 #comment1". Suppongo che si utilizza qualcosa di simile, solo meno fragile:

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

Se è necessario il valore di un 'commento', probabilmente non è un commento adeguato? Considerare l'aggiunta di chiavi esplicite per i 'commenti', in questo modo:

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

Sono d'accordo: se il commento è di interesse, allora non dovrebbe essere un commento. – pojo

+0

ha apprezzato la tua risposta in modo +1, ma sfortunatamente non riesco a modificare il file di configurazione :( – avasal

+0

Dopo un po 'di esplorazione, ho aggiornato la risposta, forse ora è più utile. – 9000

2

Accordiing alla documentazione ConfigParser module, file

di configurazione possono includere commenti, preceduti da specifici caratteri (# e;). I commenti possono apparire da soli in una riga vuota oppure possono essere immessi nelle righe contenenti i valori o nella sezione nomi. In quest'ultimo caso, devono essere preceduti da un carattere di spazio vuoto da riconoscere come commento. (Per compatibilità all'indietro, solo; inizia un commento in linea, mentre # non lo fa.)

Se vuoi leggere il "Commento" con il valore, è possibile omettere gli spazi prima del carattere ; o utilizzare il #. Ma in questo caso le stringhe comment1 e comment2 diventano parte del valore e non sono più considerate commenti.

Un approccio migliore sarebbe quella di utilizzare un nome di proprietà diversa, come ad esempio variable1_comment, oppure per definire un'altra sezione nella configurazione dedicata ai commenti:

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

La prima soluzione richiede di generare una nuova chiave utilizzando un altro (ad esempio, calcolare variable1_comment da variable1), l'altro consente di utilizzare lo stesso tasto di targeting sezioni diverse nel file di configurazione.

A partire da Python 2.7.2, è sempre possibile leggere un commento lungo la linea se si utilizza il carattere #. Come dicono i documenti, è per compatibilità con le versioni precedenti.Il seguente codice dovrebbe funzionare senza problemi:

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

per il config.ini seguente file:

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

Se si adotta questa soluzione, ricordate per analizzare manualmente il risultato di get() per i valori e commenti.

+0

il file di configurazione viene da me come input da un'altra fonte che non posso controllare .. – avasal

+0

Ho fatto un test e ho corretto la mia risposta – frm

+0

aggiornata la domanda, era un errore di battitura, commmenti nel file sta usando ';' carattere – avasal

1

secondo i manuali: Le righe che iniziano con "#" o ";" vengono ignorati e possono essere utilizzati per fornire commenti.

in modo che il valore della variabile1 è "val1 # comment1" .Il commento è parte del valore

è possibile controllare la configurazione se si mette un entrare prima il tuo commento