python3 - Listas en ConfigParser
python.ini files (10)
El archivo típico generado por ConfigParser se ve así:
[Section]
bar=foo
[Section 2]
bar2= baz
Ahora, ¿hay alguna manera de indexar listas como, por ejemplo:
[Section 3]
barList={
item1,
item2
}
Pregunta relacionada: claves únicas de ConfigParser de Python por sección
Aterricé aquí buscando consumir esto ...
[global]
spys = [email protected], [email protected]
La respuesta es dividirlo en la coma y quitar los espacios:
SPYS = [e.strip() for e in parser.get(''global'', ''spys'').split('','')]
Para obtener un resultado de la lista:
[''[email protected]'', ''[email protected]'']
Puede que no responda exactamente la pregunta del OP, pero podría ser la respuesta simple que algunas personas están buscando.
Enfrenté el mismo problema en el pasado. Si necesita listas más complejas, considere crear su propio analizador heredando ConfigParser. Luego sobrescribiría el método get con eso:
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 esta solución también podrá definir diccionarios en su archivo de configuración.
¡Pero ten cuidado! Esto no es tan seguro: esto significa que cualquiera podría ejecutar código a través de su archivo de configuración. Si la seguridad no es un problema en su proyecto, consideraría usar directamente clases de python como archivos de configuración. La siguiente es mucho más poderosa y prescindible que un archivo ConfigParser:
class Section
bar = foo
class Section2
bar2 = baz
class Section3
barList=[ item1, item2 ]
Esto es lo que uso para las listas:
contenido del archivo de configuración:
[sect]
alist = a
b
c
código:
l = config.get(''sect'', ''alist'').split(''/n'')
funciona para cuerdas
en caso de números
contenido de configuración:
nlist = 1
2
3
código:
nl = config.get(''sect'', ''alist'').split(''/n'')
l = [int(nl) for x in nl]
Gracias.
Llegué tarde a esta fiesta, pero recientemente implementé esto con una sección dedicada en un archivo de configuración para una lista:
[paths]
path1 = /some/path/
path2 = /another/path/
...
y el uso de config.items( "paths" )
para obtener una lista iterable de elementos de ruta, de esta manera:
path_items = config.items( "paths" )
for key, path in path_items:
#do something with path
Espero que esto ayude a otras personas a buscar en Google esta pregunta;)
No hay nada que le impida empacar la lista en una cadena delimitada y luego desempaquetarla una vez que obtiene la cadena de la configuración. Si lo hicieras de esta manera, tu sección de configuración se vería así:
[Section 3]
barList=item1,item2
No es bonito, pero es funcional para la mayoría de las listas simples.
Si quieres pasar literalmente en una lista, puedes usar:
ast.literal_eval()
Por ejemplo configuración:
[section]
option=["item1","item2","item3"]
El código es:
import ConfigParser
import ast
my_list = ast.literal_eval(config.get("section", "option"))
print(type(my_list))
print(my_list)
salida:
<type''list''>
["item1","item2","item3"]
Solo los tipos primitivos son compatibles con la serialización por el analizador de configuración. Usaría JSON o YAML para ese tipo de requisito.
También un poco tarde, pero tal vez sea útil para algunos. Estoy usando una combinación de ConfigParser y JSON:
[Foo]
fibs: [1,1,2,3,5,8,13]
solo léelo con:
>>> json.loads(config.get("Foo","fibs"))
[1, 1, 2, 3, 5, 8, 13]
Incluso puedes romper líneas si tu lista es larga (gracias @ peter-smit):
[Bar]
files_to_check = [
"/path/to/file1",
"/path/to/file2",
"/path/to/another file with space in the name"
]
Por supuesto, podría usar JSON, pero los archivos de configuración son mucho más legibles y la sección [DEFAULT] muy útil.
Una cosa que mucha gente no sabe es que se permiten valores de configuración multilínea. Por ejemplo:
;test.ini
[hello]
barlist =
item1
item2
El valor de config.get(''hello'',''barlist'')
ahora será:
"/nitem1/nitem2"
Lo cual puedes dividir fácilmente con el método de las divisiones (no te olvides de filtrar elementos vacíos).
Si miramos a un gran marco como Pyramid están usando esta técnica:
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
Yo mismo, quizás extienda ConfigParser si esto es algo común para ti:
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)]
Tenga en cuenta que hay algunas cosas a tener en cuenta al usar esta técnica
- Las nuevas líneas que son elementos deben comenzar con espacios en blanco (por ejemplo, un espacio o una pestaña)
- Todas las líneas siguientes que comienzan con espacios en blanco se consideran parte del elemento anterior. También si tiene un signo = o si comienza con a; siguiendo el espacio en blanco.
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('','')
Así que ahora mi archivo config.cfg
, que podría verse así:
[server]
credentials=username:admin,password:$3<r3t
loggingdirs=/tmp/logs,~/logs,/var/lib/www/logs
timeoutwait=15
Se puede analizar en objetos de grano fino para mi pequeño proyecto.
>>> 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''
Esto es para un análisis muy rápido de configuraciones simples, pierde toda la capacidad de obtener entradas, boles y otros tipos de resultados sin transformar el objeto devuelto desde el Parser
, o volver a realizar el trabajo de análisis realizado por la clase Analizador en otro lugar.