无法获取argparse读取带有破折号的带引号的字符串?

sfe*_*ell 46 python command-line-interface argparse

有没有办法让argparse将两个引号之间的任何内容识别为单个参数?它似乎继续看到破折号,并假设它是一个新选项的开始

我有类似的东西:

mainparser = argparse.ArgumentParser()
subparsers = mainparser.add_subparsers(dest='subcommand')
parser = subparsers.add_parser('queue')
parser.add_argument('-env', '--extraEnvVars', type=str,
                        help='String of extra arguments to be passed to model.')
...other arguments added to parser...
Run Code Online (Sandbox Code Playgroud)

但是当我跑步时:

python Application.py queue -env "-s WHATEVER -e COOL STUFF"
Run Code Online (Sandbox Code Playgroud)

它给了我:

Application.py queue: error: argument -env/--extraEnvVars: expected one argument
Run Code Online (Sandbox Code Playgroud)

如果我离开第一个破折号,它的工作完全正常,但是能够传入带有破折号的字符串是至关重要的.我已经尝试用\来转义它,这会导致它成功但是将\添加到参数字符串有没有人知道如何解决这个问题?无论-s是否是解析器中的参数,都会发生这种情况.

编辑:我正在使用Python 2.7.

EDIT2:

python Application.py -env " -env"
Run Code Online (Sandbox Code Playgroud)

工作得非常好,但是

python Application.py -env "-env"
Run Code Online (Sandbox Code Playgroud)

才不是.

EDIT3:看起来这实际上是就是BEING已经讨论了一个错误:http://www.gossamer-threads.com/lists/python/bugs/89529,http://python.6.x6.nabble.com/issue9334- argparse-does-not-accept-options-taking-arguments-beginning-with-dash-regression-from-optp-td578790.html.它仅在2.7中而不是在optparse中.

EDIT4:当前的开放式错误报告是:http://bugs.python.org/issue9334

Set*_*ton 49

更新的答案:

你可以在调用时给出一个等号:

python Application.py -env="-env"
Run Code Online (Sandbox Code Playgroud)

原始答案:

我也有麻烦做你想做的事情,但有一个变通方法构建到argparse,这是parse_known_args方法.这将允许您未定义的所有参数通过解析器,并假设您将它们用于子进程.缺点是您不会使用错误的参数进行错误报告,并且您必须确保选项和子进程选项之间没有冲突.

另一种选择可能是强制用户使用加号而不是减号:

python Application.py -e "+s WHATEVER +e COOL STUFF"
Run Code Online (Sandbox Code Playgroud)

然后在传递给子进程之前在后处理中将'+'更改为' - '.

  • @sfendel尝试使用等号:`python Application.py -env =" - env"` (5认同)

hpa*_*ulj 17

这个问题在http://bugs.python.org/issue9334中有详细讨论.大多数活动是在2011年.去年我添加了一个补丁,但argparse补丁积压.

问题在于字符串中的潜在歧义'--env',或者"-s WHATEVER -e COOL STUFF"当它遵循带参数的选项时.

optparse做一个简单的从左到右的解析.第一个--env是一个带有一个参数的选项标志,因此它会消耗下一个参数,无论它看起来如何. argparse另一方面,两次循环穿过琴弦.首先,它将它们分类为"O"或"A"(选项标志或参数).在第二个循环上,它使用re类似的模式匹配来处理变量nargs值.在这种情况下,它看起来像我们有OO,两个标志,没有参数.

使用时的解决方案argparse是确保参数字符串不会与选项标志混淆.此处(以及错误问题)中显示的可能性包括:

--env="--env"  # clearly defines the argument.

--env " --env"  # other non - character
--env "--env "  # space after

--env "--env one two"  # but not '--env "-env one two"'
Run Code Online (Sandbox Code Playgroud)

它本身'--env'看起来像一个标志(即使引用,见sys.argv),但当其他字符串后面没有.但是"-env one two"有问题,因为它可以被解析为['-e','nv one two'],' - e'标志后跟一个字符串(或更多的选项).

--并且nargs=argparse.PARSER还可以用于强制argparse查看所有后续字符串作为参数.但它们只在参数列表的末尾起作用.

在issue9334中有一个建议的补丁来添加一个args_default_to_positional=True模式.在此模式下,解析器仅将字符串分类为选项标志,如果它可以使用定义的参数清楚地匹配它们.因此,' - env --one'中的'--one'将被归类为参数.但是' - env --env'中的第二个'--env'仍将被归类为选项标志.


扩大相关案例

使用带有以短划线(" - ")开头的参数值的argparse

parser = argparse.ArgumentParser(prog="PROG")
parser.add_argument("-f", "--force", default=False, action="store_true")
parser.add_argument("-e", "--extra")
args = parser.parse_args()
print(args)
Run Code Online (Sandbox Code Playgroud)

产生

1513:~/mypy$ python3 stack16174992.py --extra "--foo one"
Namespace(extra='--foo one', force=False)
1513:~/mypy$ python3 stack16174992.py --extra "-foo one"
usage: PROG [-h] [-f] [-e EXTRA]
PROG: error: argument -e/--extra: expected one argument
1513:~/mypy$ python3 stack16174992.py --extra "-bar one"
Namespace(extra='-bar one', force=False)
1514:~/mypy$ python3 stack16174992.py -fe one
Namespace(extra='one', force=True)
Run Code Online (Sandbox Code Playgroud)

"-foo one"案例失败,因为它-foo被解释为-f标志加上未指定的附加内容.这是允许-fe被解释为的相同动作['-f','-e'].

如果我更改nargsto REMAINDER(not PARSER),则后面的所有内容都-e被解释为该标志的参数:

parser.add_argument("-e", "--extra", nargs=argparse.REMAINDER)
Run Code Online (Sandbox Code Playgroud)

所有案例都有效.请注意,该值是一个列表.并且不需要报价:

1518:~/mypy$ python3 stack16174992.py --extra "--foo one"
Namespace(extra=['--foo one'], force=False)
1519:~/mypy$ python3 stack16174992.py --extra "-foo one"
Namespace(extra=['-foo one'], force=False)
1519:~/mypy$ python3 stack16174992.py --extra "-bar one"
Namespace(extra=['-bar one'], force=False)
1519:~/mypy$ python3 stack16174992.py -fe one
Namespace(extra=['one'], force=True)
1520:~/mypy$ python3 stack16174992.py --extra --foo one
Namespace(extra=['--foo', 'one'], force=False)
1521:~/mypy$ python3 stack16174992.py --extra -foo one
Namespace(extra=['-foo', 'one'], force=False)
Run Code Online (Sandbox Code Playgroud)

argparse.REMAINDER就像'*',除了它接下来的一切,无论它看起来像是旗帜. argparse.PARSER更像是'+',因为它首先需要一个positional类似的参数.它nargs就是subparsers用的.

这种用途REMAINDER记录在案,https://docs.python.org/3/library/argparse.html#nargs

  • 非常感谢:`nargs = argparse.PARSER`帮助了我. (2认同)

Wil*_*iam 13

您可以使用空格python tst.py -e ' -e blah'作为一个非常简单的解决方法来启动参数.lstrip()如果你愿意,只需将它恢复正常即可.

或者,如果第一个"子参数"也不是原始函数的有效参数,那么您根本不需要做任何事情.也就是说,唯一python tst.py -e '-s hi -e blah'不起作用的原因是因为它-s是一个有效的选项tst.py.

此外,现已弃用的optparse模块也可以正常运行.

  • 我认为这不会发生,因为-s是子解析器的有效选项。我尝试使用python Application.py queue -e“ -notarealoption”并得到了相同的错误。我喜欢使用lstrip比用+替换+更好-就像SethMMorton建议的一样,但实际上似乎应该有一种引用字符串的方式,使得argparse不能替换/更改/读取其中的任何字符串。 (2认同)