我的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()
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
但这对我来说似乎有点可疑 - 如果没有给出目录,它会传递一个不可读的目录,这似乎无法检查目录是否可以访问.
请注意,正如评论中指出的那样,它可能更好raise argparse.ArgumentError(self, ...)而不是argparse.ArgumentTypeError.
编辑
据我所知,没有办法验证默认参数.我想argparse开发人员只是假设如果你提供默认值,那么它应该是有效的.这里最快速,最简单的方法是在解析参数后立即验证参数.看起来,你只是想让一个临时目录做一些工作.如果是这种情况,您可以使用该tempfile模块获取一个新目录.我更新了上面的答案以反映这一点.我创建一个临时目录,使用它作为默认参数(tempfile已经保证它创建的目录是可写的)然后我注册它以在程序退出时删除.
Dan*_*ski 27
几个月前,我向Python标准库邮件列表提交了一个"路径参数"补丁.
使用此类PathType,您可以简单地指定以下参数类型以仅匹配现有目录 - 其他任何内容都将给出错误消息:
type = PathType(exists=True, type='dir')
Run Code Online (Sandbox Code Playgroud)
这是代码,可以很容易地修改为需要特定的文件/目录权限:
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
Run Code Online (Sandbox Code Playgroud)
jfs*_*jfs 13
如果您的脚本无法在没有有效的情况下工作launch_directory,则应将其作为必需参数:
parser.add_argument('launch_directory', type=readable_dir)
Run Code Online (Sandbox Code Playgroud)
顺便说一句,你应该使用argparse.ArgumentTypeError而不是Exceptionin readable_dir().
| 归档时间: |
|
| 查看次数: |
41085 次 |
| 最近记录: |