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