Make argparse utils' valid_date work with the default format of UNIX date.
[pyutils.git] / src / pyutils / argparse_utils.py
index d1e28ba80b2ae758a7a9bfd41ba91fcadfada26a..0ce429f1e4957b6c8d469ca555eb3f6f07147e7b 100644 (file)
@@ -49,21 +49,21 @@ class ActionNoYes(argparse.Action):
 
     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'
+            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 NoYes action'
+            msg = "Only single argument is allowed with NoYes action"
             logger.critical(msg)
             raise ValueError(msg)
         opt = option_strings[0]
-        if not opt.startswith('--'):
-            msg = 'Yes/No arguments must be prefixed with --'
+        if not opt.startswith("--"):
+            msg = "Yes/No arguments must be prefixed with --"
             logger.critical(msg)
             raise ValueError(msg)
 
         opt = opt[2:]
-        opts = ['--' + opt, '--no_' + opt]
+        opts = ["--" + opt, "--no_" + opt]
         super().__init__(
             opts,
             dest,
@@ -76,7 +76,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)
@@ -252,7 +252,7 @@ def valid_percentage(num: str) -> float:
     argparse.ArgumentTypeError: 115 is an invalid percentage; expected 0 <= n <= 100.0
 
     """
-    num = num.strip('%')
+    num = num.strip("%")
     n = float(num)
     if 0.0 <= n <= 100.0:
         return n
@@ -330,7 +330,8 @@ def valid_date(txt: str) -> datetime.date:
     .. note::
         dates like 'next wednesday' work fine, they are just
         hard to doctest for without knowing when the testcase will be
-        executed...
+        executed...  See :py:mod:`pyutils.datetimes.dateparse_utils`
+        for other examples of usable expressions.
 
     >>> valid_date('next wednesday') # doctest: +ELLIPSIS
     -ANYTHING-
@@ -340,7 +341,7 @@ def valid_date(txt: str) -> datetime.date:
     date = to_date(txt)
     if date is not None:
         return date
-    msg = f'Cannot parse argument as a date: {txt}'
+    msg = f"Cannot parse argument as a date: {txt}"
     logger.error(msg)
     raise argparse.ArgumentTypeError(msg)
 
@@ -369,10 +370,13 @@ def valid_datetime(txt: str) -> datetime.datetime:
     >>> valid_datetime('6/5/2021 3:01:02')
     datetime.datetime(2021, 6, 5, 3, 1, 2)
 
+    >>> valid_datetime('Sun Dec 11 11:50:00 PST 2022')
+    datetime.datetime(2022, 12, 11, 11, 50)
+
     .. note::
         Because this code uses an English date-expression parsing grammar
         internally, much more complex datetimes can be expressed in free form.
-        See: `tests/datetimez/dateparse_utils_test.py` for examples.  These
+        See :mod:`pyutils.datetimes.dateparse_utils` for details.  These
         are not included in here because they are hard to write valid doctests
         for!
 
@@ -384,7 +388,14 @@ def valid_datetime(txt: str) -> datetime.datetime:
     dt = to_datetime(txt)
     if dt is not None:
         return dt
-    msg = f'Cannot parse argument as datetime: {txt}'
+
+    # Don't choke on the default format of unix date.
+    try:
+        return datetime.datetime.strptime(txt, "%a %b %d %H:%M:%S %Z %Y")
+    except Exception:
+        pass
+
+    msg = f"Cannot parse argument as datetime: {txt}"
     logger.error(msg)
     raise argparse.ArgumentTypeError(msg)
 
@@ -438,7 +449,7 @@ def valid_duration(txt: str) -> datetime.timedelta:
     ...
     argparse.ArgumentTypeError: a little while is not a valid duration.
     """
-    from pyutils.datetimez.datetime_utils import parse_duration
+    from pyutils.datetimes.datetime_utils import parse_duration
 
     try:
         secs = parse_duration(txt, raise_on_error=True)
@@ -448,8 +459,8 @@ def valid_duration(txt: str) -> datetime.timedelta:
         raise argparse.ArgumentTypeError(e) from e
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     import doctest
 
-    doctest.ELLIPSIS_MARKER = '-ANYTHING-'
+    doctest.ELLIPSIS_MARKER = "-ANYTHING-"
     doctest.testmod()