"""
from argparse import ArgumentParser, ArgumentTypeError
-from os.path import isfile
+from os.path import isfile, isdir
class ArgParserWantsExit(Exception):
class NonExitingParser(ArgumentParser):
"""ArgumentParser that does not call sys.exit(2) on parse failure.
- Calling sys.exit also just raises a SystemExit exception. But that is not
+ Calling `sys.exit` also just raises a SystemExit exception. But that is not
a subclass of Exception and not as explicit and specific as this one.
Convenient e.g. for global try-except blocks e.g. in a daemon::
if not filename.strip():
return ''
return existing_file(filename)
+
+
+def existing_dir(path):
+ """
+ Function that raises ArgumentTypeError if argument is not an existing directory.
+
+ .. seealso:: :py:func:`existing_file`, :py:func:`existing_dir_or_empty`
+ """
+ if isdir(path):
+ return path
+ raise ArgumentTypeError('{} is not an existing directory'.format(path))
+
+
+def existing_dir_or_empty(path=''):
+ """
+ Like :py:func:`existing_dir` but accepts empty path (returns '' then).
+ """
+ if not path.strip():
+ return ''
+ return existing_dir(path)
import unittest
import os
-from os.path import isfile
-from tempfile import mkstemp
+from os.path import isfile, isdir
+from shutil import rmtree
+from tempfile import mkstemp, mkdtemp
# relative import of tested module ensures we do not test installed version
try:
# test with existing file
parser = argparse_helpers.NonExitingParser()
parser.add_argument('--input', type=argparse_helpers.existing_file)
+ parser.add_argument('--input2', type=argparse_helpers.existing_file_or_empty)
+ parser.parse_args(['--input', temp_file, '--input2', temp_file])
finally:
if temp_handle:
os.close(temp_handle)
parser.parse_args,
['--input', temp_file, ])
+ def test_existing_dir(self):
+ temp_dir = None
+ try:
+ # create a dir
+ temp_dir = mkdtemp()
+
+ # test with existing dir
+ parser = argparse_helpers.NonExitingParser()
+ parser.add_argument('--input', type=argparse_helpers.existing_dir)
+ parser.add_argument('--input2', type=argparse_helpers.existing_dir_or_empty)
+ parser.parse_args(['--input', temp_dir, '--input2', temp_dir])
+ finally:
+ if temp_dir and isdir(temp_dir):
+ rmtree(temp_dir)
+
+ # test with non-existing dir
+ self.assertRaisesRegex(argparse_helpers.ArgParserWantsExit,
+ 'is not an existing directory',
+ parser.parse_args,
+ ['--input', temp_dir, ])
+
+ def test_allow_empty(self):
+ parser = argparse_helpers.NonExitingParser()
+ parser.add_argument('--file', type=argparse_helpers.existing_file_or_empty)
+ parser.add_argument('--dir', type=argparse_helpers.existing_dir_or_empty)
+
+ # both emtpy: no problem
+ parser.parse_args(['--file', '', '--dir', ''])
+
+ # test with non-existing file/dir
+ self.assertRaisesRegex(argparse_helpers.ArgParserWantsExit,
+ 'is not an existing file',
+ parser.parse_args,
+ ['--dir', '', '--file', 'not-an-existing-file'])
+ self.assertRaisesRegex(argparse_helpers.ArgParserWantsExit,
+ 'is not an existing directory',
+ parser.parse_args,
+ ['--file', '', '--dir', 'not-an-existing-dir'])
+
+
if __name__ == '__main__':
unittest.main()