arg.py (6807B)
1 # standard import 2 import re 3 4 5 re_name = r'^[a-zA-Z_\.]+$' 6 re_arg = r'^[a-zA-Z][a-zA-z\-]+$' 7 re_dest = r'^[a-zA-Z_]+$' 8 9 def to_key(v): 10 if not re.match(re_name, v): 11 raise ValueError('invalid key {}'.format(v)) 12 return v.upper() 13 14 15 class ArgFlag: 16 17 def __init__(self): 18 self.__pure = [] 19 self.__alias = [] 20 self.__reverse = {} 21 self.__c = 1 22 self.__all = 0 23 24 25 @property 26 def all(self): 27 return self.__all 28 29 30 def __iter__(self): 31 r = {} 32 for v in self.__pure: 33 yield v, self.val(v) 34 for k in self.__alias: 35 v = self.val(k) 36 k += '=' + ','.join(self.names(v)) 37 yield k, v 38 return r 39 40 41 def val(self, v): 42 if isinstance(v, int): 43 if self.__reverse.get(v) == None: 44 raise ValueError('not a valid flag value: {}'.format(v)) 45 return v 46 k = to_key(v) 47 return getattr(self, k) 48 49 50 def add(self, k): 51 k = to_key(k) 52 if getattr(self, k, False): 53 raise ValueError('key exists: {}'.format(k)) 54 setattr(self, k, self.__c) 55 self.__pure.append(k) 56 self.__reverse[self.__c] = k 57 self.__c <<= 1 58 self.__all = self.__c - 1 59 60 61 def have_all(self, v): 62 if v & self.__all != v: 63 raise ValueError('missing flag {} in {}'.format(v, self.__all)) 64 return v 65 66 67 def match(self, k, v): 68 k = to_key(k) 69 return getattr(self, k) & v > 0 70 71 72 def alias(self, k, *args): 73 k = to_key(k) 74 if getattr(self, k, False): 75 raise ValueError('key exists: {}'.format(k)) 76 r = 0 77 for v in args: 78 r |= self.val(v) 79 r = self.have_all(r) 80 setattr(self, k, r) 81 self.__alias.append(k) 82 self.__reverse[r] = k 83 84 85 def less(self, k, v): 86 try: 87 k = to_key(k) 88 flags = getattr(self, k) 89 except TypeError: 90 flags = k 91 try: 92 vv = to_key(v) 93 v = getattr(self, vv) 94 except TypeError: 95 pass 96 mask = ~(self.__all & v) 97 r = flags & mask 98 return r 99 100 101 def more(self, k, v): 102 try: 103 k = to_key(k) 104 flags = getattr(self, k) 105 except TypeError: 106 flags = k 107 try: 108 vv = to_key(v) 109 v = getattr(self, vv) 110 except TypeError: 111 pass 112 113 return flags | v 114 115 116 def names(self, flags): 117 flags_debug = [] 118 c = 1 119 i = 0 120 while c < self.__c: 121 if flags & c > 0: 122 k = self.__pure[i] 123 flags_debug.append(k) 124 c <<= 1 125 i += 1 126 return flags_debug 127 128 129 def get(self, k): 130 k = to_key(k) 131 v = getattr(self, k) 132 return self.val(v) 133 134 135 class Arg: 136 137 def __init__(self, flags): 138 self.__flags = flags 139 self.__v = {} 140 self.__long = {} 141 self.__k = [] 142 self.__l = [] 143 self.__dest = {} 144 self.__x = {} 145 self.__crsr = 0 146 self.__typ = {} 147 self.__z = 0 148 149 150 def add(self, k, v, check=True, typ=str, dest=None, **kwargs): 151 if len(k) != 1 and check: 152 raise ValueError('short flag must have length 1, got "{}"'.format(k)) 153 v = self.__flags.val(v) 154 if self.__v.get(v) == None: 155 self.__v[v] = [] 156 self.__v[v].append(k) 157 self.__z |= v 158 self.__k.append(k) 159 if dest != None: 160 if not re.match(re_dest, dest): 161 raise ValueError('invalid destination name: {}'.format(dest)) 162 else: 163 dest = k 164 self.__dest[k] = dest 165 166 self.__x[k] = kwargs 167 self.__typ[k] = typ 168 169 170 def add_long(self, k, v, typ=str, dest=None, **kwargs): 171 v = self.__flags.val(v) 172 if self.__v.get(v) == None: 173 self.__v[v] = [] 174 self.__v[v].append(k) 175 self.__z |= v 176 self.__l.append(k) 177 if dest != None: 178 if not re.match(re_dest, dest): 179 raise ValueError('invalid destination name: {}'.format(dest)) 180 self.__dest[k] = dest 181 182 self.__x[k] = kwargs 183 self.__typ[k] = typ 184 185 186 def set_long(self, short, long, dest=None): 187 if not re.match(re_arg, long): 188 raise ValueError('invalid flag name: {}'.format(long)) 189 if short not in self.__k: 190 raise ValueError('unknown short flag: {}'.format(long)) 191 self.__long[short] = long 192 193 if dest != None: 194 if not re.match(re_dest, dest): 195 raise ValueError('invalid destination name: {}'.format(dest)) 196 self.__dest[short] = dest 197 198 199 def get(self, k): 200 k = self.__flags.val(k) 201 r = [] 202 for v in self.__v[k]: 203 long = None 204 short = None 205 if v in self.__l: 206 long = '--' + v 207 else: 208 long = self.__long.get(v) 209 if long != None: 210 long = '--' + long 211 short = '-' + v 212 dest = self.__dest[v] 213 typ = self.__typ[v] 214 r.append((short, long, dest, typ,)) 215 return r 216 217 218 def val(self, k): 219 return self.__flags.get(k) 220 221 222 def match(self, k, v_cmp, negate=False): 223 k = to_key(k) 224 v = self.__flags.val(k) 225 if v == 0: 226 return False 227 r = 0 228 if not negate: 229 r = (v & self.__z & v_cmp) 230 return r == v 231 232 233 def __iter__(self): 234 self.__crsr = 1 235 return self 236 237 238 def __next__(self): 239 while True: 240 v = None 241 try: 242 v = self.__flags.val(self.__crsr) 243 except ValueError: 244 self.__crsr = 0 245 if self.__crsr == 0: 246 raise StopIteration() 247 248 v = self.__crsr 249 self.__crsr <<= 1 250 if self.__v.get(v) != None: 251 return v 252 253 254 def kwargs(self, k): 255 return self.__x.get(k, {}) 256 257 258 def process_args(argparser, args, flags): 259 for flag in args: 260 261 if flag & flags == 0: 262 continue 263 264 for (short, long, dest, typ,) in args.get(flag): 265 266 kw = {} 267 try: 268 kw = args.kwargs(short[1:]) 269 except TypeError: 270 kw = args.kwargs(long[2:]) 271 272 if typ == bool: 273 kw['action'] = 'store_true' 274 else: 275 kw['type'] = typ 276 kw['dest'] = dest 277 278 if long == None: 279 argparser.add_argument(short, **kw) 280 elif short == None: 281 argparser.add_argument(long, **kw) 282 else: 283 argparser.add_argument(short, long, **kw) 284 285 return argparser