Hammer on that run_tests.py thing again.
[python_utils.git] / argparse_utils.py
index 8c254ae1f995f6aa684134c595e35968ea5b36cd..f73a8936d3eb268b96ea387a543608d24d0ceb51 100644 (file)
@@ -1,5 +1,9 @@
 #!/usr/bin/python3
 
+# © Copyright 2021-2022, Scott Gasch
+
+"""Helpers for commandline argument parsing."""
+
 import argparse
 import datetime
 import logging
@@ -8,7 +12,6 @@ from typing import Any
 
 from overrides import overrides
 
-
 # This module is commonly used by others in here and should avoid
 # taking any unnecessary dependencies back on them.
 
@@ -16,15 +19,31 @@ logger = logging.getLogger(__name__)
 
 
 class ActionNoYes(argparse.Action):
-    def __init__(
-        self, option_strings, dest, default=None, required=False, help=None
-    ):
+    """An argparse Action that allows for commandline arguments like this::
+
+        cfg.add_argument(
+            '--enable_the_thing',
+            action=ActionNoYes,
+            default=False,
+            help='Should we enable the thing?'
+        )
+
+    This creates the following cmdline arguments::
+
+        --enable_the_thing
+        --no_enable_the_thing
+
+    These arguments can be used to indicate the inclusion or exclusion of
+    binary exclusive behaviors.
+    """
+
+    def __init__(self, option_strings, dest, default=None, required=False, help=None):
         if default is None:
             msg = 'You must provide a default with Yes/No action'
             logger.critical(msg)
             raise ValueError(msg)
         if len(option_strings) != 1:
-            msg = 'Only single argument is allowed with YesNo action'
+            msg = 'Only single argument is allowed with NoYes action'
             logger.critical(msg)
             raise ValueError(msg)
         opt = option_strings[0]
@@ -47,9 +66,7 @@ class ActionNoYes(argparse.Action):
 
     @overrides
     def __call__(self, parser, namespace, values, option_strings=None):
-        if option_strings.startswith('--no-') or option_strings.startswith(
-            '--no_'
-        ):
+        if option_strings.startswith('--no-') or option_strings.startswith('--no_'):
             setattr(namespace, self.dest, False)
         else:
             setattr(namespace, self.dest, True)
@@ -86,8 +103,8 @@ def valid_bool(v: Any) -> bool:
 
     try:
         return to_bool(v)
-    except Exception:
-        raise argparse.ArgumentTypeError(v)
+    except Exception as e:
+        raise argparse.ArgumentTypeError(v) from e
 
 
 def valid_ip(ip: str) -> str:
@@ -252,10 +269,10 @@ def valid_duration(txt: str) -> datetime.timedelta:
 
     try:
         secs = parse_duration(txt)
-    except Exception as e:
-        raise argparse.ArgumentTypeError(e)
-    finally:
         return datetime.timedelta(seconds=secs)
+    except Exception as e:
+        logger.exception(e)
+        raise argparse.ArgumentTypeError(e) from e
 
 
 if __name__ == '__main__':