2012-08-16 74 views
2

這個簡化的腳本足以導致問題......只是檢查'-d'參數是否是一個有效的目錄,如果沒有提供默認值,則提供默認值。 。argparse.add_argument()默認總是使用...有時

#!/usr/bin/python 

import os 
import argparse 

def valid(dir): 
    subdir = dir + '/Desktop' 
    if not os.path.exists(subdir): 
     raise argparse.ArgumentTypeError("%s is not a valid directory" % subdir) 
    return dir 

parser = argparse.ArgumentParser(description="blah blah blah") 
parser.add_argument('-d', '--directory', help='directory to check', default=os.getcwd(), type=valid) 
args = parser.parse_args() 

而且不要緊默認參數是什麼,當我運行它使用默認的,不管我在命令行中輸入,並如下拋出一個未捕獲的異常腳本:

Traceback (most recent call last): 
    File "./parsertest.py", line 15, in <module> 
    args = parser.parse_args() 
    File "/usr/lib/python2.7/argparse.py", line 1688, in parse_args 
    args, argv = self.parse_known_args(args, namespace) 
    File "/usr/lib/python2.7/argparse.py", line 1710, in parse_known_args 
    default = self._get_value(action, default) 
    File "/usr/lib/python2.7/argparse.py", line 2239, in _get_value 
    raise ArgumentError(action, msg) 
argparse.ArgumentError: argument -d/--directory: /home/users/jrice/Desktop/Desktop is not a valid directory 

運行良好,我的意思是,處理ArgumentTypeError時,它應該,只是打印味精的時候,如果我做到以下幾點:

  1. 刪除「默認=」參數
  2. 不要追加「/桌面」來目錄,所以子目錄=目錄,或只檢查目錄本身
  3. 運行我的主目錄中的腳本!?!?

詳細說明:如果我做了上述任何一項,即使'-d'無效,一切都很好。這是輸出,這是我想要的。

>./Desktop/parsertest.py -d blah 
usage: parsertest.py [-h] [-d DIRECTORY] 
parsertest.py: error: argument -d/--directory: blah/Desktop is not a valid directory 

爲什麼os.getcwd()+'/ Desktop'有什麼不同?

回答

2

Argparse會嘗試將默認參數轉換爲賦給它的任何類型。

import argparse 

parser = argparse.ArgumentParser(description="blah blah blah") 
parser.add_argument('-i',default="1",type=int) 

args = parser.parse_args([]) 
print args   # Namespace(i=1) 
print type(args.i) # <type 'int'> 

這樣做的原因設計選擇是有點怪我,但它可能是讓你可以通過字符串default只是因爲這將讓他們在命令行,然後幫助將正確的格式。

注意我並不喜歡將驗證代碼傳遞給type關鍵字參數,即使他們在documentation中這樣做。該參數是將輸入字符串轉換爲其他類型。如果你真的想這樣做,你解析驗證,你應該考慮使用自定義Action,但在這個例子中,它可能只是最容易做的:

#...snip... 
parser.add_argument('-d', '--directory', help='directory to check') 
args = parser.parse_args() 
args.directory = valid(args.directory if args.directory is not None else os.getcwd()) 
#the following should work too. 
#args.directory = valid(args.directory if args.directory else os.getcwd()) 
+0

只要將驗證代碼傳遞給type關鍵字就沒有意義,這裏記錄它[http://docs.python.org/library/argparse.html#type],如果我對此有所瞭解,並且您認爲是正確的。 – 2012-08-16 16:20:54

+0

@JimiChanga - 我不太喜歡那個例子,但你是對的。它*可以*用於類型檢查,但只有在可以通過默認值的情況下才能保證。在他們的'perfect_square'的例子中,輸入參數是一個位置參數,這意味着它是**必需的**。在這種情況下,同時進行轉換和檢查是有意義的,因爲它們有保證要檢查的東西。當然,這提出了一個問題,如果'os.getcwd()'沒有'Desktop'子目錄會發生什麼?爲什麼這個特例要通過? – mgilson 2012-08-16 16:28:46

+0

@JimiChanga - 我根據你的鏈接稍微更新了我的答案。謝謝。 – mgilson 2012-08-16 16:32:00

3

我相信你的「類型檢查」太過分了。你把一個不存在的目錄視爲無效的類型,這不是​​的想法。在你的情況下,默認值可能不是一個混淆argparse的「有效類型」。看看下面的代碼和它的輸出:

#!/usr/bin/python 

import os 
import argparse 

def valid(dir): 
    print "Checking " + dir 
    subdir = dir + '/Desktop' 
    #if not os.path.exists(subdir): 
    # raise argparse.ArgumentTypeError("%s is not a valid directory" % subdir) 
    return dir 

parser = argparse.ArgumentParser(description="blah blah blah") 
parser.add_argument('-d', '--directory', help='directory to check', type=valid, default=os.getcwd()) 
args = parser.parse_args() 

/home/user/Desktop-d /home/user執行它給:

Checking /home/user/Desktop 
Checking /home/user 

正如你所看到的,​​首先將默認值,然後才命令行給出值。

要解決上述問題,請確保默認值始終爲「有效類型」,或者在​​完成後檢查目錄。

+0

感謝您的幫助!不要緊,如果它是一個有效的類型操作系統。即使/ tmp有效,getcwd()應該總是返回一個有效的目錄,'default =/tmp'也會做同樣的事情。 – 2012-08-16 19:15:20

+0

實際上,假設os.getcwd()總是返回一個有效的目錄是不正確的。有時它會引發FileNotFoundError。考慮一下當我創建一個目錄/ tmp/foo,「cd」給它並啓動'python'時會發生什麼。我檢查'os.getcwd()'返回''/ tmp/foo''。然後我切換到另一個終端和'rmdir/tmp/foo'。當我在Python會話中調用它時,'os.getcwd()'現在會引發FileNotFoundError。 – kampu 2013-05-21 13:53:54