2012-08-16 206 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