2013-12-23 97 views
2

我有一個python腳本,它接受一個可選的位置參數並有幾個子命令。其中一些子命令需要位置參數,有些則不需要。我嘗試使用不需要位置參數的子命令時出現了問題。考慮下面的測試文件:argparse可選的位置參數和子分析器參數

import argparse 

argp = argparse.ArgumentParser() 
argp.add_argument('inputfile', type=str, nargs='?', 
        help='input file to process') 
argp.add_argument('--main_opt1', type=str, 
        help='global option') 

subp = argp.add_subparsers(title='subcommands', 
          dest='parser_name', 
          help='additional help', 
          metavar="<command>") 

tmpp = subp.add_parser('command1', help='command1 help') 
tmpp.add_argument('pos_arg1', type=str, 
        help='positional argument') 

print repr(argp.parse_args()) 

當我嘗試的第一個參數一切順利使用子command1

macbook-pro:~ jmlopez$ python pytest.py filename command1 otherarg 
Namespace(inputfile='filename', main_opt1=None, parser_name='command1', pos_arg1='otherarg') 

但現在讓我們假設command1不需要第一個位置參數。

macbook-pro:~ jmlopez$ python pytest.py command1 otherarg 
usage: pytest.py [-h] [--main_opt1 MAIN_OPT1] [inputfile] <command> ... 
pytest.py: error: argument <command>: invalid choice: 'otherarg' (choose from 'command1') 

我莫名其妙地被期待inputfile設置爲None。​​可以預測command1實際上是一個子命令,因此inputfile應該設置爲None嗎?

回答

0

您需要告訴解析器第一個參數是不同的類型。 嘗試添加標記選項,默認值None這樣的:

argp.add_argument('-i','--inputfile', type=str, nargs='?', 
       help='input file to process',default=None) 

現在,你所需要的參數inputfile中前加-i,但它會正常工作。

macbook-pro:~ jmlopez$ python pytest.py -i filename command1 otherarg 
Namespace(inputfile='filename', main_opt1=None, parser_name='command1', pos_arg1='otherarg') 

macbook-pro:~ jmlopez$ python pytest.py command1 otherarg 
Namespace(inputfile=None, main_opt1=None, parser_name='command1', pos_arg1='otherarg') 
+0

擁有它之前我可以使用'macbook-pro:〜jmlopez $ python pytest.py _ command1 otherarg'讓python知道輸入參數是空的。我寧願有個選項說'--cmd'來指定第一個關鍵字是一個命令,而不是它的輸入。 – jmlopez

1

argp子分析器說法看起來就像另一個位置,即需要選擇(在subparsers的名稱)。另外argppos_arg1一無所知。這是tmpp的參數列表。

argp看到filename command1 otherarg,filenamecommand1滿足其2個定位。然後在tmpp上傳遞otherarg

隨着command1 otherarg,再次2個字符串,2個argp定位。 command分配給inputfile。有沒有邏輯回溯,並說command1更適合subcommands,或者`tmpp'需要這些字符串之一。

您可以將第一個位置更改爲可選--inputfile

或者您可以inputfiletmpp的另一位置。如果多個子分析器需要它,請考慮使用parents

​​跟你一樣不聰明,不能'前瞻'或'回溯'。如果它看起來很聰明,那是因爲它使用re模式匹配來處理nargs值(例如?,*,+)。

EDIT

的一種方式「特技」 argparse成識別所述第一位置作爲子分析器是後插入一個任選的。使用command1 -b xxx otherarg,-b xxx打散了位置字符串列表,因此只有command1inputfilesubcommands匹配。

p=argparse.ArgumentParser() 
p.add_argument('file',nargs='?',default='foo') 
sp = p.add_subparsers(dest='cmd') 
spp = sp.add_parser('cmd1') 
spp.add_argument('subfile') 
spp.add_argument('-b') 

p.parse_args('cmd1 -b x three'.split()) 
# Namespace(b='x', cmd='cmd1', file='foo', subfile='three') 

的這裏的問題是如何處理​​可變nargs postionals。第二個位置是一個子分析器的事實並不重要。雖然​​允許任意順序的可變長度位置,但它如何處理它們可能會造成混淆。如果只有一個這樣的位置,預測什麼會更容易,並且最終發生。

+1

看來這樣。我想實現我想要的唯一方法是準備'sys.argv'並根據需要插入默認輸入文件或默認命令,然後讓'argparse'完成它的工作。 – jmlopez

+0

在'subcommands'之前有'inputfile'出現很重要嗎?通常(像在'git'這樣的程序中)subparser是第一個位置參數。如果'inputfile'是由'command1'以特殊方式處理的,我希望在命令行結尾附近命名它。 – hpaulj

+0

我已經添加了一個部分解決方案 - 在subparse中添加一個'optional'(標記)參數來分解'位置'字符串列表。 – hpaulj

相關問題