Python argparse:存储参数不匹配任何子解析器

Posted

技术标签:

【中文标题】Python argparse:存储参数不匹配任何子解析器【英文标题】:Python argparse: Store parameters not matching any subparser 【发布时间】:2021-03-15 01:43:18 【问题描述】:

我正在使用 argparse 库来解析我的 python 脚本的参数。这是我的代码:

 parser = argparse.ArgumentParser(
        prog="confgit",
        description="Git overhead for version control of your config files",
        formatter_class=argparse.RawTextHelpFormatter, )

    parser.add_argument(
        "-c", "--config",
        type=str,
        default=DEFAULT_CONFIG_PATH,
        dest="CONFIG_PATH",
        help="load alternative config")

    subparsers = parser.add_subparsers(help="Commands:")

    subparsers.add_parser("include", help="Include file or directory in to repository").add_argument(
        "file_to_include",
        type=str,
        action="store",
        nargs="?",
        const="",
        default=False,
        help="include file or directory in to repository")
    subparsers.add_parser("exclude", help="Exclude file or directory in to repository").add_argument(
        "exclude",
        type=str,
        action="store",
        help="exclude file or directory from repository")

    print(parser.parse_args())

我希望能够将不匹配任何子解析器的参数存储为字符串。例如 运行 myprogram include test.txt --config .config/cfg.txt 将导致:

Namespace(CONFIG_PATH='.config/cfg.txt', file_to_include='test.txt')

运行myprogram some text here 将导致:

Namespace(CONFIG_PATH='.config/default.txt', input="some other text")

我怎样才能做到这一点? 谢谢你的帮助

【问题讨论】:

通常我们将add_subparsers结果分配给一个变量,然后将其与以下add_argument一起使用。您的链接适用于一个参数,但让这位老 argparse 用户感到困惑。 【参考方案1】:

代码的帮助:

1940:~/mypy$ python3 stack65119253.py -h
usage: confgit [-h] [-c CONFIG_PATH] include,exclude ...

Git overhead for version control of your config files

positional arguments:
  include,exclude     Commands:
    include             Include file or directory in to repository
    exclude             Exclude file or directory in to repository

optional arguments:
  -h, --help            show this help message and exit
  -c CONFIG_PATH, --config CONFIG_PATH
                        load alternative config

所以你可以提供一个带有值的optional'-c'。

subparsers 参数是一个 positional 和 2 个 choices。这不是必需的,但如果您确实提供了一个字符串,它将针对这些字符串进行测试。

1941:~/mypy$ python3 stack65119253.py include -h
usage: confgit include [-h] [file_to_include]

positional arguments:
  file_to_include  include file or directory in to repository

optional arguments:
  -h, --help       show this help message and exit
1941:~/mypy$ python3 stack65119253.py exclude -h
usage: confgit exclude [-h] exclude

positional arguments:
  exclude     exclude file or directory from repository

optional arguments:
  -h, --help  show this help message and exit

例如:

1946:~/mypy$ python3 stack65119253.py -c foobar
Namespace(CONFIG_PATH='foobar')

1946:~/mypy$ python3 stack65119253.py -c foobar test
usage: confgit [-h] [-c CONFIG_PATH] include,exclude ...
confgit: error: invalid choice: 'test' (choose from 'include', 'exclude')

1947:~/mypy$ python3 stack65119253.py -c foobar include
Namespace(CONFIG_PATH='foobar', file_to_include=False)

argparse 通过位置将字符串分配给positionals。它不按值分配。也就是说,它不测试某些值,并根据它决定它是否合格。 choices 测试是在分配之后进行的。如果要按值分配,请使用optionals

parser.add_argument('--include', nargs='?')
parser.add_argument('--exclude')

parse+known_args 是处理unrecognized 参数的一种方式,但它无法绕过invalid choices 错误。

【讨论】:

我可以通过将 nargs 位置放在前面来部分解决它,但由于某种原因,最后一个参数会针对 subparser 命令进行测试,而不是被 nargs slurped。我想这只是合乎逻辑的,因为这样就不可能在子命令之前有一个 nargs 位置并让子命令工作。 当你连续有 2 个位置时,一个是 ?,另一个是 'plain',它会保留一个字符串作为第二个。由于过去补丁中的故障,subparsers 位置有点奇怪,并且在这种情况下表现为必需的位置,但在更大的图片中不是必需的。作为一般规则,subparsers 之前的位置不应该有变量nargs【参考方案2】:

如果用户不引用字符串"some other text",您只需将其视为3 个不同的参数["some", "other", "text"]。但是要尽可能地处理它,您只需要在名为input 的参数上使用nargs 选项。 argparse 页面顶部有一个带有“数字累加器”的示例。

    parser = argparse.ArgumentParser(description='Process some integers.')
    parser.add_argument('integers', metavar='N', type=int, nargs='+',
                        help='an integer for the accumulator')

对 0 个或多个参数使用 * 而不是 +,并将 integers 替换为您想要的任何参数名称。


经过进一步调查,当您有子解析器时,我上面写的内容将不起作用。我建议将您的 includeexclude 子命令设置为选项。无论如何都想做这不是明智的吗?在您当前的配置中,您只能包含或排除。

【讨论】:

在我的尝试中,我无法让它工作,因为它告诉我子解析器参数之一是必需的,尽管在 python 3.7 中他们引入了可选的子解析器,所以我不完全确定为什么它不起作用。不过,基本的想法应该可行。

以上是关于Python argparse:存储参数不匹配任何子解析器的主要内容,如果未能解决你的问题,请参考以下文章

Python argparse 忽略无法识别的参数

Python argparse:默认参数存储为字符串,而不是列表

在没有任何参数的情况下调用脚本时使用 Python argparse 显示帮助消息

带有编号参数名称的 Python argparse

Python Argparse“需要以下参数”错误

python库之argparse