Skip to content

Instantly share code, notes, and snippets.

@TheMatt2
Last active October 20, 2023 00:42
Show Gist options
  • Save TheMatt2/2b7846b7a301ff2e99da6c1c7183bfc5 to your computer and use it in GitHub Desktop.
Save TheMatt2/2b7846b7a301ff2e99da6c1c7183bfc5 to your computer and use it in GitHub Desktop.
Simplier PathType object for helping parse argparse inputs. Takes up less lines of code and removes rarely used features (still present on pathtype_v2.py)
"""
Simplified PathType
- Simplify for common case
- Only one type, no more (never used really)
- No dash support, just simplier
- No symilnk (never used)
A helper type for input validation in argparse for paths.
This provides a convienent way to check the path type and existance.
This class is provided as an alternative to argparse.FileType(), which
does not open the path, only validates it and supports directories.
The way argparse.FileType() operates is problematic, as it can cause the
file descriptor to be left open if an error occurs. To quote the argparse
docs page:
https://docs.python.org/3/library/argparse.html
- If one argument uses FileType and then a subsequent argument fails,
an error is reported but the file is not automatically closed.
In this case, it would be better to wait until after the parser has
run and then use the with-statement to manage the files.
Example Usage:
parser = argparse.ArgumentParser()
# Add an argument that must be an existing file
parser.add_argument('existing_file', type = PathType(type='file', dexists = True))
# Add an argument for a folder that must NOT exist.
parser.add_argument('non_existant_folder', type = PathType(type='dir', exists = False))
"""
# Code from https://stackoverflow.com/questions/11415570/directory-path-types-with-argparse
#
# This was also suggested to be an official change to argparse.
# https://mail.python.org/pipermail/stdlib-sig/2015-July/000990.html
# Changed to using callable() function, instead of checking for __call__() method
# and changed err to ArgumentTypeError.
# Also fixed os.path.sympath() reference to os.path.islink().
import os
from argparse import ArgumentTypeError
class PathType:
def __init__(self, exists = True, type = "file"):
"""
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", None
If None, the type of file/directory/symlink is not checked.
"""
# Check type
if type not in ("file", "dir", None):
raise ValueError(f"type {type!r} is not a recognized file type")
# Check exists
if exists not in [True, False, None]:
raise TypeError("exists argument is not a bool or None")
self._exists = exists
self._type = type
def __call__(self, string):
"""
Check if string is a path of the requested type.
"""
if self._exists:
if not os.path.exists(string):
raise ArgumentTypeError(f"{self._type} does not exist: {string!r}")
if self._type == "file":
if not os.path.isfile(string):
raise ArgumentTypeError(f"path is not a file: {string!r}")
elif self._type == "dir":
if not os.path.isdir(string):
raise ArgumentTypeError(f"path is not a directory: {string!r}")
else:
# If the path should not exist
if self._exists == False and os.path.exists(string):
raise ArgumentTypeError(f"{self._type} exists: {string!r}")
# Make sure parent directory does exist
p = os.path.normpath(os.path.dirname(string))
if not os.path.exists(p):
raise ArgumentTypeError(f"parent directory does not exist: {p!r}")
elif not os.path.isdir(p):
raise ArgumentTypeError(f"parent path is not a directory: {p!r}")
return string
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment