Python 在插值中使用上一个配置文件中的值

Python 在插值中使用上一个配置文件中的值,python,configuration-files,string-interpolation,Python,Configuration Files,String Interpolation,我正在使用一个程序,它使用python的configparser.configparser来处理配置文件,作为构建东西的指令。它的设置是为了可以指定多个命令行文件参数,并且后面文件中的规范将覆盖前面文件中设置的内容 这意味着我可以在triple.ini文件中设置一个基本模型 [admin] basename = trivial_model [model basic] data = data.tsv 并使用更复杂的模型扩展它extension.ini [admin] basename = tri

我正在使用一个程序,它使用python的
configparser.configparser
来处理配置文件,作为构建东西的指令。它的设置是为了可以指定多个命令行文件参数,并且后面文件中的规范将覆盖前面文件中设置的内容

这意味着我可以在
triple.ini
文件中设置一个基本模型

[admin]
basename = trivial_model
[model basic]
data = data.tsv
并使用更复杂的模型扩展它
extension.ini

[admin]
basename = trivial_model_extended
[model basic]
model = bsvs
program triality.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.interpolationdepthror:在值替换中超过了递归限制:“admin”部分中的选项“basename”包含一个插值键,它不能在10个步骤中替换。原始值:“(基本名称)s_扩展”

是否有一种简单、内置或优雅的方法来支持像这样的增量规范,或者通过更改当前的实现(这似乎归结为

parser.add_argument(
    "config",
    nargs="+")

args = parser.parse_args()
c = configparser.ConfigParser()
for conf in args.config:
    c.read(conf)
)或者通过一些巧妙的
[默认值]
节或配置文件中的值(或两者,如果需要)?

一些注释:

  • 不能像上面那样递归
    basename
    定义。我的方法是在
    [DEFAULT]
    部分中添加除
    basename
    以外的内容,例如,triple.ini可能如下所示:

    [DEFAULT]
    basename_default = default from trivial.ini
    
    [admin]
    basename = trivial_model
    
    [model basic]
    data = data.tsv
    
    [admin]
    basename = %(basename_default)s and more
    
  • 请注意,
    [DEFAULT]
    部分需要全部大写

  • 接下来,我可能有一个additiona.ini文件,我称之为more.ini,它如下所示:

    [DEFAULT]
    basename_default = default from trivial.ini
    
    [admin]
    basename = trivial_model
    
    [model basic]
    data = data.tsv
    
    [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')])
get
时间进行评估 以您正在寻找的方式进行递归插值是不可能的,因为插值只在调用
ConfigParser.get(section,option)
时起作用,而不是在读取配置文件时起作用。从
BasicInterpolation
的文档字符串:

[...]  All reference expansions are done late, on demand. [...]
我们如何解决这个问题?
ConfigParser
\u read
方法在读取之前会调用
self.\u插值,但到那时它已经覆盖了
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.\u read
,该方法包含大部分解析魔法,以及
ConfigParser.\u join\u multiline\u values
,该方法当前包含对
self.\u interpolation.before\u read
的调用。(对我来说,这是一个愚蠢的地方。)