mirror of
ssh://git.janware.com/srv/git/janware/proj/jw-python
synced 2026-01-15 01:52:56 +01:00
jwutils.Options: Add support for duplicate keys
Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
parent
12bf59b3cd
commit
82c0e6fe2e
1 changed files with 61 additions and 24 deletions
|
|
@ -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
|
||||
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'):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue