mirror of
ssh://devgit.janware.com/janware/proj/jw-python
synced 2026-06-17 07:06:37 +02:00
Include py-topdir.mk, which entails loads of fallout from make check. Fix it.
Signed-off-by: Jan Lindemann <jan@janware.com>
183 lines
5.5 KiB
Python
183 lines
5.5 KiB
Python
import json
|
|
import re
|
|
import shlex
|
|
import traceback
|
|
|
|
from collections import OrderedDict
|
|
|
|
from .log import ERR, get_caller_pos, slog, slog_m
|
|
|
|
class Options: # export
|
|
|
|
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 = cls)
|
|
except Exception:
|
|
pass
|
|
return None
|
|
|
|
def __parse(self, opts_str, cls):
|
|
r = self.__parse_json(opts_str, cls)
|
|
if r is not None:
|
|
return r
|
|
r = cls()
|
|
try:
|
|
opt_strs = shlex.split(opts_str)
|
|
except Exception:
|
|
slog_m(ERR, traceback.format_exc())
|
|
slog(ERR, 'Failed to split options string >{}<'.format(opts_str))
|
|
raise
|
|
for opt_str in opt_strs:
|
|
opt_str = re.sub(r'\s*=\s*', '=', opt_str)
|
|
sides = opt_str.split('=')
|
|
lhs = sides[0].strip()
|
|
if not len(lhs):
|
|
continue
|
|
if self.__allowed_keys and lhs not 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.__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 key not in self.__dict.keys():
|
|
return None
|
|
return self.__dict[key]
|
|
|
|
def __str__(self):
|
|
return ', '.join(str(p[0]) + ': ' + str(p[1]) for p in self.__data.pairs)
|
|
|
|
def __repr__(self):
|
|
return self.__str__()
|
|
|
|
def __format__(self, fmt):
|
|
return self.__str__()
|
|
|
|
def __len__(self):
|
|
return len(self.__data.pairs)
|
|
|
|
def __contains__(self, keys):
|
|
if type(keys) not in [list, set]:
|
|
return keys in self.__dict.keys()
|
|
for key in keys:
|
|
if key not in self.__dict.keys():
|
|
return False
|
|
return True
|
|
|
|
def __iter__(self):
|
|
return iter(self.__list)
|
|
|
|
#def __next__(self):
|
|
# return next(self.__list)
|
|
|
|
def __init__(
|
|
self, spec = None, delimiter = ',', allowed_keys = None, true_val = True
|
|
):
|
|
self.__true_val = true_val
|
|
self.__allowed_keys = None
|
|
self.__delimiter = delimiter
|
|
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 = 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.__data.pairs
|
|
|
|
def get(self, key, default = None, by_index = False):
|
|
if by_index:
|
|
if isinstance(key, int):
|
|
raise KeyError(
|
|
'Tried to get value from options string with ' +
|
|
'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.__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, str(self))
|
|
)
|
|
|
|
def update(self, rhs):
|
|
if hasattr(rhs, 'items'):
|
|
for key, val in rhs.items():
|
|
self.__dict[key] = val
|
|
return
|
|
if isinstance(rhs, str):
|
|
self.update(self.__parse(rhs, self.OrderedData))
|
|
return
|
|
raise Exception(
|
|
'Tried to update options with object of incompatible type {}'.format(
|
|
type(rhs)
|
|
)
|
|
)
|
|
|
|
def append_to(self, obj):
|
|
for opt in self.__list:
|
|
setattr(obj, opt[0], opt[1])
|