2017-10-10 251 views
0

我正在使用Python 2.7,并试图使用argparse完成类似shell的行为。 我的问题,一般来说,我似乎无法在Python 2.7中找到一种方法来使用argparse的子分析器作为可选项。 这是很难解释我的问题,所以我会描述我的程序需要什么。如何使用Argparse模块与Python 2.7设置默认的Subparser

该方案有2种模式工作:

  1. 与给定的命令启动程序(每个命令都有它自己的 附加参数)和其他参数将运行一个特定 任务。
  2. 不使用命令启动程序会启动一个类似shell的程序,它可以接收一行参数并对它们进行处理,就好像程序是使用给定行调用的参数一样。

因此,例如,如果我的程序支持 'CMD1' 和 'CMD2' 的命令,我可以用它像这样:

  • python program.py cmd1 additional_args1
  • python program.py cmd2 additional_args2

或壳模式:

  • python program.py
    • cmd1 additional_args1
    • cmd2 additional_args2
    • quit

另外,我也希望我的程序能够利用可选的全局参数,将影响所有命令。

对于我正在使用argparse像这样(这是一个纯粹的例子):

parser = argparse.ArgumentParser(description="{} - Version {}".format(PROGRAM_NAME, PROGRAM_VERSION)) 

parser.add_argument("-i", "--info", help="Display more information") 

subparsers = parser.add_subparsers() 

parserCmd1 = subparsers.add_parser("cmd1", help="First Command") 
parserCmd1.set_defaults(func=cmd1) 

parserCmd2 = subparsers.add_parser("cmd2", help="Second Command") 
parserCmd2.add_argument("-o", "--output", help="Redirect Output") 
parserCmd2.set_defaults(func=cmd2) 

所以我可以调用CMD1(没有额外的参数)或CMD2(带或不带-o标​​志)。而且我可以添加标志-i来显示被调用命令的更多信息。

我的问题是,我无法激活shell模式,因为我必须提供CMD1或CMD2作为参数

限制(因为使用它是强制性的subparsers的):

  • 我不能使用Python 3(我知道在那里可以很容易地完成)
  • 由于全局可选参数,我无法检查是否没有参数来跳过arg解析。
  • 我不想增加一个新的命令调用外壳,在所有

所以不提供命令时,我怎样才能实现这种行为与argparse和Python 2.7它必须是?

+0

只是一个快速的音符 - 事实上,subparsers是可选的是一个错误。他们曾经被要求(作为一个正常的位置),但在几年前一个不相关的变化,subparsers通过裂缝跌倒。我将不得不更详细地研究您的问题,以了解为什么您认为Py2和Py3在这方面存在差异。 – hpaulj

回答

1

另一个想法是使用2阶段的解析。一个处理'globals',返回它无法处理的字符串。然后有条件地使用子分析器处理额外事件。

import argparse 

def cmd1(args): 
    print('cmd1', args) 
def cmd2(args): 
    print('cmd2', args) 

parser1 = argparse.ArgumentParser() 

parser1.add_argument("-i", "--info", help="Display more information") 

parser2 = argparse.ArgumentParser() 
subparsers = parser2.add_subparsers(dest='cmd') 

parserCmd1 = subparsers.add_parser("cmd1", help="First Command") 
parserCmd1.set_defaults(func=cmd1) 

parserCmd2 = subparsers.add_parser("cmd2", help="Second Command") 
parserCmd2.add_argument("-o", "--output", help="Redirect Output") 
parserCmd2.set_defaults(func=cmd2) 

args, extras = parser1.parse_known_args() 
if len(extras)>0 and extras[0] in ['cmd1','cmd2']: 
    args = parser2.parse_args(extras, namespace=args) 
    args.func(args) 
else: 
    print('doing system with', args, extras) 

样品运行:

0901:~/mypy$ python stack46667843.py -i info 
('doing system with', Namespace(info='info'), []) 
0901:~/mypy$ python stack46667843.py -i info extras for sys 
('doing system with', Namespace(info='info'), ['extras', 'for', 'sys']) 
0901:~/mypy$ python stack46667843.py -i info cmd1 
('cmd1', Namespace(cmd='cmd1', func=<function cmd1 at 0xb74b025c>, info='info')) 
0901:~/mypy$ python stack46667843.py -i info cmd2 -o out 
('cmd2', Namespace(cmd='cmd2', func=<function cmd2 at 0xb719ebc4>, info='info', output='out')) 
0901:~/mypy$ 
+0

感谢您的回复,我能够接受您的答案并实施我的工作。需要。 – Yoavhayun

1
在 '可选' subparsers的话题

的bug /问题(有链接)。

https://bugs.python.org/issue29298

注意,这有一个最近的拉请求。


随着你的脚本和添加

args = parser.parse_args() 
print(args) 

结果

1008:~/mypy$ python3 stack46667843.py 
Namespace(info=None) 
1009:~/mypy$ python2 stack46667843.py 
usage: stack46667843.py [-h] [-i INFO] {cmd1,cmd2} ... 
stack46667843.py: error: too few arguments 
1009:~/mypy$ python2 stack46667843.py cmd1 
Namespace(func=<function cmd1 at 0xb748825c>, info=None) 
1011:~/mypy$ python3 stack46667843.py cmd1 
Namespace(func=<function cmd1 at 0xb7134dac>, info=None) 

我以为 '可选' subparsers既影响的Py2和3个版本,但显然它不。我将不得不看代码来验证原因。


在这两种语言中,subparsers.requiredFalse。如果我将它设置为true

subparsers.required=True 

(并添加dest到subparsers定义),该PY3错误消息

1031:~/mypy$ python3 stack46667843.py 
usage: stack46667843.py [-h] [-i INFO] {cmd1,cmd2} ... 
stack46667843.py: error: the following arguments are required: cmd 

所以这是一个差异如何2个版本测试required参数。 Py3注意到required属性; PY2(显然)使用检查positionals列表是否为空的早期方法。


检查所需参数发生在parser._parse_known_args的末尾附近。

Python2.7包括

# if we didn't use all the Positional objects, there were too few 
    # arg strings supplied. 
    if positionals: 
     self.error(_('too few arguments')) 

,检查action.required迭代之前。这就是正在迎头赶上失踪cmd,说too few arguments

因此,一个杂牌是编辑argparse.py,所以它的PY 3版本的相应部分匹配删除该块。

+0

嗨,感谢您的回复。我也无法编辑argparse,出于同样的原因,我无法使用Python3 。这将成为我工作的公司中人员使用的工具。我唯一的保证是他们安装了Python 2.7。 – Yoavhayun

相关问题