解析互斥的可选和位置参数,后跟传递参数

时间:2019-05-04 19:48:19

标签: python argparse

我正在尝试模拟Python解释器的命令行行为,如帮助文本所示:

command [options] [-m mod | file] [arg] ...

也就是说:

  • 任意数量的任意选项(格式为-[a-zA-Z],用作标志或带有单个参数)
  • 以下之一:
    • -m mod
    • 文件
  • 零个或多个应按原样使用的参数

我尝试使用内置的argparse模块,但未成功。

import argparse

parser = argparse.ArgumentParser()

selector = parser.add_mutually_exclusive_group(required=True)
selector.add_argument('file', nargs='?', help='path to script')
selector.add_argument('-m', help='module name')

parser.add_argument('args', nargs=argparse.REMAINDER)

parser.parse_args(['-m', 'hello', '--', 'arg1'])

运行此结果

usage: test.py [-h] [-m M] [file] ...
test.py: error: argument file: not allowed with argument -m

这很有意义,因为argparse似乎通常无视选项的顺序-解析选项后剩余的任何位置参数都按指定的顺序从头到尾填充位置参数。

我尝试定义自定义argparse.Action来完成这项工作,但最终看起来很hacky,因为与该组中一个参数相对应的Action类需要为以后包含在args中。

我也尝试过对parser.parse_args的输入进行预处理,但是不喜欢这种方法,因为有关哪些选项具有值(以将选项参数与file参数区分开)的信息是终端参数组的一部分(应将其视为直通参数[arg] ...的开始)将在argparse.add_argument ...调用与预处理代码之间重复。

什么是好的方法(除了要求提供路径-f之外)?

其他限制:

  • 我更喜欢使用argparse或具有良好接口的东西,该接口可以关联参数以帮助文本,并且加载时间不长(对我来说,argparse的导入时间为6毫秒)
  • 我只需要与Python 3.6及更高版本兼容。
  • 这不是理想的选择,但是我可以要求用户在后续参数(将传递给模块或文件的参数)以{{1开头的情况下,将--作为第一个arg }},否则可能会误认为-中的内容。

1 个答案:

答案 0 :(得分:0)

即使没有相互排斥的分组,fileargs也不能很好地发挥作用:

In [2]: parser = argparse.ArgumentParser()                                           
In [3]: parser.add_argument('-m');                                                    
In [4]: parser.add_argument('file', nargs='?');                                      
In [6]: parser.add_argument('args', nargs=argparse.REMAINDER);   

确定:

In [7]: parser.parse_args('-m foo a b c '.split())                                   
Out[7]: Namespace(args=['b', 'c'], file='a', m='foo')

'-'只允许我们使用'-b'作为纯字符串:

In [8]: parser.parse_args('-m foo a -- -b c '.split())                               
Out[8]: Namespace(args=['-b', 'c'], file='a', m='foo')

'a'进入'file',其余部分进入'args'-这是因为所有“连续”位置都被一起求值。使用remainder-m标志将被忽略,并被视为纯字符串。

In [9]: parser.parse_args('a -m foo -- -b c '.split())                               
Out[9]: Namespace(args=['-m', 'foo', '--', '-b', 'c'], file='a', m=None)
In [10]: parser.parse_args('a -- -b c '.split())                                     
Out[10]: Namespace(args=['-b', 'c'], file='a', m=None)

参数分配甚至在调用Action之前就已发生,因此自定义Action类不会改变这种行为。

模糊的参数可以使您最好地控制顺序和互斥。