Le fichier typique généré par ConfigParser ressemble à ceci:
[Section]
bar=foo
[Section 2]
bar2= baz
Maintenant, existe-t-il un moyen d’indexer des listes comme, par exemple:
[Section 3]
barList={
item1,
item2
}
Question associée: Clés uniques ConfigParser de Python par section
Rien ne vous empêche de compresser la liste dans une chaîne puis de la décompresser une fois que vous obtenez la chaîne de la configuration. Si vous le faisiez de cette façon, votre section de configuration ressemblerait à ceci:
[Section 3]
barList=item1,item2
Ce n'est pas joli mais c'est fonctionnel pour la plupart des listes simples.
Également un peu en retard, mais peut-être utile pour certains… .. J'utilise une combinaison de ConfigParser et JSON:
[Foo]
fibs: [1,1,2,3,5,8,13]
il suffit de le lire avec:
>>> json.loads(config.get("Foo","fibs"))
[1, 1, 2, 3, 5, 8, 13]
Vous pouvez même casser des lignes si votre liste est longue (merci @ peter-smit):
[Bar]
files_to_check = [
"/path/to/file1",
"/path/to/file2",
"/path/to/another file with space in the name"
]
Bien sûr, je pourrais simplement utiliser JSON, mais je trouve les fichiers de configuration beaucoup plus lisibles et la section [DEFAULT] très pratique.
Arriver en retard à cette soirée, mais j'ai récemment implémenté ceci avec une section dédiée dans un fichier de configuration pour une liste:
[paths]
path1 = /some/path/
path2 = /another/path/
...
et en utilisant config.items( "paths" )
pour obtenir une liste itérable d'items de chemin, comme ceci:
path_items = config.items( "paths" )
for key, path in path_items:
#do something with path
J'espère que cela aide d'autres personnes à googler cette question;)
Une chose que beaucoup de gens ignorent, c'est que les valeurs de configuration multilignes sont autorisées. Par exemple:
;test.ini
[hello]
barlist =
item1
item2
La valeur de config.get('hello','barlist')
sera désormais:
"\nitem1\nitem2"
Ce que vous pouvez facilement diviser avec la méthode splitlines (n'oubliez pas de filtrer les éléments vides).
Si nous cherchons un gros framework comme Pyramid, ils utilisent cette technique:
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
Moi-même, je pourrais peut-être prolonger ConfigParser s'il s'agit d'une chose courante pour vous:
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)]
Notez qu'il y a quelques points à surveiller lors de l'utilisation de cette technique
Si vous voulez littéralement passer une liste, vous pouvez utiliser:
ast.literal_eval()
Par exemple configuration:
[section]
option=["item1","item2","item3"]
Le code est:
import ConfigParser
import ast
my_list = ast.literal_eval(config.get("section", "option"))
print(type(my_list))
print(my_list)
sortie:
<type'list'>
["item1","item2","item3"]
J'ai atterri ici pour chercher à consommer cette ...
[global]
spys = [email protected], [email protected]
La réponse est de la diviser sur la virgule et de supprimer les espaces:
SPYS = [e.strip() for e in parser.get('global', 'spys').split(',')]
Pour obtenir un résultat de liste:
['[email protected]', '[email protected]']
Cela peut ne pas répondre exactement à la question du PO mais peut-être être la réponse simple que certaines personnes recherchent.
C'est ce que j'utilise pour les listes:
contenu du fichier de configuration:
[sect]
alist = a
b
c
code:
l = config.get('sect', 'alist').split('\n')
ça marche pour les ficelles
en cas de nombre
contenu de la configuration:
nlist = 1
2
3
code:
nl = config.get('sect', 'alist').split('\n')
l = [int(nl) for x in nl]
merci.
Aucune mention de la converters
KWARG POUR ConfigParser()
dans aucune de ces réponses n’a été décevante.
Selon la documentation, vous pouvez passer un dictionnaire à ConfigParser
qui ajoutera une méthode get
à la fois pour l’analyseur et les proxies de section. Donc pour une liste:
exemple.ini
[Germ]
germs: a,list,of,names, and,1,2, 3,numbers
Exemple de parseur:
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']
C'est mon choix personnel, car aucun sous-classement n'est nécessaire et je n'ai pas à compter sur un utilisateur final pour écrire parfaitement JSON ou une liste pouvant être interprétée par ast.literal_eval
.
Seuls les types primitifs sont pris en charge pour la sérialisation par l'analyseur de configuration. J'utiliserais JSON ou YAML pour ce genre d'exigence.
J'ai rencontré le même problème dans le passé. Si vous avez besoin de listes plus complexes, créez votre propre analyseur en héritant de ConfigParser. Ensuite, vous écraseriez la méthode get avec ceci:
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
Avec cette solution, vous pourrez également définir des dictionnaires dans votre fichier de configuration.
Mais fais attention! Ce n'est pas aussi sûr: cela signifie que n'importe qui pourrait exécuter du code dans votre fichier de configuration. Si la sécurité n’est pas un problème dans votre projet, j’envisagerais d’utiliser directement les classes python en tant que fichiers de configuration. Ce qui suit est beaucoup plus puissant et consommable qu'un fichier 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(',')
Alors maintenant, mon fichier config.cfg
, qui pourrait ressembler à ceci:
[server]
credentials=username:admin,password:$3<r3t
loggingdirs=/tmp/logs,~/logs,/var/lib/www/logs
timeoutwait=15
Peut être analysé en objets suffisamment fins pour mon petit projet.
>>> 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'
Ceci permet une analyse très rapide des configurations simples, vous perdez toute possibilité d'extraire des ints, des bools et d'autres types de sortie sans transformer l'objet renvoyé de Parser
, ni refaire le travail d'analyse effectué par la classe Parser ailleurs.
J'ai terminé une tâche similaire dans mon projet avec une section avec des clés sans valeurs:
import configparser
# allow_no_value param says that no value keys are ok
config = configparser.ConfigParser(allow_no_value=True)
# overwrite optionxform method for overriding default behaviour (I didn't want lowercased keys)
config.optionxform = lambda optionstr: optionstr
config.read('./app.config')
features = list(self.config['FEATURES'].keys())
print(features)
Sortie:
['BIOtag', 'TextPosition', 'IsNoun', 'IsNomn']
app.config:
[FEATURES]
BIOtag
TextPosition
IsNoun
IsNomn
json.loads
& ast.literal_eval
semble fonctionner, mais une simple liste dans config traite chaque caractère comme un octet renvoyant ainsi les crochets même ....
signification si config a fieldvalue = [1,2,3,4,5]
then config.read(*.cfg)
config['fieldValue'][0]
retournant [
à la place de 1