aiee

Python modules for common command line interfacing utils
git clone git://git.defalsify.org/aiee.git
Log | Files | Refs | LICENSE

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