argparse没有正确处理subparser中的缩写

时间:2017-11-10 11:57:10

标签: python argparse case-sensitive case-insensitive subparsers

(在 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')

为什么即使使用subparserallow_abbrev=True缩写也无效?

LONG VER

基本上,在argparse接受缩写subparsers名称/别名时遇到问题。

以下是代码:

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 doc

  

ArgumentParser支持使用。创建此类子命令   add_subparsers()方法。 add_subparsers()方法通常是   没有参数调用并返回一个特殊的操作对象。这个   object有一个方法 add_parser(),它接受一个命令名   和任何ArgumentParser构造函数参数,返回一个   ArgumentParser对象,可以照常修改。

  1. 好的,所以任何object created with add_subparser()都可以创建自己的ArgumentParser object object.add_parser()吗?

  2. ...这意味着这个新创建的ArgumentParser对象应该能够接受任何ArgumentParser个参数了吗?

  3. 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)
    
      

    创建一个新的 ArgumentParser 对象。所有参数都应作为关键字传递   参数。每个参数在下面都有自己更详细的描述,但简而言之   他们是:

         

    allow_abbrev - 如果缩写是明确的,则允许缩写长选项。

         

    (默认: True

         

    在版本3.5中更改:添加了allow_abbrev参数。

         

    (这是在python 3.6.0上)

    先谢谢你,伙计们

2 个答案:

答案 0 :(得分:2)

实现了允许缩小子名称缩写的补丁,但是当它被证明是错误的时候撤回了:

Issue 12713: allow abbreviation of sub commands by users

允许用户关闭长选项的缩写是一个不同的问题,在

中处理

Issue 14910: argparse: disable abbreviation

代码的两个不同部分。

  

allow_abbrev - 如果缩写是明确的,则允许缩写 long 选项。

使用以下命令创建一个长选项:

caesar.add_argument('-f','--foobar')

使用默认的allow_abbrev值,这可以使用'-f',' - foo'和'--foobar'。在这种情况下,long_option是'--foobar'。有了它False,' - foo'将无效。

parser决定ccaesarcae是否为有效的子分析器命令(通过subp特殊操作对象parser.add_subparsers创建。这更像是choices的位置。

parser.add_argument('foo', choices = ['c', 'caesar'])

答案 1 :(得分:0)

我得到的错误是:

usage: [-h] {caesar,c} ...
: error: unrecognized arguments: a e s

暗示缩写应该是可组合的,即两个不同的缩写&#34; c&#34;和&#34; a&#34;可以通过传递ca来引用。

那里真的应该发生什么? ca既是c又是(不存在的)a简短形式的组合,也是缩写。解析器应该选择哪个?因此,在设计库时必须明确解决这个问题:为了可预测性,你不能同时拥有这两个。

话虽如此,也许你可以通过传递conflict_handler='resolve'来调整结果? https://docs.python.org/3/library/argparse.html#allow-abbrev