X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=argparse_utils.py;h=0ee2be9f8017093caeff732962ad9b4d10a993e7;hb=c41e0e59446412511c5737cf5b6ba8f289e75e7e;hp=3799a47ccbc1a34a599cdd443eaf5dfa33a64772;hpb=09e6d10face80d98a4578ff54192b5c8bec007d7;p=python_utils.git diff --git a/argparse_utils.py b/argparse_utils.py index 3799a47..0ee2be9 100644 --- a/argparse_utils.py +++ b/argparse_utils.py @@ -4,6 +4,7 @@ import argparse import datetime import logging import os +from typing import Any # This module is commonly used by others in here and should avoid # taking any unnecessary dependencies back on them. @@ -56,14 +57,54 @@ class ActionNoYes(argparse.Action): setattr(namespace, self.dest, True) -def valid_bool(v): +def valid_bool(v: Any) -> bool: + """ + If the string is a valid bool, return its value. + + >>> valid_bool(True) + True + + >>> valid_bool("true") + True + + >>> valid_bool("yes") + True + + >>> valid_bool("on") + True + + >>> valid_bool("1") + True + + >>> valid_bool(12345) + Traceback (most recent call last): + ... + argparse.ArgumentTypeError: 12345 + + """ if isinstance(v, bool): return v from string_utils import to_bool - return to_bool(v) + try: + return to_bool(v) + except Exception: + raise argparse.ArgumentTypeError(v) def valid_ip(ip: str) -> str: + """ + If the string is a valid IPv4 address, return it. Otherwise raise + an ArgumentTypeError. + + >>> valid_ip("1.2.3.4") + '1.2.3.4' + + >>> valid_ip("localhost") + Traceback (most recent call last): + ... + argparse.ArgumentTypeError: localhost is an invalid IP address + + """ from string_utils import extract_ip_v4 s = extract_ip_v4(ip.strip()) if s is not None: @@ -74,6 +115,22 @@ def valid_ip(ip: str) -> str: def valid_mac(mac: str) -> str: + """ + If the string is a valid MAC address, return it. Otherwise raise + an ArgumentTypeError. + + >>> valid_mac('12:23:3A:4F:55:66') + '12:23:3A:4F:55:66' + + >>> valid_mac('12-23-3A-4F-55-66') + '12-23-3A-4F-55-66' + + >>> valid_mac('big') + Traceback (most recent call last): + ... + argparse.ArgumentTypeError: big is an invalid MAC address + + """ from string_utils import extract_mac_address s = extract_mac_address(mac) if s is not None: @@ -84,6 +141,22 @@ def valid_mac(mac: str) -> str: def valid_percentage(num: str) -> float: + """ + If the string is a valid percentage, return it. Otherwise raise + an ArgumentTypeError. + + >>> valid_percentage("15%") + 15.0 + + >>> valid_percentage('40') + 40.0 + + >>> valid_percentage('115') + Traceback (most recent call last): + ... + argparse.ArgumentTypeError: 115 is an invalid percentage; expected 0 <= n <= 100.0 + + """ num = num.strip('%') n = float(num) if 0.0 <= n <= 100.0: @@ -94,6 +167,19 @@ def valid_percentage(num: str) -> float: def valid_filename(filename: str) -> str: + """ + If the string is a valid filename, return it. Otherwise raise + an ArgumentTypeError. + + >>> valid_filename('/tmp') + '/tmp' + + >>> valid_filename('wfwefwefwefwefwefwefwefwef') + Traceback (most recent call last): + ... + argparse.ArgumentTypeError: wfwefwefwefwefwefwefwefwef was not found and is therefore invalid. + + """ s = filename.strip() if os.path.exists(s): return s @@ -103,6 +189,18 @@ def valid_filename(filename: str) -> str: def valid_date(txt: str) -> datetime.date: + """If the string is a valid date, return it. Otherwise raise + an ArgumentTypeError. + + >>> valid_date('6/5/2021') + datetime.date(2021, 6, 5) + + # Note: dates like 'next wednesday' work fine, they are just + # hard to test for without knowing when the testcase will be + # executed... + >>> valid_date('next wednesday') # doctest: +ELLIPSIS + -ANYTHING- + """ from string_utils import to_date date = to_date(txt) if date is not None: @@ -113,6 +211,18 @@ def valid_date(txt: str) -> datetime.date: def valid_datetime(txt: str) -> datetime.datetime: + """If the string is a valid datetime, return it. Otherwise raise + an ArgumentTypeError. + + >>> valid_datetime('6/5/2021 3:01:02') + datetime.datetime(2021, 6, 5, 3, 1, 2) + + # Again, these types of expressions work fine but are + # difficult to test with doctests because the answer is + # relative to the time the doctest is executed. + >>> valid_datetime('next christmas at 4:15am') # doctest: +ELLIPSIS + -ANYTHING- + """ from string_utils import to_datetime dt = to_datetime(txt) if dt is not None: @@ -120,3 +230,9 @@ def valid_datetime(txt: str) -> datetime.datetime: msg = f'Cannot parse argument as datetime: {txt}' logger.warning(msg) raise argparse.ArgumentTypeError(msg) + + +if __name__ == '__main__': + import doctest + doctest.ELLIPSIS_MARKER = '-ANYTHING-' + doctest.testmod()