parsing.fichier de propriétés en Python
le module ConfigParser
soulève une exception si l'on analyse un simple fichier de style Java .properties
dont le contenu est composé de paires de valeurs clés (I..e sans en-têtes de section de style INI). Est-il une solution de contournement?
9 réponses
dire que vous avez, par exemple:
$ cat my.props
first: primo
second: secondo
third: terzo
, c'est-à-dire un format .config
, sauf qu'il manque le nom d'une section principale. Ensuite, il est facile de simuler l'en-tête de section:
import ConfigParser
class FakeSecHead(object):
def __init__(self, fp):
self.fp = fp
self.sechead = '[asection]\n'
def readline(self):
if self.sechead:
try:
return self.sechead
finally:
self.sechead = None
else:
return self.fp.readline()
utilisation:
cp = ConfigParser.SafeConfigParser()
cp.readfp(FakeSecHead(open('my.props')))
print cp.items('asection')
sortie:
[('second', 'secondo'), ('third', 'terzo'), ('first', 'primo')]
ma solution est d'utiliser StringIO
et de préparer un simple en-tête de mannequin:
import StringIO
import os
config = StringIO.StringIO()
config.write('[dummysection]\n')
config.write(open('myrealconfig.ini').read())
config.seek(0, os.SEEK_SET)
import ConfigParser
cp = ConfigParser.ConfigParser()
cp.readfp(config)
somevalue = cp.getint('dummysection', 'somevalue')
j'ai pensé MestreLion "read_string" commentaire était beau et simple et mérite d'être un exemple.
pour Python 3.2+, vous pouvez implémenter l'idée de la" section mannequin "comme ceci:
with open(CONFIG_PATH, 'r') as f:
config_string = '[dummy_section]\n' + f.read()
config = configparser.ConfigParser()
config.read_string(config_string)
la réponse d'Alex Martelli ci-dessus ne fonctionne pas pour Python 3.2+: readfp()
a été remplacé par read_file()
, et il faut maintenant un itérateur au lieu d'utiliser la méthode readline()
.
voici un extrait qui utilise la même approche, mais fonctionne en Python 3.2+.
>>> import configparser
>>> def add_section_header(properties_file, header_name):
... # configparser.ConfigParser requires at least one section header in a properties file.
... # Our properties file doesn't have one, so add a header to it on the fly.
... yield '[{}]\n'.format(header_name)
... for line in properties_file:
... yield line
...
>>> file = open('my.props', encoding="utf_8")
>>> config = configparser.ConfigParser()
>>> config.read_file(add_section_header(file, 'asection'), source='my.props')
>>> config['asection']['first']
'primo'
>>> dict(config['asection'])
{'second': 'secondo', 'third': 'terzo', 'first': 'primo'}
>>>
YAY! une autre version
basé sur cette réponse (l'ajout utilise un énoncé dict
, with
, et supporte le caractère %
)
import ConfigParser
import StringIO
import os
def read_properties_file(file_path):
with open(file_path) as f:
config = StringIO.StringIO()
config.write('[dummy_section]\n')
config.write(f.read().replace('%', '%%'))
config.seek(0, os.SEEK_SET)
cp = ConfigParser.SafeConfigParser()
cp.readfp(config)
return dict(cp.items('dummy_section'))
Utilisation
props = read_properties_file('/tmp/database.properties')
# It will raise if `name` is not in the properties file
name = props['name']
# And if you deal with optional settings, use:
connection_string = props.get('connection-string')
password = props.get('password')
print name, connection_string, password
le .properties
fichier utilisé dans mon exemple
name=mongo
connection-string=mongodb://...
password=my-password%1234
Modifier 2015-11-06
grâce à Neill Lima mentionnant qu'il y avait un problème avec le caractère %
.
la raison en est ConfigParser
conçu pour analyser .ini
fichiers. Le caractère %
est une syntaxe spéciale. afin d'utiliser le caractère %
il a simplement ajouté un a remplacer pour %
par %%
selon la syntaxe .ini
.
with open('some.properties') as file:
props = dict(line.strip().split('=', 1) for line in file)
crédit à comment créer un dictionnaire qui contient des paires de valeurs clés à partir d'un fichier texte
maxsplit=1
est important s'il y a des signes égaux dans la valeur (par exemple someUrl=https://some.site.com/endpoint?id=some-value&someotherkey=value
)
Cette réponse suggère d'utiliser itertools.chaîne en Python 3.
from configparser import ConfigParser
from itertools import chain
parser = ConfigParser()
with open("foo.conf") as lines:
lines = chain(("[dummysection]",), lines) # This line does the trick.
parser.read_file(lines)
with open('mykeyvaluepairs.properties') as f:
defaults = dict([line.split() for line in f])
config = configparser.ConfigParser(defaults)
config.add_section('dummy_section')
maintenant config.get('dummy_section', option)
retournera "option" de la section par défaut.
ou:
with open('mykeyvaluepairs.properties') as f:
properties = dict([line.split() for line in f])
config = configparser.ConfigParser()
config.add_section('properties')
for prop, val in properties.items():
config.set('properties', prop, val)
dans ce cas config.get('properties', option)
n'a pas recours à la section par défaut.
encore une autre réponse pour python2.7 basé sur réponse D'Alex Martelli
import ConfigParser
class PropertiesParser(object):
"""Parse a java like properties file
Parser wrapping around ConfigParser allowing reading of java like
properties file. Based on stackoverflow example:
/q/parsing-properties-file-in-python-9858/"""
def __init__(self):
self.secheadname = 'fakeSectionHead'
self.sechead = '[' + self.secheadname + ']\n'
def readline(self):
if self.sechead:
try:
return self.sechead
finally:
self.sechead = None
else:
return self.fp.readline()
def parse(self, filepath):
self.fp = open(filepath)
cp = ConfigParser.SafeConfigParser()
cp.readfp(self)
self.fp.close()
return cp.items(self.secheadname)