парсинг файла .properties в Python - PullRequest
48 голосов
/ 12 мая 2010

Модуль ConfigParser вызывает исключение, если анализируется простой файл в стиле Java .properties, содержимое которого представляет собой пары ключ-значение (т.е. без INI заголовки разделов). Есть ли обходной путь?

Ответы [ 10 ]

74 голосов
/ 12 мая 2010

Скажем, у вас есть, например .:

$ cat my.props
first: primo
second: secondo
third: terzo

т.е. будет форматом .config, за исключением того, что в нем отсутствует начальное имя раздела. Тогда легко подделать заголовок раздела:

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()

использование:

cp = ConfigParser.SafeConfigParser()
cp.readfp(FakeSecHead(open('my.props')))
print cp.items('asection')

выход:

[('second', 'secondo'), ('third', 'terzo'), ('first', 'primo')]
38 голосов
/ 26 августа 2014

Я думал Комментарий MestreLion "read_string" был приятным и простым и заслуживал примера.

Для Python 3.2+ вы можете реализовать идею "фиктивного раздела" следующим образом:

with open(CONFIG_PATH, 'r') as f:
    config_string = '[dummy_section]\n' + f.read()
config = configparser.ConfigParser()
config.read_string(config_string)
32 голосов
/ 28 декабря 2011

Мое решение - использовать StringIO и добавить простой фиктивный заголовок:

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')
18 голосов
/ 19 декабря 2011

Ответ Алекса Мартелли, приведенный выше, не работает для Python 3.2+: readfp() заменен на read_file(), и теперь он использует итератор вместо использования readline() метода.

Вот фрагмент, который использует тот же подход, но работает в 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'}
>>>
4 голосов
/ 02 июля 2018
with open('some.properties') as file:
    props = dict(line.strip().split('=', 1) for line in file)

Кредит Как создать словарь, содержащий пары ключ-значение из текстового файла

maxsplit=1 важно, если в значении есть знаки равенства (например, someUrl=https://some.site.com/endpoint?id=some-value&someotherkey=value)

4 голосов
/ 17 февраля 2015

YAY! другая версия

На основании этого ответа (при добавлении используется оператор dict, with и поддерживается символ %)

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

Использование

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

файл .properties, используемый в моем примере

name=mongo
connection-string=mongodb://...
password=my-password%1234

Редактировать 2015-11-06

Благодаря Нилу Лайме , который упомянул, что была проблема с символом %.

Причиной этого является ConfigParser, предназначенный для анализа .ini файлов. Символ % - это специальный синтаксис. чтобы использовать символ %, просто добавили замену % на %% в соответствии с синтаксисом .ini.

1 голос
/ 18 августа 2016

Этот ответ предлагает использовать itertools.chain в 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)
0 голосов
/ 12 февраля 2019
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 голосов
/ 23 октября 2017

Еще один ответ для python2.7, основанный на Ответ Алекса Мартелли

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:
    /1583072/parsing-faila-properties-v-python#1583074

    Example usage
    -------------
    >>> pp = PropertiesParser()
    >>> props = pp.parse('/home/kola/configfiles/dev/application.properties')
    >>> print props

    """

    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)
0 голосов
/ 08 сентября 2013
with open('mykeyvaluepairs.properties') as f:
    defaults = dict([line.split() for line in f])
config = configparser.ConfigParser(defaults)
config.add_section('dummy_section')

Теперь config.get('dummy_section', option) вернет 'option' из секции DEFAULT.

или

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)

В этом случае config.get('properties', option) не обращается к разделу по умолчанию.

...