配置 argparse 以接受带引号的参数

Configure argparse to accept quoted arguments

我正在编写一个程序,除其他外,该程序允许用户通过参数指定要加载的模块(然后用于执行操作)。我正在尝试设置一种方法来轻松地将参数传递给这个内部模块,并且我试图使用 ArgParse 的 action='append' 来构建一个参数列表,然后我将通过该列表。

这是我使用的参数的基本布局

parser.add_argument('-M', '--module',
                    help="Module to run on changed files - should be in format MODULE:CLASS\n\
                          Specified class must have function with the signature run(src, dest)\
                          and return 0 upon success",
                    required=True)
parser.add_argument('-A', '--module_args',
                    help="Arg to be passed through to the specified module",
                    action='append',
                    default=[])

但是 - 如果我然后尝试使用 python my_program -M module:class -A "-f filename" 运行 这个程序(我想通过 -f filename 传递到我的模块)它似乎正在解析 -f 作为它自己的参数(我得到错误 my_program: error: argument -A/--module_args: expected one argument

有什么想法吗?

解决方案是接受任意参数 - argparse 的文档中有一个示例 here:

argparse.REMAINDER. All the remaining command-line arguments are gathered into a list. This is commonly useful for command line utilities that dispatch to other command line utilities:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--foo')
>>> parser.add_argument('command')
>>> parser.add_argument('args', nargs=argparse.REMAINDER)
>>> print(parser.parse_args('--foo B cmd --arg1 XX ZZ'.split()))
Namespace(args=['--arg1', 'XX', 'ZZ'], command='cmd', foo='B')

有:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-M', '--module',
                    help="Module to run on changed files - should be in format MODULE:CLASS\n\
                          Specified class must have function with the signature run(src, dest)\
                          and return 0 upon success",
                    )
parser.add_argument('-A', '--module_args',
                    help="Arg to be passed through to the specified module",
                    action='append',
                    default=[])
import sys
print(sys.argv)
print(parser.parse_args())

我得到:

1028:~/mypy$ python stack45146728.py -M module:class -A "-f filename"
['stack45146728.py', '-M', 'module:class', '-A', '-f filename']
Namespace(module='module:class', module_args=['-f filename'])

这是使用 linux shell。引用的字符串仍然是一个字符串,如 sys.argv 中所示,并被正确解释为 -A.

的参数

没有引号,-f 是单独的并被解释为一个标志。

1028:~/mypy$ python stack45146728.py -M module:class -A -f filename
['stack45146728.py', '-M', 'module:class', '-A', '-f', 'filename']
usage: stack45146728.py [-h] [-M MODULE] [-A MODULE_ARGS]
stack45146728.py: error: argument -A/--module_args: expected one argument

您使用的是 windows 还是其他一些不以相同方式处理引号的 OS/shell?


您询问的命令行略有不同:

1032:~/mypy$ python stack45146728.py  -A "-k filepath" -A "-t"
['stack45146728.py', '-A', '-k filepath', '-A', '-t']
usage: stack45146728.py [-h] [-M MODULE] [-A MODULE_ARGS]
stack45146728.py: error: argument -A/--module_args: expected one argument

正如我已经指出的,-k filepath 作为一个字符串传递。由于 space,argparse 不会将其解释为标志。但它确实将裸露的“-t”解释为标志。

有一个 bug/issue 关于将未定义的 '-xxx' 字符串解释为参数而不是标志的可能性。我必须查看一下,看看是否有任何东西投入生产。

有关如何将字符串分类为标志或参数的详细信息,请参见 argparse.ArgumentParser._parse_optional 方法。它包含评论:

    # if it contains a space, it was meant to be a positional
    if ' ' in arg_string:
        return None

http://bugs.python.org/issue9334 argparse does not accept options taking arguments beginning with dash (regression from optparse) 是一个古老而漫长的话题 bug/issue。