【发布时间】:2020-03-25 01:41:24
【问题描述】:
我正在尝试扩展 argparse 以使用配置文件以及 CLI 参数。我想传入配置文件中的所有选项但如果有未知选项则不退出。
我的想法是先致电parse_known_args 了解新选项,然后致电
parse_known_args 再次与 sys.argv。这使我可以准确地警告配置文件中的未知选项,而不是 CLI 上的选项。但是,如果没有足够的参数,argparse 会在第一次调用 parse_known_args 后退出。有没有办法告诉它不要退出?
我的代码如下所示:
class Parser(argparse.ArgumentParser):
def parse_known_args(self, args=None, namespace=None):
config = {}
for file in get_config_files(self.prog):
for key, value in try_parse(file, self.default_ext).items():
config[key] = value, file
new_args = []
for key, (val, _) in config.items():
new_args.append('--' + key)
new_args.append(val)
# override configuration with argparse's builtin parsing
# makes CLI options take precedence over config files
# ----- This is where argparse exits -----
parsed_config, unknown = super().parse_known_args(new_args, namespace)
#print("finished first call to known_args")
for key in unknown[::2]:
key = key[2:]
_, filename = config[key]
warnings.warn("unknown option '%s' (from %s)" % (key, filename))
#print(parsed_config)
return super().parse_known_args(args, parsed_config)
示例用法如下所示:
>>> from pyautoconfig import Parser
>>> p = Parser(prog='test')
>>> p.add_argument('positional')
_StoreAction(option_strings=[], dest='positional', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>> p.parse_args(['positional arg'])
usage: test [-h] positional
test: error: the following arguments are required: positional
请注意,即使我传递了位置参数,它也是如何以错误退出的。我怎样才能避免这种情况?
我找到了How to call parse_args() twice on the same set of arguments in Python's argparse?,但它处理的参数太多,而不是太少(推荐的解决方案是使用parse_known_args)。
如果有帮助,完整代码是 on GitHub。
【问题讨论】:
-
我查看了源代码,我什至无法捕捉到 ArgumentError 因为
parse_known_args吞下它并首先退出:github.com/python/cpython/blob/3.8/Lib/argparse.py#L1799 :( -
您可能在这里陷入了“XY 问题”。我会重新考虑您要做什么:mywiki.wooledge.org/XyProblem 换句话说:尝试使用不同的工具来解析配置文件,而不是用于命令行参数的东西。
-
@KevinAnderson 问题是我想保留 argparse 的所有功能,例如
type和mutually_exclusive_args和choices。我不想让 argparse 解析 JSON 或类似的东西,我自己做所有这些。 -
您可以在解析器遇到错误时更改行为。
parser.error和parser.exit可以定制。请注意,required_actions案例使用self.error(....)。 -
@hpaulj 这不起作用,因为它不检查互斥参数。请注意,在检查所需参数之后进行检查:github.com/python/cpython/blob/3.8/Lib/argparse.py#L2038。此外,我不想捕捉每一个错误,只捕捉这个特定的错误。