Create new arparse_helpers with NonExitingParser and existing_file
authorChristian Herdtweck <christian.herdtweck@intra2net.com>
Fri, 15 Jun 2018 09:06:02 +0000 (11:06 +0200)
committerChristian Herdtweck <christian.herdtweck@intra2net.com>
Mon, 8 Oct 2018 07:33:52 +0000 (09:33 +0200)
src/argparse_helpers.py [new file with mode: 0644]

diff --git a/src/argparse_helpers.py b/src/argparse_helpers.py
new file mode 100644 (file)
index 0000000..e18a1c2
--- /dev/null
@@ -0,0 +1,81 @@
+# The software in this package is distributed under the GNU General
+# Public License version 2 (with a special exception described below).
+#
+# A copy of GNU General Public License (GPL) is included in this distribution,
+# in the file COPYING.GPL.
+#
+# As a special exception, if other files instantiate templates or use macros
+# or inline functions from this file, or you compile this file and link it
+# with other works to produce a work based on this file, this file
+# does not by itself cause the resulting work to be covered
+# by the GNU General Public License.
+#
+# However the source code for this file must still be made available
+# in accordance with section (3) of the GNU General Public License.
+#
+# This exception does not invalidate any other reasons why a work based
+# on this file might be covered by the GNU General Public License.
+
+"""
+argparse_helpers: Some convenience helpers for argparse
+
+Featuring
+- NonExitingParser: a subclass of ArgumentParser that does not do sys.exit(2)
+  on parse error but instead raises a ArgParserWantsExit exception.
+- function existing_file which can be used as a type in add_argument() calls
+
+.. codeauthor:: Intra2net
+"""
+
+from argparse import ArgumentParser, ArgumentTypeError
+from os.path import isfile
+
+
+class ArgParserWantsExit(Exception):
+    """
+    Exception raised from NonExitingParser instead of calling sys.exit(2).
+    """
+
+    def __init__(self, message):
+        super(ArgParserWantsExit, self).__init__("Error parsing args: " +
+                                                 message)
+
+
+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
+    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::
+
+        def main():
+            log = None
+            try:
+               log = create_log()
+               parser = NonExitingParser()
+               # ... add args ...
+               args = parser.parse_args()
+               # ... rest of your program ...
+            except Exception as exc:
+                log.error('uncaught exception: exc')  # will always show in log
+
+    """
+    def error(self, message):
+        """Called when error occurred parsing args. Raise error, not exit."""
+        raise ArgParserWantsExit(message)
+
+
+def existing_file(filename):
+    """
+    Function that raises ArgumentTypeError if argument is not an existing file.
+
+    Returns filename if it is valid.  Can be used as `type` argument in
+    :py:meth:`argparse.ArgumentParser.add_argument`
+
+    If you want to open the file, you can as well use the python built-in
+    :py:class:`argparse.FileType` instead.
+    """
+    if isfile(filename):
+        return filename
+    raise ArgumentTypeError('{} is not an existing file'.format(filename))