2017-05-30 55 views
0

我想支持一個命令行界面,用戶可以在其中聲明任意數量的樣本,並且每個樣本對應一個或多個輸入文件。事情是這樣的:用Python支持任意數量的相關命名參數argparse

$ myprogram.py \ 
     --foo bar \ 
     --sample1 input1.tsv \ 
     --sample2 input2a.tsv input2b.tsv input2c.tsv \ 
     --sample3 input3-filtered.tsv \ 
     --out output.tsv 

的想法是,選項鍵將匹配模式--sample(\d+),並且每個按鍵將消耗所有後續參數作爲選項的值,直到遇到下一個---前綴標誌。對於顯式聲明的參數,這是​​模塊通過nargs='+'選項支持的常見用例。但是因爲我需要支持任意數量的參數,所以我不能明確地聲明它們。

parse_known_args命令將允許我訪問所有用戶提供的參數,但那些未顯式聲明的參數不會被分組到索引數據結構中。對於這些我需要仔細檢查參數列表,然後看看有多少後續值對應於當前標誌,等等。

有沒有什麼辦法可以解析這些選項而不必實質上重新實現參數解析器的大部分(幾乎)從頭開始?

+0

你有沒有考慮過建立argparser?計算命令行上'--sample'的數量並使用它來構建適當的argparser?這種環島,但它可以讓argparse完成繁重的工作。 – TemporalWolf

回答

1

如果你可以用一個稍微不同的語法,即生活:

$ myprogram.py \ 
    --foo bar \ 
    --sample input1.tsv \ 
    --sample input2a.tsv input2b.tsv input2c.tsv \ 
    --sample input3-filtered.tsv \ 
    --out output.tsv 

其中參數名不包含數字,但仍進行分組,試試這個:

parser.add_argument('--sample', action='append', nargs='+') 

它產生一個列表,即。--sample x y --sample 1 2會產生Namespace(sample=[['x', 'y'], ['1', '2']])

+0

我之前使用過'action =「append」',但從來沒有在這種情況下使用過。偉大的建議! –

0

你可能會用click而不是​​來做這種事情。

引述:

$ click_

點擊是一個Python包的組合的方式創造出美麗的命令行接口 根據需要儘可能少的代碼。 這是「命令行界面創建工具包」。它非常可配置,但配有合理的默認值。

它旨在使編寫命令行工具的過程變得快速並且有趣,同時還防止由於無法實現預期的CLI API而導致的任何挫敗感。

單擊三點:

  • 命令的任意嵌套
  • 自動幫助頁面生成
  • 支持在運行時

    子的延遲加載閱讀文檔在http://click.pocoo.org/

一個點擊的重要特點是構造子命令的能力,(有點像使用Git或圖像魔術祕密),它應該讓你組織你的命令行:

myprogram.py \ 
    --foo bar \ 
    --sampleset input1.tsv \ 
    --sampleset input2a.tsv input2b.tsv input2c.tsv \ 
    --sampleset input3-filtered.tsv \ 
    combinesets --out output.tsv 

或者連:

myprogram.py \ 
    --foo bar \ 
    process input1.tsv \ 
    process input2a.tsv input2b.tsv input2c.tsv \ 
    process input3-filtered.tsv \ 
    combine --out output.tsv 

這可能是清潔劑,在這種情況下,您的代碼必須的參數調用--foo--out和函數調用processcombine進程將使用指定的輸入文件(S)被調用,並沒有對合並米。

+1

除非你真的可以通過點擊來展示如何做到這一點 - 或者至少指出了要使用的功能 - 但這並不算真正的答案。 – jwodder

1

將該數字或關鍵字設置爲單獨的參數值並在嵌套列表中收集相關參數會更簡單。

import argparse 

parser = argparse.ArgumentParser() 
parser.add_argument('--foo') 
parser.add_argument('--out') 
parser.add_argument('--sample', nargs='+', action='append', metavar=('KEY','TSV')) 

parser.print_help() 

argv = "myprogram.py \ 
     --foo bar \ 
     --sample 1 input1.tsv \ 
     --sample 2 input2a.tsv input2b.tsv input2c.tsv \ 
     --sample 3 input3-filtered.tsv \ 
     --out output.tsv" 
argv = argv.split() 
args = parser.parse_args(argv[1:]) 
print(args) 

生產:

1031:~/mypy$ python3 stack44267794.py -h 
usage: stack44267794.py [-h] [--foo FOO] [--out OUT] [--sample KEY [TSV ...]] 

optional arguments: 
    -h, --help   show this help message and exit 
    --foo FOO 
    --out OUT 
    --sample KEY [TSV ...] 
Namespace(foo='bar', out='output.tsv', 
    sample=[['1', 'input1.tsv'], 
      ['2', 'input2a.tsv', 'input2b.tsv', 'input2c.tsv'], 
      ['3', 'input3-filtered.tsv']]) 

已經有大約收集一般key:value對的問題。​​沒有什麼可以直接支持的。已經提出了各種各樣的東西,但都歸結爲你自己解析對。

Is it possible to use argparse to capture an arbitrary set of optional arguments?

您已經添加了併發症,論據每個鍵的數量是可變的。這就排除了處理'--sample1 = input1'作爲簡單的字符串。

​​已經延伸了衆所周知的POSIX命令行標準。但是如果你想要超越這個範圍,那麼要準備好在(sys.argv)之前或​​(parse_known_argsextras)之後處理參數。

1

正如我在我的評論中提到:

import argparse 

argv = "myprogram.py \ 
     --foo bar \ 
     --sample1 input1.tsv \ 
     --sample2 input2a.tsv input2b.tsv input2c.tsv \ 
     --sample3 input3-filtered.tsv \ 
     --out output.tsv" 

parser = argparse.ArgumentParser() 
parser.add_argument('--foo') 
parser.add_argument('--out') 
for x in range(1, argv.count('--sample') + 1): 
    parser.add_argument('--sample' + str(x), nargs='+') 
args = parser.parse_args(argv.split()[1:]) 

給出:

print args 
Namespace(foo='bar', out='output.tsv', sample1=['input1.tsv'], sample2=['input2a.tsv', 'input2b.tsv', 'input2c.tsv'], sample3=['input3-filtered.tsv']) 

與真實sys.argv你可能不得不更換argv.count與稍長' '.join(sys.argv).count('--sample')

這種方法的主要缺點是自動幫助生成w生病不包括這些領域。

+1

您的代碼使用字符串'argv',但不能與已分割的'sys.argv'一起使用。幫助將列出命令行中給出的任何'sample#',以及'-h'。但是爲了顯示一個通用的'sample#',你必須使用一個自定義的'usage'參數。 – hpaulj