Разбор заводного файла в python
У меня есть отличный конфигурационный файл, к которому я тоже хочу добавить данные. Было бы проще собирать данные с использованием python, который я хочу добавить, но я не смог найти соответствующий модуль ConfigSlurper в python, и я не нашел простого способа сделать это с помощью ConfigParser или чего-либо еще. Кто-нибудь сделал что-то подобное, что имеет некоторые отзывы / советы по лучшему подходу?
2 ответа
Это было забавное упражнение.
from shlex import shlex
from ast import literal_eval
TRANSLATION = {
"true": True,
"false": False,
"null": None,
}
class ParseException(Exception):
def __init__(self, token, line):
self.token = token
self.line = line
def __str__(self):
return "ParseException at line %d: invalid token %s" % (self.line, self.token)
class GroovyConfigSlurper:
def __init__(self, source):
self.source = source
def parse(self):
lex = shlex(self.source)
lex.wordchars += "."
state = 1
context = []
result = dict()
while 1:
token = lex.get_token()
if not token:
return result
if state == 1:
if token == "}":
if len(context):
context.pop()
else:
raise ParseException(token, lex.lineno)
else:
name = token
state = 2
elif state == 2:
if token == "=":
state = 3
elif token == "{":
context.append(name)
state = 1
else:
raise ParseException(token, lex.lineno)
elif state == 3:
try:
value = TRANSLATION[token]
except KeyError:
value = literal_eval(token)
key = ".".join(context + [name]).split(".")
current = result
for i in xrange(0, len(key) - 1):
if key[i] not in current:
current[key[i]] = dict()
current = current[key[i]]
current[key[-1]] = value
state = 1
Затем вы можете сделать
with open("test.conf", "r") as f:
print GroovyConfigSlurper(f).parse()
# => {'setting': {'smtp': {'mail': {'host': 'smtp.myisp.com', 'auth': {'user': 'server'}}}}, 'grails': {'webflow': {'stateless': True}}, 'resources': {'URL': 'http://localhost:80/resources'}}
Ответ user240443Я мог бы также предложить две небольшие модификации, они были необходимы в нашем случае (анализ файлов конфигурации Nextflow на основе Groovy из базы кода Python):
- поддержка отрицательных чисел (т. е. монадического знака минус)
- поддержка однострочных комментариев в стиле Groovy (т.е. //)
Также добавлен простой служебный метод для записи JSON в файл и добавлена возможность передавать строковое имя файла вместо строкового объекта.
Обновленный код выглядит следующим образом:
from shlex import shlex
from ast import literal_eval
TRANSLATION = {
"true": True,
"false": False,
"null": None,
}
class ParseException(Exception):
def __init__(self, token, line):
self.token = token
self.line = line
def __str__(self):
return "ParseException at line %d: invalid token %s" % (self.line, self.token)
class GroovyConfigParser:
def __init__(self, source):
if isinstance(source, str):
self.source = open(source)
self.should_close_source = True
else:
self.source = source
self.should_close_source = False
def __del__(self):
if self.should_close_source and not self.source.closed:
self.source.close()
def parse(self):
lex = shlex(self.source)
lex.wordchars = lex.wordchars + ".-"
lex.commenters = "//"
state = 1
context = []
result = dict()
while True:
token = lex.get_token()
if not token:
return result
if state == 1:
if token == "}":
if len(context):
context.pop()
else:
raise ParseException(token, lex.lineno)
else:
name = token
state = 2
elif state == 2:
if token == "=":
state = 3
elif token == "{":
context.append(name)
state = 1
else:
raise ParseException(token, lex.lineno)
elif state == 3:
try:
value = TRANSLATION[token]
except KeyError:
value = literal_eval(token)
key = ".".join(context + [name]).split(".")
current = result
for i in range(len(key) - 1):
if key[i] not in current:
current[key[i]] = dict()
current = current[key[i]]
current[key[-1]] = value
state = 1
def write_as_json_file(self, json_file):
import json
with open(json_file, 'w') as file:
json.dump(self.parse(), file, indent=4)