使用ConfigParser阅读原始部分

时间:2013-05-03 16:22:07

标签: python

我正在尝试使用ConfigParser模块以.ini格式处理完全几乎的文件。我想知道是否可以阅读“raw”部分,我只是在该部分中获得全文。如果不可能的话,我想知道是否有另一种“标准化”方法(带有内置模块)来处理这种类型的文件,可能包括shlex或类似的文件标准库。

我查看了ConfigParser的来源,看起来文本在任何地方都没有“原始”存储,所以我猜这是不可能的。

我认为我正在尝试解析的文件示例会有所帮助。我想要一个包含3个部分的文件:

[load]
files=a,b,c

[process]
<raw python code>

[export]
files=x,y,z

这个想法是加载/导出部分是ConfigParser模块假定的确切格式/行为。但是,process部分需要作为原始Python代码读取。用户将根据从load部分中的文件加载的数据,在此处放置需要执行多次的原始代码。

这不是最复杂的格式,因此我可以轻松编写自己的解析器。如果需要,我还可以将文件格式更改为.ini样式。我只想让用户能够拥有多个部分和一个“原始”Python代码部分。也许ConfigParser完全是错误的做法。

我不想为此编写自己的解析器,因为它看起来与现有格式非常相似。但是,如果它更适合,我可以轻松选择另一种“标准”格式。我只是不知道其他这样的格式。

1 个答案:

答案 0 :(得分:1)

好吧,如果您准备假设[process]总是在[export]之前,并且[export]将始终标记Python代码的结尾,那么您可以预先处理ini文件删除该部分,然后将其传递给ConfigParser,并使用类似的内容...

from ConfigParser import RawConfigParser
from StringIO import StringIO

START_PROCESS_TOKEN = '[process]'
END_PROCESS_TOKEN = '[export]'

def hacky_parse(stream):
    state = 0
    ini_io = StringIO()
    python_io = StringIO()
    for line in stream.readlines():
        if state == 0:
            if line.strip() == START_PROCESS_TOKEN:
                state = 1
                continue
            ini_io.write(line)
        elif state == 1:
            if line.strip() == END_PROCESS_TOKEN:
                ini_io.write(line)
                state = 2
                continue
            python_io.write(line)
        else:
            ini_io.write(line)

    ini_io.seek(0)
    python_io.seek(0)

    config_parser = RawConfigParser()
    config_parser.readfp(ini_io)

    python_code = python_io.getvalue()

    return config_parser, python_code


cfg = """
[load]
files=a,b,c

[process]
while 1:
    do_stuff()

[export]
files=x,y,z
"""

my_stream = StringIO(cfg)
config_parser, process_code = hacky_parse(my_stream)
print 'The value of "files" in section "load" is...'
print config_parser.get('load', 'files')
print
print 'The raw Python code is...'
print process_code

......产生......

The value of "files" in section "load" is...
a,b,c

The raw Python code is...
while 1:
    do_stuff()

......很明显,用my_stream代替真实的文件对象...

my_stream = open('config.ini', 'r')

<强>更新

嗯,你的代码有更多破坏的可能性,例如,如果行代码[load]出现在Python代码中。

我只是想到了另一种选择。如果您使配置文件看起来像RFC822消息......

Load-Files: a,b,c
Export-Files: x,y,z

# Python code starts here
while 1:
    do_stuff()

...你可以像这样解析它......

import email

cfg = \
"""Load-Files: a,b,c
Export-Files: x,y,z

# Python code starts here
while 1:
    do_stuff()
"""

msg = email.message_from_string(cfg)
print msg.items()
print
print msg.get_payload()

..产生......

[('Load-Files', 'a,b,c'), ('Export-Files', 'x,y,z')]

# Python code starts here
while 1:
    do_stuff()

我的意思是,您不必使用严格的RFC822格式,但将Python代码放在​​配置文件末尾的优点是,代码中的任何内容都不可能与您使用的格式冲突对于文件的其余部分。