From: Christian Herdtweck Date: Fri, 1 Apr 2022 11:29:19 +0000 (+0200) Subject: Create argparse type "existing_dir[_empty]" X-Git-Tag: v1.7.1~9 X-Git-Url: http://developer.intra2net.com/git/?p=pyi2ncommon;a=commitdiff_plain;h=f02ce4ca6f4c3469014bc9bee8d353c6997be10a Create argparse type "existing_dir[_empty]" Programs often have a file or dir as argument, check in argparse right away whether that actually exists. Optionally, accept an empty value to use a default value. --- diff --git a/src/argparse_helpers.py b/src/argparse_helpers.py index 91e64d2..93e4bad 100644 --- a/src/argparse_helpers.py +++ b/src/argparse_helpers.py @@ -28,7 +28,7 @@ Featuring """ from argparse import ArgumentParser, ArgumentTypeError -from os.path import isfile +from os.path import isfile, isdir class ArgParserWantsExit(Exception): @@ -44,7 +44,7 @@ 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:: @@ -88,3 +88,23 @@ def existing_file_or_empty(filename=''): 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) diff --git a/test/test_argparse_helpers.py b/test/test_argparse_helpers.py index 175219e..f0c77e2 100644 --- a/test/test_argparse_helpers.py +++ b/test/test_argparse_helpers.py @@ -27,8 +27,9 @@ For help see :py:mod:`unittest` 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: @@ -61,6 +62,8 @@ class ArgparseTester(unittest.TestCase): # 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) @@ -73,5 +76,45 @@ class ArgparseTester(unittest.TestCase): 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()