2017-10-10 254 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

相關問題