diff --git a/tools/python/jwutils/Options.py b/tools/python/jwutils/Options.py index a2e7732..1b19d66 100644 --- a/tools/python/jwutils/Options.py +++ b/tools/python/jwutils/Options.py @@ -1,28 +1,44 @@ import re import json from collections import OrderedDict -from . import log +from .log import * import shlex class Options: # export - def __parse_json(self, spec): + class OrderedData: + + def __init__(self, pairs = None): + self.__pairs = [] if pairs is None else pairs + + def add(self, lhs, rhs): + self.__pairs.append((lhs, rhs)) + + def dump(self): + for p in self.__pairs: + print(p) + + @property + def pairs(self): + return self.__pairs + + def __parse_json(self, spec, cls): spec = spec.strip() if len(spec) < 3: return None if spec[0] != '{': spec = '{' + spec + '}' try: - return json.loads(spec, object_pairs_hook=OrderedDict) + return json.loads(spec, object_pairs_hook=cls) except: pass return None - def __parse(self, opts_str): - r = self.__parse_json(opts_str) + def __parse(self, opts_str, cls): + r = self.__parse_json(opts_str, cls) if r is not None: return r - r = OrderedDict() + r = cls() opt_strs = shlex.split(opts_str) for opt_str in opt_strs: opt_str = re.sub('\s*=\s*', '=', opt_str) @@ -33,13 +49,31 @@ class Options: # export if self.__allowed_keys and not lhs in self.__allowed_keys: raise Exception('Field "{}" not supported'.format(lhs)) rhs = ' '.join(sides[1:]).strip() if len(sides) > 1 else self.__true_val - r[lhs] = rhs + if cls == OrderedDict: + r[lhs] = rhs + elif cls == self.OrderedData: + r.add(lhs, rhs) return r def __recache(self): self.__list.clear() - self.__list = list(self.__dict) - self.__str = str(dict(self.__dict)) + self.__dict.clear() + for key, val in self.__data.pairs: + self.__list.append(key) + if key not in self.__dict.keys(): + self.__dict[key] = val + else: + cur = self.__dict[key] + if isinstance(cur, str): + cur = [cur, val] + elif isinstance(cur, set): + cur.add(val) + elif isinstance(cur, list): + cur.append(val) + else: + cur = [cur, val] + self.__dict[key] = cur + self.__str = self.__str__() def __getitem__(self, key): if not key in self.__dict.keys(): @@ -47,16 +81,16 @@ class Options: # export return self.__dict[key] def __str__(self): - return self.__str + return ', '.join(str(p[0]) + ': ' + str(p[1]) for p in self.__data.pairs) def __repr__(self): - return self.__str + return self.__str__() def __format__(self, fmt): - return self.__str + return self.__str__() def __len__(self): - return len(self.__list) + return len(self.__data.pairs) def __contains__(self, keys): if not type(keys) in [list, set]: @@ -76,39 +110,42 @@ class Options: # export self.__true_val = true_val self.__allowed_keys = None self.__delimiter = delimiter - self.__spec = spec - self.__dict = OrderedDict() if spec is None else self.__parse(spec) + self.__data = self.OrderedData() if spec is None else self.__parse(spec, self.OrderedData) + self.__dict = {} + #self.__dict = OrderedDict() if spec is None else self.__parse(spec, OrderedDict) self.__list = [] self.__str = None self.__recache() - def dump(self, prio): - caller = log.get_caller_pos() - for key, val in self.__dict.items(): - log.slog(prio, "{}=\"{}\"".format(key, val)) + def dump(self, prio, caller=None): + if caller is None: + caller = get_caller_pos() + for key, val in self.__data.pairs: + slog(prio, "{}=\"{}\"".format(key, val), caller=caller) def keys(self): return self.__dict.keys() def items(self): - return self.__dict.items() + #return self.__dict.items() + return self.__data.pairs def get(self, key, default=None, by_index=False): if by_index: if type(key) != int: raise KeyError('Tried to get value from options string with ' + - 'index {} of type "{}": {}'.format(key, type(key), self.__spec)) - if key >= len(self.__list): + 'index {} of type "{}": {}'.format(key, type(key), str(self))) + if key >= len(self.__data.pairs): if default is not None: return default raise KeyError('Tried to get value from options string with ' + - 'index {} of {}: {}'.format(key, len(self.__list), self.__spec)) + 'index {} of {}: {}'.format(key, len(self.__data.pairs), str(self))) return self.__list[key] if key in self.__dict.keys(): return self.__dict[key] if default is not None: return default - raise KeyError('Key "{}" is not present in options string: {}'.format(key, self.__spec)) + raise KeyError('Key "{}" is not present in options string: {}'.format(key, str(self))) def update(self, rhs): if hasattr(rhs, 'items'):