Le module ConfigParser
déclenche une exception si l'on analyse un simple fichier de style Java .properties
, dont le contenu est constitué de paires clé-valeur (i..e sans en-tête de section de style INI). Y at-il une solution de contournement?
Disons que vous avez, par exemple:
$ cat my.props
first: primo
second: secondo
third: terzo
c’est-à-dire un format .config
, sauf qu’il manque un nom de section en tête. 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')]
Je pensais que _ { le commentaire "read_string" de MestreLion } était gentil et simple et méritait un exemple.
Pour Python 3.2+, vous pouvez implémenter l'idée de "section factice" comme ceci:
with open(CONFIG_PATH, 'r') as f:
config_string = '[dummy_section]\n' + f.read()
config = configparser.ConfigParser()
config.read_string(config_string)
Ma solution consiste à utiliser StringIO
et à ajouter un en-tête factice simple:
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')
La réponse ci-dessus d'Alex Martelli ne fonctionne pas pour Python 3.2+: la fonction readfp()
a été remplacée par la fonction read_file()
; elle prend désormais 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'}
>>>
with open('some.properties') as file:
props = dict(line.strip().split('=', 1) for line in file)
Crédit à Comment créer un dictionnaire contenant des paires clé-valeur à partir d'un fichier texte
maxsplit=1
est important s'il y a des signes identiques dans la valeur (par exemple someUrl=https://some.site.com/endpoint?id=some-value&someotherkey=value
)
Basé sur cette réponse (l'ajout utilise une instruction dict
, with
et prend en charge 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'))
Usage
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 fichier .properties
utilisé dans mon exemple
name=mongo
connection-string=mongodb://...
password=my-password%1234
Merci à Neill Lima de mentionner qu’il y avait un problème avec le caractère %
.
La raison en est ConfigParser
conçu pour analyser les fichiers .ini
. Le caractère %
est une syntaxe spéciale. pour utiliser le caractère %
, il a simplement ajouté un remplacement à %
avec %%
conformément à la syntaxe .ini
.
Cette réponse suggère d'utiliser itertools.chain dans 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)
from pyjavaproperties import Properties
p = Properties()
p.load(open('test.properties'))
p.list()
print p
print p.items()
print p['name3']
p['name3'] = 'changed = value'
print p['name3']
p['new key'] = 'new value'
p.store(open('test2.properties','w'))