2014-10-06 60 views
4

我需要實現一個命令行界面,其中程序接受子命令。如何使用argparse處理CLI子命令

例如,如果該計劃被稱爲「富」,在CLI看起來像

foo cmd1 <cmd1-options> 
foo cmd2 
foo cmd3 <cmd3-options> 

cmd1cmd3必須與他們的選擇至少一個和三個cmd*參數總是獨佔使用。

我想在argparse中使用subparsers,但暫時沒有成功。問題出在cmd2,沒有參數:

如果我嘗試添加沒有參數的子分析器條目,parse_args返回的名稱空間將不包含任何告訴我該選項被選中的信息(請參見下面的示例) 。 如果我嘗試將cmd2作爲參數添加到parser(而不是子分析器),那麼argparse會認爲cmd2參數後面會有任何子分析器參數。

有沒有簡單的方法來實現這一點​​?使用情況應該是很常見......

這裏如下是我迄今試圖更接近我所需要的:

所有subparsers的
parser = argparse.ArgumentParser() 
subparsers = parser.add_subparsers(help='Functions') 
parser_1 = subparsers.add_parser('cmd1', help='...') 
parser_1.add_argument('cmd1_option1', type=str, help='...') 

parser_2 = subparsers.add_parser(cmd2, help='...') 

parser_3 = subparsers.add_parser('cmd3', help='...') 
parser_3.add_argument('cmd3_options', type=int, help='...') 

args = parser.parse_args() 

回答

5

首先是從未插入的命名空間。在這個例子中你張貼,如果你嘗試運行腳本:

$python3 test_args.py cmd1 1 
Namespace(cmd1_option1='1') 

其中test_args.py包含您所提供的代碼(與import argparse在開始和print(args)末)。

請注意,沒有提及cmd1僅限於它的論點。 這是設計

正如在評論中指出的那樣,您可以添加通過dest參數傳遞給add_subparsers調用的信息。

通常的方法來處理這些情況是使用subparsers的set_defaults方法:

import argparse 
parser = argparse.ArgumentParser() 
subparsers = parser.add_subparsers(help='Functions') 
parser_1 = subparsers.add_parser('cmd1', help='...') 
parser_1.add_argument('cmd1_option1', type=str, help='...') 
parser_1.set_defaults(parser1=True) 

parser_2 = subparsers.add_parser('cmd2', help='...') 
parser_2.set_defaults(parser2=True) 

parser_3 = subparsers.add_parser('cmd3', help='...') 
parser_3.add_argument('cmd3_options', type=int, help='...') 
parser_3.set_defaults(parser_3=True) 

args = parser.parse_args() 
print(args) 

導致:

$python3 test_args.py cmd1 1 
Namespace(cmd1_option1='1', parser1=True) 
$python3 test_args.py cmd2 
Namespace(parser2=True) 

通常,不同子分析器會,大部分時間,以完全不同的方式處理參數。通常的模式是具有不同的功能來運行不同的命令,並使用set_defaults來設置func屬性。當您解析參數您只需調用調用:

subparsers = parser.add_subparsers() 
parser_1 = subparsers.add_parser(...) 
parser_1.set_default(func=do_command_one) 

parser_k = subparsers.add_parser(...) 
parser_k.set_default(func=do_command_k) 

args = parser.parse_args() 
if args.func: 
    args.func(args) 
+0

我對'永不插入'問題。簡單地給'add_subparsers'一個'dest'。 – hpaulj 2014-10-06 23:05:20

+0

@hpaulj你是對的。但是,我個人從未使用過。正如我所說的,對不同的子分析器使用不同的處理函數有更多的命令,所以使用'set_defaults'是更好的解決方案。只適用於想要使用'dest'參數的最簡單情況。 – Bakuriu 2014-10-07 10:37:43

0

子分析器身份可如果add_subparsers命令被賦予dest被添加到主Namespace

從文檔:

但是,如果有必要檢查被調用的子分析器的名稱,DEST關鍵字參數到add_subparsers()調用將工作:

>>> parser = argparse.ArgumentParser() 
>>> subparsers = parser.add_subparsers(dest='subparser_name') 
>>> subparser1 = subparsers.add_parser('1') 
>>> subparser1.add_argument('-x') 
>>> subparser2 = subparsers.add_parser('2') 
>>> subparser2.add_argument('y') 
>>> parser.parse_args(['2', 'frobble']) 
Namespace(subparser_name='2', y='frobble') 

默認情況下,destargparse.SUPPRESS,它使subparsers不會將名稱添加到namespace