Python argparse 需要来自配置文件/字典的参数
Python argparse required arguments from configuration file / dict
我的脚本有多个配置命名参数。我想从配置文件 and/or 命令行提供它们。
- 一些参数是必需的/强制性的
- 默认情况下,这些是从配置文件中读取的
- 可选择使用命令行中的值覆盖它们
- 未提供参数(配置文件或命令行)时必须报告错误
之前一直在使用 set_defaults(),但是在使用 add_arguments(..., required=True)
时会出现错误。
Python 2.7 是否有更好的工作解决方案?
from argparse import ArgumentParser
# this dict will be read from configuration file
config_args = {'my_argument': 'value from configuration file'}
parser = ArgumentParser()
parser.add_argument('--my-argument', dest='my_argument', required=True)
# use values from configuration file by default
parser.set_defaults(**config_args)
# override with command line arguments when provided
args = parser.parse_args({})
这个例子会导致错误:
usage: [-h] --required REQUIRED
: error: argument --required is required
In [355]: config_args = {'my_argument': 'value from configuration file'}
In [356]: parser = argparse.ArgumentParser()
add_argument
创建并 returns 一个 Action
对象。让我们保存对该对象的引用,并查看它:
In [357]: a1 = parser.add_argument('--my-argument', dest='my_argument', required
...: =True)
In [358]: a1
Out[358]: _StoreAction(option_strings=['--my-argument'], dest='my_argument', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
注意它的 default
是 None
,默认为 store
。 required
也设置为 True
.
set_defaults
更改 a1.default
值:
In [359]: parser.set_defaults(**config_args)
In [360]: a1
Out[360]: _StoreAction(option_strings=['--my-argument'], dest='my_argument', nargs=None, const=None, default='value from configuration file', type=None, choices=None, help=None, metavar=None)
set_defaults
也可用于设置参数中未出现的 dest
的值(在子解析器的文档中有说明)。
运行 没有参数,我们会得到一个错误 - 因为该操作是必需的。默认值的存在不会覆盖它。
In [361]: parser.parse_args([])
usage: ipython3 [-h] --my-argument MY_ARGUMENT
ipython3: error: the following arguments are required: --my-argument
An exception has occurred, use %tb to see the full traceback.
SystemExit: 2
如果我们将 required
属性更改为 False
(a1
是一个对象,其属性可以在一定范围内更改。包括 a1.default
)。
In [362]: a1.required
Out[362]: True
In [363]: a1.required=False
In [364]: parser.parse_args([])
Out[364]: Namespace(my_argument='value from configuration file')
现在显示您的配置值。命令行值可以覆盖它。
您还可以在 namespace
参数中提供默认值:
In [365]: ns = argparse.Namespace(my_argument='foo')
In [366]: parser.parse_args([], namespace=ns)
Out[366]: Namespace(my_argument='foo')
此 foo
值具有优先权,因此不使用操作默认值或 set_defaults
值。
https://bugs.python.org/issue29670 argparse: does not respect required args pre-populated into namespace
在此 bug/issue 中,用户希望 ns
中存在一个值来覆盖 required
测试。也就是说,他希望此 ns
表现得好像该值已在命令行上提供。我的结论是,这不是一件容易改变的事情。当前的 parse_args
结构不允许我们修改或绕过 required
.
之类的测试
如果您想要更高级的测试,我建议您保留 default=None
,并在解析后进行您自己的测试。
if args.my_argument is None:
args.my_argument = 'default from config'
根据@hpaulj的回答,对代码做了微调。使用 ArgumentParser 通知缺少的参数,无论是从命令行还是配置文件提供的。
Python27 ArgumentParser 不提供 public API 来访问添加的参数操作。但是有私有属性_actions
。因此,如果从配置文件中提供,只需循环 parser._actions
并重置 required
属性 就足以解决我的用例。
固定代码如下:
from argparse import ArgumentParser
# this dict will be read from configuration file
config_args = {'my_argument': 'value from configuration file'}
parser = ArgumentParser()
arg = parser.add_argument('--my-argument', required=True)
# use values from configuration file by default
parser.set_defaults(**config_args)
# Reset `required` attribute when provided from config file
for action in parser._actions:
if action.dest in config_args:
action.required = False
# override with command line arguments when provided
args = parser.parse_args({})
我的脚本有多个配置命名参数。我想从配置文件 and/or 命令行提供它们。
- 一些参数是必需的/强制性的
- 默认情况下,这些是从配置文件中读取的
- 可选择使用命令行中的值覆盖它们
- 未提供参数(配置文件或命令行)时必须报告错误
之前一直在使用 set_defaults(),但是在使用 add_arguments(..., required=True)
时会出现错误。
Python 2.7 是否有更好的工作解决方案?
from argparse import ArgumentParser
# this dict will be read from configuration file
config_args = {'my_argument': 'value from configuration file'}
parser = ArgumentParser()
parser.add_argument('--my-argument', dest='my_argument', required=True)
# use values from configuration file by default
parser.set_defaults(**config_args)
# override with command line arguments when provided
args = parser.parse_args({})
这个例子会导致错误:
usage: [-h] --required REQUIRED
: error: argument --required is required
In [355]: config_args = {'my_argument': 'value from configuration file'}
In [356]: parser = argparse.ArgumentParser()
add_argument
创建并 returns 一个 Action
对象。让我们保存对该对象的引用,并查看它:
In [357]: a1 = parser.add_argument('--my-argument', dest='my_argument', required
...: =True)
In [358]: a1
Out[358]: _StoreAction(option_strings=['--my-argument'], dest='my_argument', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
注意它的 default
是 None
,默认为 store
。 required
也设置为 True
.
set_defaults
更改 a1.default
值:
In [359]: parser.set_defaults(**config_args)
In [360]: a1
Out[360]: _StoreAction(option_strings=['--my-argument'], dest='my_argument', nargs=None, const=None, default='value from configuration file', type=None, choices=None, help=None, metavar=None)
set_defaults
也可用于设置参数中未出现的 dest
的值(在子解析器的文档中有说明)。
运行 没有参数,我们会得到一个错误 - 因为该操作是必需的。默认值的存在不会覆盖它。
In [361]: parser.parse_args([])
usage: ipython3 [-h] --my-argument MY_ARGUMENT
ipython3: error: the following arguments are required: --my-argument
An exception has occurred, use %tb to see the full traceback.
SystemExit: 2
如果我们将 required
属性更改为 False
(a1
是一个对象,其属性可以在一定范围内更改。包括 a1.default
)。
In [362]: a1.required
Out[362]: True
In [363]: a1.required=False
In [364]: parser.parse_args([])
Out[364]: Namespace(my_argument='value from configuration file')
现在显示您的配置值。命令行值可以覆盖它。
您还可以在 namespace
参数中提供默认值:
In [365]: ns = argparse.Namespace(my_argument='foo')
In [366]: parser.parse_args([], namespace=ns)
Out[366]: Namespace(my_argument='foo')
此 foo
值具有优先权,因此不使用操作默认值或 set_defaults
值。
https://bugs.python.org/issue29670 argparse: does not respect required args pre-populated into namespace
在此 bug/issue 中,用户希望 ns
中存在一个值来覆盖 required
测试。也就是说,他希望此 ns
表现得好像该值已在命令行上提供。我的结论是,这不是一件容易改变的事情。当前的 parse_args
结构不允许我们修改或绕过 required
.
如果您想要更高级的测试,我建议您保留 default=None
,并在解析后进行您自己的测试。
if args.my_argument is None:
args.my_argument = 'default from config'
根据@hpaulj的回答,对代码做了微调。使用 ArgumentParser 通知缺少的参数,无论是从命令行还是配置文件提供的。
Python27 ArgumentParser 不提供 public API 来访问添加的参数操作。但是有私有属性_actions
。因此,如果从配置文件中提供,只需循环 parser._actions
并重置 required
属性 就足以解决我的用例。
固定代码如下:
from argparse import ArgumentParser
# this dict will be read from configuration file
config_args = {'my_argument': 'value from configuration file'}
parser = ArgumentParser()
arg = parser.add_argument('--my-argument', required=True)
# use values from configuration file by default
parser.set_defaults(**config_args)
# Reset `required` attribute when provided from config file
for action in parser._actions:
if action.dest in config_args:
action.required = False
# override with command line arguments when provided
args = parser.parse_args({})