我正在使用一个程序,该程序使用python' configparser.ConfigParser
来处理配置文件作为构建事物的指令。它的设置使得可以指定多个命令行文件参数,并且以后文件中的规范将覆盖先前文件中设置的内容。
这意味着我可以在trivial.ini
文件中设置基本模型
[admin]
basename = trivial_model
[model basic]
data = data.tsv
并使用更复杂的模型extension.ini
[admin]
basename = trivial_model_extended
[model basic]
model = bsvs
和program trivial.ini extension.ini
的行为就像它有
[admin]
basename = trivial_model_extended
[model basic]
data = data.tsv
model = bsvs
现在编写一个更加模块化的东西会很好,因为它能够组合多个这样的扩展而不需要过多地关注细节,给每个扩展名提供不同的基本文件名。我想也许这可能有用
[admin]
basename = %(basename)s_extended
[model basic]
model = bsvs
但是对于当前的实现,我得到了configparser.InterpolationDepthError: Recursion limit exceeded in value substitution: option 'basename' in section 'admin' contains an interpolation key which cannot be substituted in 10 steps. Raw value: '%(basename)s_extended'
。
是否有一种简单,内置或优雅的方式来启用此类增量规范,或者通过更改当前的实现(这似乎归结为
parser.add_argument(
"config",
nargs="+")
args = parser.parse_args()
c = configparser.ConfigParser()
for conf in args.config:
c.read(conf)
)或通过配置文件中的一些聪明的[default]
部分或值(或两者都必要)?
答案 0 :(得分:1)
一些评论:
您无法像上面那样递归basename
定义。我的方法是使用除[DEFAULT]
之外的其他内容basename
部分,例如,trivial.ini可能如下所示:
[DEFAULT]
basename_default = default from trivial.ini
[admin]
basename = trivial_model
[model basic]
data = data.tsv
请注意,[DEFAULT]
部分必须全部为大写
接下来,我可能会有一个附加的.ini文件,我称之为more.ini,它看起来像这样:
[admin]
basename = %(basename_default)s and more
此外,您不需要循环来读取配置文件:只需为read()
方法提供一个文件名列表,其中后一个文件将覆盖第一个文件。
把它放在一起:
parser = argparse.ArgumentParser()
parser.add_argument("config", nargs="+")
args = parser.parse_args('trivial.ini extension.ini more.ini'.split())
cfg = ConfigParser.ConfigParser()
cfg.read(args.config)
admin = 'admin'
model_basic = 'model basic'
print('basename:', cfg.get(admin, 'basename'))
print('defaults:', cfg.defaults())
输出:
basename: default from trivial.ini and more
defaults: OrderedDict([('basename_default', 'default from trivial.ini')])
答案 1 :(得分:0)
get
- 时间您正在寻找的方式的递归插值不可能是开箱即用的,因为插值仅在调用ConfigParser.get(section, option)
时起作用,而不是在读取配置文件时起作用。来自BasicInterpolation
的文档字符串:
[...] All reference expansions are done late, on demand. [...]
_read
的{{1}}方法会调用ConfigParser
,但到那时它已经覆盖了self._interpolation.before_read
对象的旧内部值,所以即使
ConfigParser
不会自行完成这个技巧。
您还必须重载class BasicReadInterpolation (configparser.BasicInterpolation):
def before_read(self, parser, section, option, value):
L = []
import pdb
pdb.set_trace()
interpolations = parser[parser.default_section]
interpolations.update(parser[section])
self._interpolate_some(
parser, option, L, value, section, interpolations, 1)
return ''.join(L)
,其中包含大部分解析魔法的方法,ConfigParser._read
,其中当前包含对ConfigParser._join_multiline_values
的调用。 (对我来说,这是一个愚蠢的地方。)