02db0f08e762e9a430c9f03f7ce08a4a0acdb7b6
[python_utils.git] / argparse_utils.py
1 #!/usr/bin/python3
2
3 import argparse
4 import datetime
5 import logging
6 import os
7
8 logger = logging.getLogger(__name__)
9
10
11 class ActionNoYes(argparse.Action):
12     def __init__(
13             self,
14             option_strings,
15             dest,
16             default=None,
17             required=False,
18             help=None
19     ):
20         if default is None:
21             msg = 'You must provide a default with Yes/No action'
22             logger.critical(msg)
23             raise ValueError(msg)
24         if len(option_strings) != 1:
25             msg = 'Only single argument is allowed with YesNo action'
26             logger.critical(msg)
27             raise ValueError(msg)
28         opt = option_strings[0]
29         if not opt.startswith('--'):
30             msg = 'Yes/No arguments must be prefixed with --'
31             logger.critical(msg)
32             raise ValueError(msg)
33
34         opt = opt[2:]
35         opts = ['--' + opt, '--no_' + opt]
36         super().__init__(
37             opts,
38             dest,
39             nargs=0,
40             const=None,
41             default=default,
42             required=required,
43             help=help
44         )
45
46     def __call__(self, parser, namespace, values, option_strings=None):
47         if (
48                 option_strings.startswith('--no-') or
49                 option_strings.startswith('--no_')
50         ):
51             setattr(namespace, self.dest, False)
52         else:
53             setattr(namespace, self.dest, True)
54
55
56 def valid_bool(v):
57     if isinstance(v, bool):
58         return v
59     from string_utils import to_bool
60     return to_bool(v)
61
62
63 def valid_ip(ip: str) -> str:
64     from string_utils import extract_ip_v4
65     s = extract_ip_v4(ip.strip())
66     if s is not None:
67         return s
68     msg = f"{ip} is an invalid IP address"
69     logger.warning(msg)
70     raise argparse.ArgumentTypeError(msg)
71
72
73 def valid_mac(mac: str) -> str:
74     from string_utils import extract_mac_address
75     s = extract_mac_address(mac)
76     if s is not None:
77         return s
78     msg = f"{mac} is an invalid MAC address"
79     logger.warning(msg)
80     raise argparse.ArgumentTypeError(msg)
81
82
83 def valid_percentage(num: str) -> float:
84     num = num.strip('%')
85     n = float(num)
86     if 0.0 <= n <= 100.0:
87         return n
88     msg = f"{num} is an invalid percentage; expected 0 <= n <= 100.0"
89     logger.warning(msg)
90     raise argparse.ArgumentTypeError(msg)
91
92
93 def valid_filename(filename: str) -> str:
94     s = filename.strip()
95     if os.path.exists(s):
96         return s
97     msg = f"{filename} was not found and is therefore invalid."
98     logger.warning(msg)
99     raise argparse.ArgumentTypeError(msg)
100
101
102 def valid_date(txt: str) -> datetime.date:
103     from string_utils import to_date
104     date = to_date(txt)
105     if date is not None:
106         return date
107     msg = f'Cannot parse argument as a date: {txt}'
108     logger.warning(msg)
109     raise argparse.ArgumentTypeError(msg)
110
111
112 def valid_datetime(txt: str) -> datetime.datetime:
113     from string_utils import to_datetime
114     dt = to_datetime(txt)
115     if dt is not None:
116         return dt
117     msg = f'Cannot parse argument as datetime: {txt}'
118     logger.warning(msg)
119     raise argparse.ArgumentTypeError(msg)