跳过主要内容

argparse的替代品,允许通过配置文件和/或环境变量设置选项。

项目描述

PyPI version Supported Python versions Downloads per week API Documentation

概述

具有大量用户可设置选项的应用程序最好通过命令行参数、配置文件、硬编码默认值以及在某些情况下环境变量组合进行配置。

Python的命令行解析模块,如argparse,对配置文件和环境变量的支持非常有限,因此此模块扩展了argparse以添加这些功能。

在PyPI上可用:http://pypi.python.org/pypi/ConfigArgParse

功能

  • 现在可以使用单个API(如果以多种方式指定了值,则:命令行 > 环境变量 > 配置文件值 > 默认值)一次性定义、文档化和解析命令行、配置文件、环境变量和默认设置

  • 配置文件可以具有.ini或.yaml风格的语法(例如,key=value或key: value)

  • 用户可以通过类似普通命令行参数的方式提供配置文件(例如,-c path/to/config.txt),而不是argparse风格的@config.txt。

  • 可以指定一个或多个默认配置文件路径(例如,[‘/etc/bla.conf’,‘~/.my_config’])。

  • 完全支持argparse的所有功能,因此该模块可以作为直接替换(通过argparse单元测试验证)。

  • 环境变量和配置文件键及语法将在-h帮助信息中自动记录。

  • 新的方法print_values()可以报告键和值以及它们的设置位置(例如,命令行、环境变量、配置文件或默认值)。

  • 轻量级(无第三方库依赖,除了可选的PyYAML)。

  • 可扩展的(可以通过从ConfigFileParser派生来自定义新的配置文件格式)。

  • 通过运行argparse附带的自定义单元测试进行单元测试,但在configargparse上,并使用tox进行Python 3.5+测试。

示例

config_test.py:

定义4个选项和一个位置参数的脚本,然后解析并打印值。它还打印出帮助信息以及由format_values()生成的字符串,以显示它们的格式。

import configargparse

p = configargparse.ArgParser(default_config_files=['/etc/app/conf.d/*.conf', '~/.my_settings'])
p.add('-c', '--my-config', required=True, is_config_file=True, help='config file path')
p.add('--genome', required=True, help='path to genome file')  # this option can be set in a config file because it starts with '--'
p.add('-v', help='verbose', action='store_true')
p.add('-d', '--dbsnp', help='known variants .vcf', env_var='DBSNP_PATH')  # this option can be set in a config file because it starts with '--'
p.add('vcf', nargs='+', help='variant file(s)')

options = p.parse_args()

print(options)
print("----------")
print(p.format_help())
print("----------")
print(p.format_values())    # useful for logging where different settings came from

config.txt

由于上述脚本将配置文件设置为required=True,因此让我们创建一个配置文件来提供给它

# settings for config_test.py
genome = HCMV     # cytomegalovirus genome
dbsnp = /data/dbsnp/variants.vcf

命令行

现在运行脚本并传递配置文件

DBSNP_PATH=/data/dbsnp/variants_v2.vcf python config_test.py --my-config config.txt f1.vcf f2.vcf

输出

以下是结果

Namespace(dbsnp='/data/dbsnp/variants_v2.vcf', genome='HCMV', my_config='config.txt', v=False, vcf=['f1.vcf', 'f2.vcf'])
----------
usage: config_test.py [-h] -c MY_CONFIG --genome GENOME [-v] [-d DBSNP]
                      vcf [vcf ...]

Args that start with '--' (eg. --genome) can also be set in a config file
(/etc/app/conf.d/*.conf or ~/.my_settings or specified via -c). Config file
syntax allows: key=value, flag=true, stuff=[a,b,c] (for details, see syntax at
https://goo.gl/R74nmi). If an arg is specified in more than one place, then
commandline values override environment variables which override config file
values which override defaults.

positional arguments:
  vcf                   variant file(s)

optional arguments:
  -h, --help            show this help message and exit
  -c MY_CONFIG, --my-config MY_CONFIG
                        config file path
  --genome GENOME       path to genome file
  -v                    verbose
  -d DBSNP, --dbsnp DBSNP
                        known variants .vcf [env var: DBSNP_PATH]

----------
Command Line Args:   --my-config config.txt f1.vcf f2.vcf
Environment Variables:
  DBSNP_PATH:        /data/dbsnp/variants_v2.vcf
Config File (config.txt):
  genome:            HCMV

特殊值

在内部,configargparse通过将它们转换为相应的命令行参数来处理环境变量和配置文件值。例如,“key = value”将被处理为如果命令行上指定了“–key value”。

以下特殊值(无论是配置文件还是环境变量)都将以特殊方式处理以支持布尔值和列表

  • key = true的处理方式与在命令行上指定了“–key”相同。在您的Python代码中,此键必须定义为布尔标志(例如,action=”store_true”或类似)。

  • key = [value1, value2, ...]的处理方式与在命令行上指定了“–key value1 –key value2”等相同。在您的Python代码中,此键必须定义为列表(例如,action=”append”)。

配置文件语法

只有具有长版本的命令行参数(例如,以“–”开头的)可以在配置文件中设置。例如,可以通过在配置文件中放置“color=green”来设置“–color”。配置文件语法取决于构造函数参数:config_file_parser_class,它可以设置为以下提供的类之一:DefaultConfigFileParserYAMLConfigFileParserConfigparserConfigFileParser或设置为ConfigFileParser抽象类的子类。

DefaultConfigFileParser - 有效语法的完整范围

# this is a comment
; this is also a comment (.ini style)
---            # lines that start with --- are ignored (yaml style)
-------------------
[section]      # .ini-style section names are treated as comments

# how to specify a key-value pair (all of these are equivalent):
name value     # key is case sensitive: "Name" isn't "name"
name = value   # (.ini style)  (white space is ignored, so name = value same as name=value)
name: value    # (yaml style)
--name value   # (argparse style)

# how to set a flag arg (eg. arg which has action="store_true")
--name
name
name = True    # "True" and "true" are the same

# how to specify a list arg (eg. arg which has action="append")
fruit = [apple, orange, lemon]
indexes = [1, 12, 35 , 40]

YAMLConfigFileParser - 允许使用YAML语法的子集(http://goo.gl/VgT2DU

# a comment
name1: value
name2: true    # "True" and "true" are the same

fruit: [apple, orange, lemon]
indexes: [1, 12, 35, 40]
colors:
  - green
  - red
  - blue

ConfigparserConfigFileParser - 允许使用python的configparser模块语法的子集(https://docs.pythonlang.cn/3.7/library/configparser.html)。特别是以下configparser选项被设置

config = configparser.ArgParser(
    delimiters=("=",":"),
    allow_no_value=False,
    comment_prefixes=("#",";"),
    inline_comment_prefixes=("#",";"),
    strict=True,
    empty_lines_in_values=False,
)

一旦 configparser 解析了配置文件,所有节名称都会被删除,因此所有键都必须具有唯一的名称,无论它们定义在哪个 INI 节下。此外,任何具有 Python 列表语法的键都会通过将其作为 Python 代码评估为列表(使用 ast.literal_eval)(https://docs.pythonlang.cn/3/library/ast.html#ast.literal_eval)来转换为列表。为了方便起见,所有多行值都被转换为单行值。因此,多行字符串值将把所有换行符转换为空格。注意,由于具有 Python 字典语法的键值对被保存为单行字符串,即使在配置文件中跨多行格式化,也可以使用 PyYAML 的 safe_load 读取并转换为有效的 Python 字典。以下是一个示例。

# inside your config file (e.g. config.ini)
[section1]  # INI sections treated as comments
system1_settings: { # start of multi-line dictionary
    'a':True,
    'b':[2, 4, 8, 16],
    'c':{'start':0, 'stop':1000},
    'd':'experiment 32 testing simulation with parameter a on'
    } # end of multi-line dictionary value

.......

# in your configargparse setup
import configargparse
import yaml

parser = configargparse.ArgParser(
    config_file_parser_class=configargparse.ConfigparserConfigFileParser
)
parser.add_argument('--system1_settings', type=yaml.safe_load)

args = parser.parse_args() # now args.system1 is a valid python dict

IniConfigParser - 支持节段的 INI 解析器。

这个解析器与 ConfigparserConfigFileParser 有些相似。它使用 configparser,并应用对使用 Python 列表语法写入的值的相同处理。

以下是一些增加的功能
  • 必须通过参数创建,以将解析器绑定到节段列表。

  • 不将多行字符串转换为单行。

  • 可选支持将多行字符串转换为列表(如果 split_ml_text_to_list=True)。

  • 可选支持在配置文件中引用字符串

    (当文本不应转换为列表或文本应包含尾随空格时很有用)。

此配置解析器可用于与 setup.cfg 文件集成。

示例

# this is a comment
; also a comment
[my_super_tool]
# how to specify a key-value pair
format-string: restructuredtext
# white space are ignored, so name = value same as name=value
# this is why you can quote strings
quoted-string = '\thello\tmom...  '
# how to set an arg which has action="store_true"
warnings-as-errors = true
# how to set an arg which has action="count" or type=int
verbosity = 1
# how to specify a list arg (eg. arg which has action="append")
repeatable-option = ["https://docs.pythonlang.cn/3/objects.inv",
               "https://twistedmatrix.com/documents/current/api/objects.inv"]
# how to specify a multiline text:
multi-line-text =
   Lorem ipsum dolor sit amet, consectetur adipiscing elit.
   Vivamus tortor odio, dignissim non ornare non, laoreet quis nunc.
   Maecenas quis dapibus leo, a pellentesque leo.

如果您使用 IniConfigParser(sections, split_ml_text_to_list=True)

# the same rules are applicable with the following changes:
[my-software]
# how to specify a list arg (eg. arg which has action="append")
repeatable-option = # Just enter one value per line (the list literal format can also be used)
   https://docs.pythonlang.cn/3/objects.inv
   https://twistedmatrix.com/documents/current/api/objects.inv
# how to specify a multiline text (you have to quote it):
multi-line-text = '''
   Lorem ipsum dolor sit amet, consectetur adipiscing elit.
   Vivamus tortor odio, dignissim non ornare non, laoreet quis nunc.
   Maecenas quis dapibus leo, a pellentesque leo.
   '''

用法

import configargparse
parser = configargparse.ArgParser(
         default_config_files=['setup.cfg', 'my_super_tool.ini'],
         config_file_parser_class=configargparse.IniConfigParser(['tool:my_super_tool', 'my_super_tool']),
     )
...

TomlConfigParser - 支持节段的 TOML 解析器。

TOML 解析器。此配置解析器可用于与 pyproject.toml 文件集成。

示例

# this is a comment
[tool.my-software] # TOML section table.
# how to specify a key-value pair
format-string = "restructuredtext" # strings must be quoted
# how to set an arg which has action="store_true"
warnings-as-errors = true
# how to set an arg which has action="count" or type=int
verbosity = 1
# how to specify a list arg (eg. arg which has action="append")
repeatable-option = ["https://docs.pythonlang.cn/3/objects.inv",
               "https://twistedmatrix.com/documents/current/api/objects.inv"]
# how to specify a multiline text:
multi-line-text = '''
   Lorem ipsum dolor sit amet, consectetur adipiscing elit.
   Vivamus tortor odio, dignissim non ornare non, laoreet quis nunc.
   Maecenas quis dapibus leo, a pellentesque leo.
   '''

用法

import configargparse
parser = configargparse.ArgParser(
         default_config_files=['pyproject.toml', 'my_super_tool.toml'],
         config_file_parser_class=configargparse.TomlConfigParser(['tool.my_super_tool']),
     )
...

CompositeConfigParser - 创建一个能够理解多种格式的配置解析器。

该解析器将依次尝试用每个解析器解析文件,直到成功,否则失败并显示所有遇到的错误消息。

以下代码将使 configargparse 能够理解 TOML 和 INI 格式,使其易于集成到 pyproject.tomlsetup.cfg 中。

import configargparse
my_tool_sections = ['tool.my_super_tool', 'tool:my_super_tool', 'my_super_tool']
                 # pyproject.toml like section, setup.cfg like section, custom section
parser = configargparse.ArgParser(
         default_config_files=['setup.cfg', 'my_super_tool.ini'],
         config_file_parser_class=configargparse.CompositeConfigParser(
            [configargparse.TomlConfigParser(my_tool_sections),
             configargparse.IniConfigParser(my_tool_sections, split_ml_text_to_list=True)]
            ),
     )
...

注意,必须首先放置 TOML 解析器,因为 INI 语法基本上接受任何内容,而 TOML。

ArgParser 单例

为了使配置应用程序中的不同模块更容易,configargparse 通过 configargparse.get_argument_parser(‘name’)(类似于 logging.getLogger(‘name’)) 提供了全局可用的 ArgumentParser 实例。

以下是一个具有定义和检索自己的命令行参数的 utils 模块的应用程序示例。

main.py

import configargparse
import utils

p = configargparse.get_argument_parser()
p.add_argument("-x", help="Main module setting")
p.add_argument("--m-setting", help="Main module setting")
options = p.parse_known_args()   # using p.parse_args() here may raise errors.

utils.py

import configargparse
p = configargparse.get_argument_parser()
p.add_argument("--utils-setting", help="Config-file-settable option for utils")

if __name__ == "__main__":
   options = p.parse_known_args()

帮助格式化程序

ArgumentDefaultsRawHelpFormatter 是一个新的 HelpFormatter,它既添加默认值又禁用换行。它可以传递给构造函数:ArgParser(.., formatter_class=ArgumentDefaultsRawHelpFormatter)

别名

configargparse.ArgumentParser API 继承自 argparse 的类和方法名称,同时也提供了以下更简短的名字以方便使用

  • p = configargparse.get_arg_parser() # 获取全局单例实例

  • p = configargparse.get_parser()

  • p = configargparse.ArgParser() # 创建一个新的实例

  • p = configargparse.Parser()

  • p.add_arg(..)

  • p.add(..)

  • options = p.parse(..)

帮助格式化程序

  • RawFormatter = RawDescriptionHelpFormatter

  • DefaultsFormatter = ArgumentDefaultsHelpFormatter

  • DefaultsRawFormatter = ArgumentDefaultsRawHelpFormatter

API 文档

您可以在 configargparse 模块的生成 API 文档中进行审查:这里

设计说明

单元测试

tests/test_configargparse.py 包含针对此模块特定功能(如配置文件和环境变量支持)的自定义 unittests,以及加载和运行 argparse unittests 的钩子(请参阅内置的 test.test_argparse 模块),但在 configargparse 中替代 argparse。这确保 configargparse 在所有用例中都将作为 argparse 的直接替代品。

之前存在的模块(PyPI搜索关键词:config argparse)

  • argparse(Python v2.7+ 内置模块)

    • 优点

      • 功能齐全的命令行解析

      • 可以使用易于理解的方式从文件中读取参数

    • 缺点

      • 指定配置文件路径的语法不寻常(例如:@file.txt),且在用户帮助信息中未描述。

      • 默认配置文件语法不支持注释且不直观(例如:–namevalue)

      • 不支持环境变量

  • ConfArgParse v1.0.15 (https://pypi.python.org/pypi/ConfArgParse

    • 优点

      • 扩展argparse,以支持由ConfigParser解析的配置文件

      • README中的文档清晰

    • 缺点

      • 使用ArgumentParser.set_defaults(..)处理配置文件值,这意味着“必需”和“选择”不被按预期处理。例如,如果在配置文件中指定必需值,仍然需要在命令行中再次指定。

      • 目前不支持Python 3

      • 没有单元测试,代码未良好文档化

  • appsettings v0.5 (https://pypi.python.org/pypi/appsettings

    • 优点

      • 支持配置文件(yaml格式)和环境变量解析

      • 支持仅通过配置文件设置列表和字典的配置

    • 缺点

      • 通过parse_args命名空间参数传递配置文件和环境设置

      • 测试未完成,且不支持Python 3(导入StringIO)

  • argparse_config v0.5.1 (https://pypi.python.org/pypi/argparse_config

    • 优点

      • 与ConfArgParse v1.0.15具有相似功能

    • 缺点

      • 不支持Python 3(pip安装时出错)

  • yconf v0.3.2 - (https://pypi.python.org/pypi/yconf) - 功能和界面不是很好

  • hieropt v0.3 - (https://pypi.python.org/pypi/hieropt) - 似乎未维护,找不到文档

  • configurati v0.2.3 - (https://pypi.python.org/pypi/configurati

    • 优点

      • 支持JSON、YAML或Python配置文件

      • 处理如字典这样的复杂数据结构

      • 可以将配置名称分组到部分中(类似于.ini文件)

    • 缺点

      • 不支持Python 3

      • 自上次发布到PyPI以来已有2+年

      • 似乎未维护

设计选择

  1. 所有选项都必须通过命令行设置。只有通过配置文件或环境变量设置的选项会增加API的复杂性,并且这不是一个足够有用的功能,因为开发者可以将选项分成部分,并将部分称为“配置文件密钥”,而命令行参数只是“–”加上配置密钥。

  2. 应通过将配置文件和环境变量设置附加到命令行来处理配置文件和环境变量设置(这是第1点的另一个好处)。这是一个易于实现的解决方案,并且隐式地处理了检查是否提供了所有“必需”参数等问题,并且该行为应该易于用户理解。

  3. configargparse不应覆盖argparse的convert_arg_line_to_args方法,以便可以在configargparse上运行所有argparse单元测试。

  4. 在考虑允许的配置文件密钥方面,选项的“dest”值不能作为有效的配置密钥,因为许多选项可以具有相同的dest。相反,由于多个选项不能使用相同的长参数(例如:“–long-arg-x”),让配置密钥是“–long-arg-x”或“long-arg-x”。这意味着开发者可以只允许通过配置文件指定的命令行参数的子集(例如,短参数如-x将被排除)。此外,这样配置密钥在命令行参数在帮助信息中文档化时自动得到文档化。

  5. 不要强迫用户将配置文件设置放在正确的.ini [sections] 中。这没有明显的优势,因为所有选项都可以在命令行中设置,因此无论如何都具有全局唯一的键。强制执行部分只会让用户更难,并增加了实现的复杂性。注意:这个设计选择阻止了configargparse与常见的Python项目配置文件(如setup.cfg或pyproject.toml)集成,因此添加了额外的解析器类,这些类仅解析INI或TOML配置文件中定义的值的一个子集。

  6. 如果需要,可以稍后通过实现一个单独的添加方法并使用命名空间参数(如appsettings_v0.5)来添加仅配置文件参数。

相关网站

版本控制

本软件遵循语义版本控制

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面