web-dev-qa-db-fra.com

analyse du fichier .properties en Python

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?

44
Tshepang

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')]
73
Alex Martelli

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)
32
CoupleWavyLines

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')
31
tauran

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'}
>>>
18
Oscar de Groot
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)

4
user9192156

YAY! une autre version

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

Edit 2015-11-06

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.

3
Jossef Harush

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)
1
Christian Long
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'))
0
Andy Quiroz