[stdlib-sig] argparse PathType class -- validate file/directory paths without opening them
Dan Lenski
dlenski at gmail.com
Wed Jul 22 22:25:38 CEST 2015
Hi,
The standard argparse library supports a convenient FileType class
(https://docs.python.org/3/library/argparse.html#filetype-objects)
which automatically converts file paths to open filehandles.
I've found that I frequently need to validate that arguments
correspond to valid file or directory paths, but WITHOUT
subsequently opening these paths as files.
This is useful when the path has to be subsequently passed off to
another program via subprocess, etc.
To support this case, I wrote the following PathType class, which
will validate the suitability of a path for the specified usage
(e.g. directory that exists, file that doesn't exist, etc.) before
returning it unchanged.
Would this be useful for inclusion in the standard library? Any comments
on style, parameter-naming, etc?
Thanks,
Dan Lenski
# standalone pathtype.py
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
More information about the stdlib-sig
mailing list