Domanda

Il tipico file generato da ConfigParser è simile a:

[Section]
bar=foo
[Section 2]
bar2= baz

Ora, c'è un modo per indicizzare elenchi come, ad esempio:

[Section 3]
barList={
    item1,
    item2
}

Domanda correlata: Python & # 8217; s ConfigParser chiavi uniche per sezione

È stato utile?

Soluzione

Non c'è nulla che ti impedisca di comprimere l'elenco in una stringa delimitata e quindi scompattarlo una volta ottenuta la stringa dalla configurazione. Se lo facessi in questo modo, la tua sezione di configurazione sarebbe:

[Section 3]
barList=item1,item2

Non è carino ma è funzionale per la maggior parte degli elenchi semplici.

Altri suggerimenti

Anche un po 'in ritardo, ma forse utile per alcuni. Sto usando una combinazione di ConfigParser e JSON:

[Foo]
fibs: [1,1,2,3,5,8,13]

basta leggerlo con:

>>> json.loads(config.get("Foo","fibs"))
[1, 1, 2, 3, 5, 8, 13]

Puoi anche spezzare le righe se la tua lista è lunga (grazie @ peter-smit):

[Bar]
files_to_check = [
     "/path/to/file1",
     "/path/to/file2",
     "/path/to/another file with space in the name"
     ]

Ovviamente potrei semplicemente usare JSON, ma trovo i file di configurazione molto più leggibili e la sezione [DEFAULT] molto utile.

Arrivo in ritardo a questa festa, ma di recente l'ho implementato con una sezione dedicata in un file di configurazione per un elenco:

[paths]
path1           = /some/path/
path2           = /another/path/
...

e utilizzando config.items (" percorsi ") per ottenere un elenco iterabile di elementi del percorso, in questo modo:

path_items = config.items( "paths" )
for key, path in path_items:
    #do something with path

Spero che questo aiuti altre persone a cercare su Google questa domanda;)

Una cosa che molte persone non sanno è che sono ammessi valori di configurazione multilinea. Ad esempio:

;test.ini
[hello]
barlist = 
    item1
    item2

Il valore di config.get ('hello', 'barlist') sarà ora:

"\nitem1\nitem2"

Che puoi facilmente dividere con il metodo splitlines (non dimenticare di filtrare gli oggetti vuoti).

Se guardiamo a un grande framework come Pyramid stanno usando questa tecnica:

def aslist_cronly(value):
    if isinstance(value, string_types):
        value = filter(None, [x.strip() for x in value.splitlines()])
    return list(value)

def aslist(value, flatten=True):
    """ Return a list of strings, separating the input based on newlines
    and, if flatten=True (the default), also split on spaces within
    each line."""
    values = aslist_cronly(value)
    if not flatten:
        return values
    result = []
    for value in values:
        subvalues = value.split()
        result.extend(subvalues)
    return result

Fonte

Io stesso, forse estenderei ConfigParser se questa è una cosa comune per te:

class MyConfigParser(ConfigParser):
    def getlist(self,section,option):
        value = self.get(section,option)
        return list(filter(None, (x.strip() for x in value.splitlines())))

    def getlistint(self,section,option):
        return [int(x) for x in self.getlist(section,option)]

Nota che ci sono alcune cose a cui prestare attenzione quando usi questa tecnica

  1. Le nuove linee che sono elementi dovrebbero iniziare con uno spazio bianco (ad esempio uno spazio o una scheda)
  2. Tutte le righe seguenti che iniziano con uno spazio bianco sono considerate parte dell'elemento precedente. Anche se ha un segno = o se inizia con un; seguendo lo spazio bianco.

Se vuoi letteralmente passare un elenco, puoi usare:

ast.literal_eval()

Ad esempio configurazione:

[section]
option=["item1","item2","item3"]

Il codice è:

import ConfigParser
import ast

my_list = ast.literal_eval(config.get("section", "option"))
print(type(my_list))
print(my_list)

uscita:

<type'list'>
["item1","item2","item3"]

Sono atterrato qui cercando di consumare questo ...

[global]
spys = richard.sorge@cccp.gov, mata.hari@deutschland.gov

La risposta è dividerlo sulla virgola e rimuovere gli spazi:

SPYS = [e.strip() for e in parser.get('global', 'spys').split(',')]

Per ottenere un risultato dell'elenco:

['richard.sorge@cccp.gov', 'mata.hari@deutschland.gov']

Potrebbe non rispondere esattamente alla domanda del PO ma potrebbe essere la risposta semplice che alcune persone stanno cercando.

Nessuna menzione dei convertitori kwarg per ConfigParser () in una di queste risposte è stato piuttosto deludente.

Secondo la documentazione è possibile passare un dizionario a ConfigParser che aggiungerà un metodo get sia per i parser che per i proxy di sezione. Quindi per un elenco:

example.ini

[Germ]
germs: a,list,of,names, and,1,2, 3,numbers

Esempio di parser:

cp = ConfigParser(converters={'list': lambda x: [i.strip() for i in x.split(',')]})
cp.read('example.ini')
cp.getlist('Germ', 'germs')
['a', 'list', 'of', 'names', 'and', '1', '2', '3', 'numbers']
cp['Germ'].getlist('germs')
['a', 'list', 'of', 'names', 'and', '1', '2', '3', 'numbers']

Questo è il mio preferito in quanto non è necessaria alcuna sottoclasse e non devo fare affidamento su un utente finale per scrivere perfettamente JSON o un elenco che può essere interpretato da ast.literal_eval .

Questo è quello che uso per le liste:

contenuto del file di configurazione:

[sect]
alist = a
        b
        c

codice:

l = config.get('sect', 'alist').split('\n')

funziona per le stringhe

in caso di numeri

config content:

nlist = 1
        2
        3

codice:

nl = config.get('sect', 'alist').split('\n')
l = [int(nl) for x in nl]

Grazie.

Solo i tipi primitivi sono supportati per la serializzazione dal parser di configurazione. Vorrei utilizzare JSON o YAML per quel tipo di requisito.

Ho avuto lo stesso problema in passato. Se hai bisogno di elenchi più complessi, considera la possibilità di creare il tuo parser ereditando da ConfigParser. Quindi sovrascriveresti il ??metodo get con quello:

    def get(self, section, option):
    """ Get a parameter
    if the returning value is a list, convert string value to a python list"""
    value = SafeConfigParser.get(self, section, option)
    if (value[0] == "[") and (value[-1] == "]"):
        return eval(value)
    else:
        return value

Con questa soluzione sarai anche in grado di definire dizionari nel tuo file di configurazione.

Ma stai attento! Questo non è così sicuro: questo significa che chiunque potrebbe eseguire il codice attraverso il tuo file di configurazione. Se la sicurezza non è un problema nel tuo progetto, prenderei in considerazione l'utilizzo diretto delle classi Python come file di configurazione. Quanto segue è molto più potente e sacrificabile di un file ConfigParser:

class Section
    bar = foo
class Section2
    bar2 = baz
class Section3
    barList=[ item1, item2 ]
import ConfigParser
import os

class Parser(object):
    """attributes may need additional manipulation"""
    def __init__(self, section):
        """section to retun all options on, formatted as an object
        transforms all comma-delimited options to lists
        comma-delimited lists with colons are transformed to dicts
        dicts will have values expressed as lists, no matter the length
        """
        c = ConfigParser.RawConfigParser()
        c.read(os.path.join(os.path.dirname(__file__), 'config.cfg'))

        self.section_name = section

        self.__dict__.update({k:v for k, v in c.items(section)})

        #transform all ',' into lists, all ':' into dicts
        for key, value in self.__dict__.items():
            if value.find(':') > 0:
                #dict
                vals = value.split(',')
                dicts = [{k:v} for k, v in [d.split(':') for d in vals]]
                merged = {}
                for d in dicts:
                    for k, v in d.items():
                        merged.setdefault(k, []).append(v)
                self.__dict__[key] = merged
            elif value.find(',') > 0:
                #list
                self.__dict__[key] = value.split(',')

Quindi ora il mio file config.cfg , che potrebbe apparire così:

[server]
credentials=username:admin,password:$3<r3t
loggingdirs=/tmp/logs,~/logs,/var/lib/www/logs
timeoutwait=15

Può essere analizzato in oggetti a grana fine per il mio piccolo progetto.

>>> import config
>>> my_server = config.Parser('server')
>>> my_server.credentials
{'username': ['admin'], 'password', ['$3<r3t']}
>>> my_server.loggingdirs:
['/tmp/logs', '~/logs', '/var/lib/www/logs']
>>> my_server.timeoutwait
'15'

Questo è per l'analisi molto rapida di configurazioni semplici, perdi tutta la capacità di recuperare ints, bool e altri tipi di output senza trasformare l'oggetto restituito da Parser o ripetere l'esecuzione dell'analisi lavoro svolto dalla classe Parser altrove.

json.loads & amp; ast.literal_eval sembra funzionare ma un semplice elenco all'interno di config tratta ogni carattere come byte in modo da restituire anche la parentesi quadra ....

che significa se config ha fieldvalue = [1,2,3,4,5]

quindi config.read (*. cfg) config ['fieldValue'] [0] restituendo [ al posto di 1

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top