我的python脚本需要从命令行传递的目录中读取文件.我已经定义了一个如下所示的readable_dir类型,用于与argparse一起验证在命令行上传递的目录是否存在且可读.此外,还为directory参数指定了默认值(下例中的/ tmp/non_existent_dir).这里的问题是argparse在默认值上调用readable_dir(),即使在命令行中显式传入目录参数的情况下也是如此.这会导致脚本丢失,因为在命令行上显式传入目录的上下文中不存在缺省路径/ tmp/non_existent_dir.我可以通过不指定默认值并强制使用此参数,或者通过将验证推迟到脚本中的后期来解决这个问题,但这是一个更优雅的解决方案,任何人都知道吗?
#!/usr/bin/python
import argparse
import os
def readable_dir(prospective_dir):
  if not os.path.isdir(prospective_dir):
    raise Exception("readable_dir:{0} is not a valid path".format(prospective_dir))
  if os.access(prospective_dir, os.R_OK):
    return prospective_dir
  else:
    raise Exception("readable_dir:{0} is not a readable dir".format(prospective_dir))
parser = argparse.ArgumentParser(description='test', fromfile_prefix_chars="@")
parser.add_argument('-l', '--launch_directory', type=readable_dir, default='/tmp/non_existent_dir')
args = parser.parse_args()
mgi*_*son 35
您可以创建自定义操作而不是类型:
import argparse
import os
import tempfile
import shutil
import atexit
class readable_dir(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        prospective_dir=values
        if not os.path.isdir(prospective_dir):
            raise argparse.ArgumentTypeError("readable_dir:{0} is not a valid path".format(prospective_dir))
        if os.access(prospective_dir, os.R_OK):
            setattr(namespace,self.dest,prospective_dir)
        else:
            raise argparse.ArgumentTypeError("readable_dir:{0} is not a readable dir".format(prospective_dir))
ldir = tempfile.mkdtemp()
atexit.register(lambda dir=ldir: shutil.rmtree(ldir))
parser = argparse.ArgumentParser(description='test', fromfile_prefix_chars="@")
parser.add_argument('-l', '--launch_directory', action=readable_dir, default=ldir)
args = parser.parse_args()
print (args)
但这对我来说似乎有点可疑 - 如果没有给出目录,它会传递一个不可读的目录,这似乎无法检查目录是否可以访问.
请注意,正如评论中指出的那样,它可能更好raise argparse.ArgumentError(self, ...)而不是argparse.ArgumentTypeError.
编辑
据我所知,没有办法验证默认参数.我想argparse开发人员只是假设如果你提供默认值,那么它应该是有效的.这里最快速,最简单的方法是在解析参数后立即验证参数.看起来,你只是想让一个临时目录做一些工作.如果是这种情况,您可以使用该tempfile模块获取一个新目录.我更新了上面的答案以反映这一点.我创建一个临时目录,使用它作为默认参数(tempfile已经保证它创建的目录是可写的)然后我注册它以在程序退出时删除.
Dan*_*ski 27
几个月前,我向Python标准库邮件列表提交了一个"路径参数"补丁.
使用此类PathType,您可以简单地指定以下参数类型以仅匹配现有目录 - 其他任何内容都将给出错误消息:
type = PathType(exists=True, type='dir')
这是代码,可以很容易地修改为需要特定的文件/目录权限:
from argparse import ArgumentTypeError as err
import os
class PathType(object):
    def __init__(self, exists=True, type='file', dash_ok=True):
        '''exists:
                True: a path that does exist
                False: a path that does not exist, in a valid parent directory
                None: don't care
           type: file, dir, symlink, None, or a function returning True for valid paths
                None: don't care
           dash_ok: whether to allow "-" as stdin/stdout'''
        assert exists in (True, False, None)
        assert type in ('file','dir','symlink',None) or hasattr(type,'__call__')
        self._exists = exists
        self._type = type
        self._dash_ok = dash_ok
    def __call__(self, string):
        if string=='-':
            # the special argument "-" means sys.std{in,out}
            if self._type == 'dir':
                raise err('standard input/output (-) not allowed as directory path')
            elif self._type == 'symlink':
                raise err('standard input/output (-) not allowed as symlink path')
            elif not self._dash_ok:
                raise err('standard input/output (-) not allowed')
        else:
            e = os.path.exists(string)
            if self._exists==True:
                if not e:
                    raise err("path does not exist: '%s'" % string)
                if self._type is None:
                    pass
                elif self._type=='file':
                    if not os.path.isfile(string):
                        raise err("path is not a file: '%s'" % string)
                elif self._type=='symlink':
                    if not os.path.symlink(string):
                        raise err("path is not a symlink: '%s'" % string)
                elif self._type=='dir':
                    if not os.path.isdir(string):
                        raise err("path is not a directory: '%s'" % string)
                elif not self._type(string):
                    raise err("path not valid: '%s'" % string)
            else:
                if self._exists==False and e:
                    raise err("path exists: '%s'" % string)
                p = os.path.dirname(os.path.normpath(string)) or '.'
                if not os.path.isdir(p):
                    raise err("parent path is not a directory: '%s'" % p)
                elif not os.path.exists(p):
                    raise err("parent directory does not exist: '%s'" % p)
        return string
jfs*_*jfs 13
如果您的脚本无法在没有有效的情况下工作launch_directory,则应将其作为必需参数:
parser.add_argument('launch_directory', type=readable_dir)
顺便说一句,你应该使用argparse.ArgumentTypeError而不是Exceptionin readable_dir().