argparse 没有正确处理子解析器中的缩写
argparse not handling abbreviations in subparser properly
(运行 在 python 3.6.0)
TL;DR
Usage: prog.py {caesar | vigenere} [key]
parser = argparse.ArgumentParser()
subp = parser.add_subparsers()
caesar = subp.add_parser("caesar", aliases=["c"], allow_abbrev=True)
args = parser.parse_args()
$ python prog.py caes 123
prog.py: error: invalid choice: 'caes' (choose from 'caesar', 'c')
为什么 subparser
缩写即使 allow_abbrev=True
也无效?
长版
基本上,在让 argparse
接受缩写 subparsers
names/aliases 时遇到问题。
代码如下:
Usage: prog.py [caesar] [key]
import sys, argparse
def main(argv):
parser = argparse.ArgumentParser
(description="runs text through X cipher")
subp = parser.add_subparsers\
(help="sub-command help")
#<ArgumentParser object>
caesar = subp.add_parser\
("caesar", aliases=["c"], allow_abbrev=True)
caesar.add_argument\
("key", metavar = "key (any integer)",\
type = int, default = 0)
args = parser.parse_args()
print(caesar)
if __name__ == "__main__":
sys.argv = list(str(c).lower() for c in sys.argv[0:])
main(sys.argv)
所以从上面的代码来看,应该可以接受以下任何一项:
- "Caesar" or "caesar"
- "C" or "c"
- Any abbreviation in between "c" and "caesar"
问题来了:
这个有效:$ python prog.py c 123
O
这给出了一个错误:$ python prog.py caes 123
X
prog.py: error: invalid choice: 'cae' (choose from 'caesar', 'c')
现在是令人困惑的部分。
根据 argparse 文档:
ArgumentParser supports the creation of such sub-commands with the
add_subparsers() method. The add_subparsers() method is normally
called with no arguments and returns a special action object. This
object has a single method, add_parser(), which takes a command name
and any ArgumentParser constructor arguments, and returns an
ArgumentParser object that can be modified as usual.
好的,所以任何 object created with add_subparser()
都可以用 object.add_parser()
创建自己的 ArgumentParser object
对吧?
...这意味着这个新创建的 ArgumentParser
对象应该能够接受任何 ArgumentParser
参数是吗?
ArgumentParser 定义:
class
argparse.ArgumentParser(
prog=None, usage=None,
description=None, epilog=None,
parents=[],formatter_class=argparse.HelpFormatter,
prefix_chars='-',fromfile_prefix_chars=None,
argument_default=None,conflict_handler='error',
add_help=True, allow_abbrev=True)
Create a new ArgumentParser object. All parameters should be passed as keyword
arguments. Each parameter has its own more detailed description below, but in short
they are:
allow_abbrev
- Allows long options to be abbreviated if the abbreviation is unambiguous.
(default: True)
Changed in version 3.5: allow_abbrev parameter was added.
(this was on python 3.6.0)
提前致谢各位
我得到的错误是:
usage: [-h] {caesar,c} ...
: error: unrecognized arguments: a e s
暗示缩写应该是可组合的,因为可以通过传递 ca
来引用两个不同的缩写 "c" 和 "a"。
那里真正应该发生什么? ca
是 c
和(不存在的)a
缩写形式的组合,也是缩写形式。解析器应该更喜欢哪个?因此,在设计库时必须明确解决这个问题:为了可预测性,你不能同时拥有两者。
话虽如此,也许您可以通过传递 conflict_handler='resolve'
来调整结果? https://docs.python.org/3/library/argparse.html#allow-abbrev
实现了一个允许子解析器名称缩写的补丁,但后来被证明有问题而被撤回:
Issue 12713: allow abbreviation of sub commands by users
允许用户关闭长选项的缩写是另一个问题,在
中处理
Issue 14910: argparse: disable abbreviation
代码的两个不同部分。
allow_abbrev - Allows long options to be abbreviated if the abbreviation is unambiguous.
多头期权创建于:
caesar.add_argument('-f','--foobar')
使用默认的 allow_abbrev
值,这将适用于“-f”、“--foo”和“--foobar”。本例中的 long_option
是“--foobar”。使用它 False
,'--foo' 将不起作用。
主要的 parser
决定 c
或 caesar
或 cae
是否是有效的子解析器命令(通过 subp
,特殊行动对象由parser.add_subparsers
创建)。这表现得更像是 choices
.
的位置
parser.add_argument('foo', choices = ['c', 'caesar'])
(运行 在 python 3.6.0)
TL;DR
Usage: prog.py {caesar | vigenere} [key]
parser = argparse.ArgumentParser()
subp = parser.add_subparsers()
caesar = subp.add_parser("caesar", aliases=["c"], allow_abbrev=True)
args = parser.parse_args()
$ python prog.py caes 123
prog.py: error: invalid choice: 'caes' (choose from 'caesar', 'c')
为什么 subparser
缩写即使 allow_abbrev=True
也无效?
长版
基本上,在让 argparse
接受缩写 subparsers
names/aliases 时遇到问题。
代码如下:
Usage: prog.py [caesar] [key]
import sys, argparse
def main(argv):
parser = argparse.ArgumentParser
(description="runs text through X cipher")
subp = parser.add_subparsers\
(help="sub-command help")
#<ArgumentParser object>
caesar = subp.add_parser\
("caesar", aliases=["c"], allow_abbrev=True)
caesar.add_argument\
("key", metavar = "key (any integer)",\
type = int, default = 0)
args = parser.parse_args()
print(caesar)
if __name__ == "__main__":
sys.argv = list(str(c).lower() for c in sys.argv[0:])
main(sys.argv)
所以从上面的代码来看,应该可以接受以下任何一项:
- "Caesar" or "caesar"
- "C" or "c"
- Any abbreviation in between "c" and "caesar"
问题来了:
这个有效:$ python prog.py c 123
O
这给出了一个错误:$ python prog.py caes 123
X
prog.py: error: invalid choice: 'cae' (choose from 'caesar', 'c')
现在是令人困惑的部分。
根据 argparse 文档:
ArgumentParser supports the creation of such sub-commands with the add_subparsers() method. The add_subparsers() method is normally called with no arguments and returns a special action object. This object has a single method, add_parser(), which takes a command name and any ArgumentParser constructor arguments, and returns an ArgumentParser object that can be modified as usual.
好的,所以任何
object created with add_subparser()
都可以用object.add_parser()
创建自己的ArgumentParser object
对吧?...这意味着这个新创建的
ArgumentParser
对象应该能够接受任何ArgumentParser
参数是吗?
ArgumentParser 定义:
class
argparse.ArgumentParser(
prog=None, usage=None,
description=None, epilog=None,
parents=[],formatter_class=argparse.HelpFormatter,
prefix_chars='-',fromfile_prefix_chars=None,
argument_default=None,conflict_handler='error',
add_help=True, allow_abbrev=True)
Create a new ArgumentParser object. All parameters should be passed as keyword arguments. Each parameter has its own more detailed description below, but in short they are:
allow_abbrev
- Allows long options to be abbreviated if the abbreviation is unambiguous.(default: True)
Changed in version 3.5: allow_abbrev parameter was added.
(this was on python 3.6.0)
提前致谢各位
我得到的错误是:
usage: [-h] {caesar,c} ...
: error: unrecognized arguments: a e s
暗示缩写应该是可组合的,因为可以通过传递 ca
来引用两个不同的缩写 "c" 和 "a"。
那里真正应该发生什么? ca
是 c
和(不存在的)a
缩写形式的组合,也是缩写形式。解析器应该更喜欢哪个?因此,在设计库时必须明确解决这个问题:为了可预测性,你不能同时拥有两者。
话虽如此,也许您可以通过传递 conflict_handler='resolve'
来调整结果? https://docs.python.org/3/library/argparse.html#allow-abbrev
实现了一个允许子解析器名称缩写的补丁,但后来被证明有问题而被撤回:
Issue 12713: allow abbreviation of sub commands by users
允许用户关闭长选项的缩写是另一个问题,在
中处理Issue 14910: argparse: disable abbreviation
代码的两个不同部分。
allow_abbrev - Allows long options to be abbreviated if the abbreviation is unambiguous.
多头期权创建于:
caesar.add_argument('-f','--foobar')
使用默认的 allow_abbrev
值,这将适用于“-f”、“--foo”和“--foobar”。本例中的 long_option
是“--foobar”。使用它 False
,'--foo' 将不起作用。
主要的 parser
决定 c
或 caesar
或 cae
是否是有效的子解析器命令(通过 subp
,特殊行动对象由parser.add_subparsers
创建)。这表现得更像是 choices
.
parser.add_argument('foo', choices = ['c', 'caesar'])