解析配置文件、环境变量和命令行参数,获取一个选项集合

138
Python标准库有用于配置文件解析(configparser)、环境变量读取(os.environ)和命令行参数解析(argparse)的模块。我想编写一个程序,可以完成所有这些功能,并且还要:
  • 具有级联选项值

    • 默认选项值,被覆盖为
    • 配置文件选项,被覆盖为
    • 环境变量,被覆盖为
    • 命令行选项。
  • 允许在命令行上指定一个或多个配置文件位置,例如--config-file foo.conf,并读取该文件(替代或附加到通常的配置文件)。这仍然必须遵循上述级联规则。

  • 允许在单个位置定义选项以确定配置文件和命令行的解析行为。

  • 将解析的选项统一为单个选项值集合,供程序余下部分使用,而不必关心它们来自哪里。

显然,我需要的一切都在Python标准库中,但它们之间不能很好地协同工作。

如何在最小程度偏离Python标准库的情况下实现此目标?


9
我很喜欢这个问题。我考虑做这样的事情已经很久了……我很高兴“jterrace”在这里提供了赏金,足以推动我尝试类似的事情 :) - mgilson
6
非常好的问题!令人惊讶的是,这个问题很久以前就没有被一个流行的软件包(或标准库本身)解决。 - Zearin
12个回答

0
值得一提的是jsonargparse,它具有MIT许可证并且可以在PyPI上获得。它是argparse的扩展,支持从配置文件和环境变量加载。覆盖顺序与��题中要求的相同(实际上是其超集)。
请注意,jsonargparse是一个第三方库。问题中提到了“尽量不依赖于Python标准库”,这可能被解释为不需要安装额外的包。然而,很多人阅读这个问题很可能会接受使用一个更简单、更清晰的解决方案,即使用第三方库。
一个示例的main.py如下:
from jsonargparse import ArgumentParser

parser = ArgumentParser(
    default_config_files=["defaults.yaml"],
    env_prefix="APP",
    default_env=True,
)
parser.add_argument("--opt1", default="code1")
parser.add_argument("--opt2", default="code2")
parser.add_argument("--opt3", default="code3")
parser.add_argument("--opt4", default="code4")
args = parser.parse_args()
print(args.opt1, args.opt2, args.opt3, args.opt4)

拥有一个名为defaults.yaml的配置文件,其内容如下:
opt2: defaults2

然后是一个从命令行运行的示例:
$ export APP_OPT3=env3
$ python main.py --opt4 arg4
code1 defaults2 env3 arg4

-1

我开发的confect库正是为了满足您大部分需求。

  • 它可以通过给定的文件路径或模块名多次加载配置文件。
  • 它可以从带有给定前缀的环境变量中加载配置。
  • 它可以将命令行选项附加到一些click命令上

    (抱歉,它不是argparse,但click更好、更先进。 confect可能会在未来的版本中支持argparse)。

  • 最重要的是,confect加载的是Python配置文件,而不是JSON/YMAL/TOML/INI。就像IPython配置文件或DJANGO设置文件一样,Python配置文件更灵活、更易于维护。

更多信息,请查看项目存储库中的README.rst。请注意,它仅支持Python3.6及以上版本。

示例

附加命令行选项

import click
from proj_X.core import conf

@click.command()
@conf.click_options
def cli():
    click.echo(f'cache_expire = {conf.api.cache_expire}')

if __name__ == '__main__':
    cli()

它会自动创建一个包含所有属性和默认值声明的全面帮助信息。
$ python -m proj_X.cli --help
Usage: cli.py [OPTIONS]

Options:
  --api-cache_expire INTEGER  [default: 86400]
  --api-cache_prefix TEXT     [default: proj_X_cache]
  --api-url_base_path TEXT    [default: api/v2/]
  --db-db_name TEXT           [default: proj_x]
  --db-username TEXT          [default: proj_x_admin]
  --db-password TEXT          [default: your_password]
  --db-host TEXT              [default: 127.0.0.1]
  --help                      Show this message and exit.

加载环境变量

只需要一行代码即可加载环境变量

conf.load_envvars('proj_X')

抱歉,这不是argparse,但click更好且更先进。无论第三方库的优点如何,这都不是问题的答案。 - bignose

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接