Модуль ConfigParser
создает исключение, если вы разбираете простой файл .properties
в стиле Java, чей контент является парами ключ-значение (без заголовков раздела INI-стиля). Есть ли способ обхода?
Синтаксический анализ файла .properties в Python
Ответ 1
Мое решение - использовать 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')
Ответ 2
Скажите, что у вас есть, например:
$ 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')]
Ответ 3
Ответ Alex Martelli выше не работает для 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
Я думал, что комментарий 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)
Ответ 5
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
Благодаря Neill Lima упоминалось о проблеме с символом %
.
Причиной этого является ConfigParser
, предназначенное для анализа файлов .ini
. Символом %
является специальный синтаксис. для использования символа %
просто добавлена замена для %
с помощью %%
в соответствии с синтаксисом .ini
.
Ответ 6
Этот ответ предлагает использовать 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)
Ответ 7
Еще один ответ для python2.7 на основе ответ 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:
/questions/63238/parsing-properties-file-in-python/435186#435186
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)
Ответ 8
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)
вернет "вариант" из раздела 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)
не прибегает к разделу по умолчанию.