mirror of
ssh://git.janware.com/srv/git/janware/proj/jw-python
synced 2026-01-15 01:52:56 +01:00
Add class Options
The Options constructor takes an options string, parses it and makes the options available via __getitem__(). Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
parent
a52557570b
commit
1ffdb8728a
3 changed files with 162 additions and 0 deletions
5
test/parse-opts/Makefile
Normal file
5
test/parse-opts/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
TOPDIR = ../..
|
||||||
|
|
||||||
|
include $(TOPDIR)/make/proj.mk
|
||||||
|
include $(JWBDIR)/make/py-run.mk
|
||||||
|
|
||||||
32
test/parse-opts/test.py
Normal file
32
test/parse-opts/test.py
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
from jwutils.log import *
|
||||||
|
from jwutils.Options import *
|
||||||
|
|
||||||
|
delim = "======================= "
|
||||||
|
d = "----------------------- "
|
||||||
|
|
||||||
|
s = "this=that a=b doit"
|
||||||
|
slog(NOTICE, d + s)
|
||||||
|
a = Options(s)
|
||||||
|
slog(NOTICE, d + "dump()")
|
||||||
|
a.dump(NOTICE)
|
||||||
|
slog(NOTICE, d + "by index")
|
||||||
|
for i in range(0, 4):
|
||||||
|
slog(NOTICE, "attr({}) = {}".format(i, a.get(i, by_index=True, default=False)))
|
||||||
|
slog(NOTICE, d + "by key")
|
||||||
|
for i in [ "this", "that", "b", "a", "doit"]:
|
||||||
|
slog(NOTICE, "attr({}) = {}".format(i, a[i]))
|
||||||
|
|
||||||
|
s = '"me": "too", "Pfalse": true, "myarr": ["a", "b", "c"], "me": "not"'
|
||||||
|
slog(NOTICE, delim + s)
|
||||||
|
a = Options(s)
|
||||||
|
slog(NOTICE, d + "dump()")
|
||||||
|
a.dump(NOTICE)
|
||||||
|
slog(NOTICE, d + "by index")
|
||||||
|
for i in range(0, 5):
|
||||||
|
slog(NOTICE, "attr({}) = {}".format(i, a.get(i, by_index=True, default=False)))
|
||||||
|
slog(NOTICE, d + "by key in keys()")
|
||||||
|
for i in a.keys():
|
||||||
|
slog(NOTICE, "attr({}) = {}".format(i, a[i]))
|
||||||
|
slog(NOTICE, d + "by key")
|
||||||
|
for i in [ "me", "Pfalse", "myarr" ]:
|
||||||
|
slog(NOTICE, "attr({}) = {}".format(i, a[i]))
|
||||||
125
tools/python/jwutils/Options.py
Normal file
125
tools/python/jwutils/Options.py
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
from collections import OrderedDict
|
||||||
|
from . import log
|
||||||
|
import shlex
|
||||||
|
|
||||||
|
class Options: # export
|
||||||
|
|
||||||
|
def __parse_json(self, spec):
|
||||||
|
spec = spec.strip()
|
||||||
|
if len(spec) < 3:
|
||||||
|
return None
|
||||||
|
if spec[0] != '{':
|
||||||
|
spec = '{' + spec + '}'
|
||||||
|
try:
|
||||||
|
return json.loads(spec, object_pairs_hook=OrderedDict)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __parse(self, opts_str):
|
||||||
|
r = self.__parse_json(opts_str)
|
||||||
|
if r is not None:
|
||||||
|
return r
|
||||||
|
r = OrderedDict()
|
||||||
|
opt_strs = shlex.split(opts_str)
|
||||||
|
for opt_str in opt_strs:
|
||||||
|
opt_str = re.sub('\s*=\s*', '=', opt_str)
|
||||||
|
sides = opt_str.split('=')
|
||||||
|
lhs = sides[0].strip()
|
||||||
|
if not len(lhs):
|
||||||
|
continue
|
||||||
|
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
|
||||||
|
return r
|
||||||
|
|
||||||
|
def __recache(self):
|
||||||
|
self.__list.clear()
|
||||||
|
self.__list = list(self.__dict)
|
||||||
|
self.__str = str(dict(self.__dict))
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if not key in self.__dict.keys():
|
||||||
|
return None
|
||||||
|
return self.__dict[key]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.__str
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return self.__str
|
||||||
|
|
||||||
|
def __format__(self, fmt):
|
||||||
|
return self.__str
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.__list)
|
||||||
|
|
||||||
|
def __contains__(self, keys):
|
||||||
|
if not type(keys) in [list, set]:
|
||||||
|
return keys in self.__dict.keys()
|
||||||
|
for key in keys:
|
||||||
|
if not key 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.__spec = spec
|
||||||
|
self.__dict = OrderedDict() if spec is None else self.__parse(spec)
|
||||||
|
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 keys(self):
|
||||||
|
return self.__dict.keys()
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return self.__dict.items()
|
||||||
|
|
||||||
|
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):
|
||||||
|
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))
|
||||||
|
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))
|
||||||
|
|
||||||
|
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))
|
||||||
|
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])
|
||||||
Loading…
Add table
Add a link
Reference in a new issue