leadership support

This commit is contained in:
Emmanuel Garette 2019-03-16 22:51:39 +01:00
parent aad8157b98
commit df7fc3fc8f
38 changed files with 186 additions and 72 deletions

1
test/data/unicode1.dict1 Normal file
View File

@ -0,0 +1 @@
{"options.unicode": "val"}

1
test/data/unicode1.mod1 Normal file
View File

@ -0,0 +1 @@
{"cmd": "config.option('options.unicode').value.set('val')", "body": {"updates": [{"action": "modify", "name": "options.unicode", "value": "val"}]}}

View File

@ -0,0 +1 @@
{"updates": ["options.unicode"], "model": [{"key": "options.unicode", "owner": "user", "value": "val"}]}

View File

@ -0,0 +1 @@
{"options.unicode.unicode": ["val1", "val2"], "options.unicode.unicode1": [null, null], "options.unicode.unicode2": ["follower2", "follower2"], "options.unicode.unicode3": [null, null]}

View File

@ -0,0 +1 @@
{"options.unicode.unicode": ["val3"], "options.unicode.unicode1": ["super1"], "options.unicode.unicode2": ["pas test"], "options.unicode.unicode3": [null]}

View File

@ -0,0 +1 @@
{"options.unicode.unicode": ["val3", "val4", "val5"], "options.unicode.unicode1": ["super1", "super2", null], "options.unicode.unicode2": ["pas test", "test", "follower2"], "options.unicode.unicode3": [null, "super", null]}

View File

@ -0,0 +1 @@
{"options.unicode.unicode": ["val3", "val4", "val5"], "options.unicode.unicode1": ["super1", "super2", null], "options.unicode.unicode2": ["pas test", "test", "follower2"], "options.unicode.unicode3": [null, "super", null]}

View File

@ -0,0 +1 @@
{"options.unicode.unicode": ["val3", "val4"], "options.unicode.unicode1": ["super1", "super2"], "options.unicode.unicode2": ["pas test", "follower2"], "options.unicode.unicode3": [null, "super"]}

View File

@ -0,0 +1 @@
{"options.unicode.unicode": ["val3", "val4"], "options.unicode.unicode1": ["super1", "super2"], "options.unicode.unicode2": ["pas test", "test2"], "options.unicode.unicode3": [null, "super"]}

View File

@ -0,0 +1 @@
{"cmd": "config.option('options.unicode.unicode').value.reset()", "body": {"updates": [{"action": "delete", "name": "options.unicode.unicode"}]}}

View File

@ -0,0 +1 @@
{"cmd": "config.option('options.unicode.unicode', 1).value.reset()", "body": {"updates": [{"action": "delete", "index": 1, "name": "options.unicode.unicode"}]}}

View File

@ -0,0 +1 @@
{"cmd": "config.option('options.unicode.unicode').value.set(['val3', 'val4', 'val5'])", "body": {"updates": [{"action": "modify", "name": "options.unicode.unicode", "value": ["val3", "val4", "val5"]}]}}

View File

@ -0,0 +1 @@
{"cmd": "config.option('options.unicode.unicode').value.set(['val3', 'val4', 'val5'])", "body": {"updates": [{"action": "modify", "name": "options.unicode.unicode", "value": ["val3", "val4", "val5"]}]}}

View File

@ -0,0 +1 @@
{"cmd": "config.option('options.unicode.unicode2', 1).value.reset()", "body": {"updates": [{"action": "delete", "name": "options.unicode.unicode2", "index": 1}]}}

View File

@ -0,0 +1 @@
{"cmd": "config.option('options.unicode.unicode2', 1).value.set('test2')", "body": {"updates": [{"action": "modify", "name": "options.unicode.unicode2", "index": 1, "value": "test2"}]}}

View File

@ -0,0 +1 @@
{"updates": ["options.unicode.unicode", "options.unicode.unicode1", "options.unicode.unicode2", "options.unicode.unicode3"], "model": [{"key": "options.unicode.unicode", "owner": "default", "required": true, "value": ["val1", "val2"]}, {"index": 0, "key": "options.unicode.unicode2", "owner": "default", "value": "follower2"}, {"index": 1, "key": "options.unicode.unicode2", "owner": "default", "value": "follower2"}]}

View File

@ -0,0 +1 @@
{"updates": ["options.unicode.unicode", "options.unicode.unicode1", "options.unicode.unicode2", "options.unicode.unicode3"], "model": [{"key": "options.unicode.unicode", "required": true, "value": ["val3"], "owner": "user"}, {"key": "options.unicode.unicode1", "index": 0, "value": "super1", "owner": "user"}, {"key": "options.unicode.unicode2", "index": 0, "value": "pas test", "owner": "user"}]}

View File

@ -0,0 +1 @@
{"updates": ["options.unicode.unicode", "options.unicode.unicode2"], "model": [{"key": "options.unicode.unicode", "required": true, "value": ["val3", "val4", "val5"], "owner": "user"}, {"key": "options.unicode.unicode1", "index": 0, "value": "super1", "owner": "user"}, {"key": "options.unicode.unicode1", "index": 1, "value": "super2", "owner": "user"}, {"key": "options.unicode.unicode2", "index": 0, "value": "pas test", "owner": "user"}, {"key": "options.unicode.unicode2", "index": 1, "value": "test", "owner": "user"}, {"key": "options.unicode.unicode2", "index": 2, "value": "follower2", "owner": "default"}, {"key": "options.unicode.unicode3", "index": 1, "value": "super", "owner": "user"}]}

View File

@ -0,0 +1 @@
{"model": [{"key": "options.unicode.unicode", "owner": "user", "required": true, "value": ["val3", "val4", "val5"]}, {"index": 0, "key": "options.unicode.unicode1", "owner": "user", "value": "super1"}, {"index": 1, "key": "options.unicode.unicode1", "owner": "user", "value": "super2"}, {"index": 0, "key": "options.unicode.unicode2", "owner": "user", "value": "pas test"}, {"index": 1, "key": "options.unicode.unicode2", "owner": "user", "value": "test"}, {"index": 2, "key": "options.unicode.unicode2", "owner": "default", "value": "follower2"}, {"index": 1, "key": "options.unicode.unicode3", "owner": "user", "value": "super"}], "updates": ["options.unicode.unicode", "options.unicode.unicode2"]}

View File

@ -0,0 +1 @@
{"updates": ["options.unicode.unicode2"], "model": [{"key": "options.unicode.unicode", "required": true, "value": ["val3", "val4"], "owner": "user"}, {"key": "options.unicode.unicode1", "index": 0, "value": "super1", "owner": "user"}, {"key": "options.unicode.unicode1", "index": 1, "value": "super2", "owner": "user"}, {"key": "options.unicode.unicode2", "index": 0, "value": "pas test", "owner": "user"}, {"key": "options.unicode.unicode2", "index": 1, "value": "follower2", "owner": "default"}, {"key": "options.unicode.unicode3", "index": 1, "value": "super", "owner": "user"}]}

View File

@ -0,0 +1 @@
{"updates": ["options.unicode.unicode2"], "model": [{"key": "options.unicode.unicode", "required": true, "value": ["val3", "val4"], "owner": "user"}, {"key": "options.unicode.unicode1", "index": 0, "value": "super1", "owner": "user"}, {"key": "options.unicode.unicode1", "index": 1, "value": "super2", "owner": "user"}, {"key": "options.unicode.unicode2", "index": 0, "value": "pas test", "owner": "user"}, {"key": "options.unicode.unicode2", "index": 1, "value": "test2", "owner": "user"}, {"key": "options.unicode.unicode3", "index": 1, "value": "super", "owner": "user"}]}

View File

@ -0,0 +1 @@
{"options.unicode": "val"}

View File

@ -0,0 +1 @@
{"options.unicode": null}

View File

@ -0,0 +1 @@
{"cmd": "config.option('options.unicode').value.set('val')", "body": {"updates": [{"action": "modify", "name": "options.unicode", "value": "val"}]}}

View File

@ -0,0 +1 @@
{"cmd": "config.option('options.unicode').value.reset()", "body": {"updates": [{"action": "delete", "name": "options.unicode"}]}}

View File

@ -0,0 +1 @@
{"updates": ["options.unicode"], "model": [{"key": "options.unicode", "owner": "user", "value": "val"}]}

View File

@ -0,0 +1 @@
{"updates": ["options.unicode"], "model": []}

View File

@ -0,0 +1 @@
{"options.unicode": ["val"]}

View File

@ -0,0 +1 @@
{"cmd": ["config.option('options.unicode').value.set([undefined])", "config.option('options.unicode').value.set(['val'])"], "body": {"updates": [{"action": "modify", "name": "options.unicode", "value": ["val"]}]}}

View File

@ -0,0 +1 @@
{"updates": ["options.unicode"], "model": [{"key": "options.unicode", "owner": "user", "required": true, "value": ["val"]}]}

View File

@ -0,0 +1 @@
{"options.unicode": ["a", "b"]}

View File

@ -0,0 +1 @@
{"options.unicode": ["c", "f", "e"]}

View File

@ -0,0 +1 @@
{"cmd": "config.option('options.unicode').value.reset()", "body": {"updates": [{"action": "delete", "name": "options.unicode"}]}}

View File

@ -0,0 +1 @@
{"cmd": "config.option('options.unicode').value.set(['c', 'f', 'e'])", "body": {"updates": [{"action": "modify", "name": "options.unicode", "value": ["c", "f", "e"]}]}}

View File

@ -0,0 +1 @@
{"updates": ["options.unicode"], "model": [{"key": "options.unicode", "owner": "default", "required": true, "value": ["a", "b"]}]}

View File

@ -0,0 +1 @@
{"updates": ["options.unicode"], "model": [{"key": "options.unicode", "owner": "user", "required": true, "value": ["c", "f", "e"]}]}

View File

@ -7,6 +7,7 @@ from os.path import dirname, abspath, join, normpath, splitext
# from tiramisu.error import ValueWarning # from tiramisu.error import ValueWarning
from tiramisu_json_api import Config from tiramisu_json_api import Config
from tiramisu_json_api.error import PropertiesOptionError from tiramisu_json_api.error import PropertiesOptionError
from tiramisu_json_api.setting import undefined
# warnings.simplefilter("always", ValueWarning) # warnings.simplefilter("always", ValueWarning)
@ -57,8 +58,6 @@ def test_get():
for filename in list_data(): for filename in list_data():
if debug: if debug:
print(filename) print(filename)
if 'master' in filename:
continue
with open(filename, 'r') as fh: with open(filename, 'r') as fh:
json = loads(fh.read()) json = loads(fh.read())
config = Config(json) config = Config(json)
@ -175,8 +174,6 @@ def test_prop2():
def test_info(): def test_info():
for filename in list_data(): for filename in list_data():
if 'master' in filename:
continue
with open(filename, 'r') as fh: with open(filename, 'r') as fh:
json = loads(fh.read()) json = loads(fh.read())
config = Config(json) config = Config(json)
@ -189,10 +186,14 @@ def test_info():
def test_mod(): def test_mod():
debug = False debug = False
# debug = True debug = True
for filename in list_data('.mod1'): i = 0
if 'master' in filename: while True:
continue i += 1
lists = list(list_data('.mod{}'.format(i)))
if not lists:
break
for filename in lists:
if debug: if debug:
print('test_mod', filename) print('test_mod', filename)
with open(filename[:-4] + 'json', 'r') as fh: with open(filename[:-4] + 'json', 'r') as fh:
@ -201,6 +202,12 @@ def test_mod():
config = Config(json) config = Config(json)
with open(filename) as fh: with open(filename) as fh:
mod = loads(fh.read()) mod = loads(fh.read())
if debug:
print(mod['cmd'])
if isinstance(mod['cmd'], list):
for cmd in mod['cmd']:
eval(cmd)
else:
eval(mod['cmd']) eval(mod['cmd'])
# #
if debug: if debug:
@ -209,15 +216,42 @@ def test_mod():
print('----------------') print('----------------')
pprint(mod['body']['updates']) pprint(mod['body']['updates'])
assert config.updates == mod['body']['updates'] assert config.updates == mod['body']['updates']
#
with open(filename[:-4] + 'dict1', 'r') as fh: with open(filename[:-4] + 'dict{}'.format(i), 'r') as fh:
dico1 = loads(fh.read()) dico1 = loads(fh.read())
assert dico1 == config.value.dict()
#
with open(filename[:-4] + 'updates1', 'r') as fh:
data = loads(fh.read())
if debug: if debug:
from pprint import pprint from pprint import pprint
pprint(data) pprint(dico1)
config.updates_data(data) print('----------------')
pprint(config.value.dict())
assert dico1 == config.value.dict()
def test_mod():
debug = False
# debug = True
i = 0
while True:
i += 1
lists = list(list_data('.mod{}'.format(i)))
if not lists:
break
for filename in lists:
if debug:
print('test_mod', filename)
with open(filename[:-4] + 'json', 'r') as fh:
json = loads(fh.read())
#
config = Config(json)
#
with open(filename[:-4] + 'updates{}'.format(i), 'r') as fh:
data = loads(fh.read())
config.updates_data(data)
with open(filename[:-4] + 'dict{}'.format(i), 'r') as fh:
dico1 = loads(fh.read())
if debug:
from pprint import pprint
pprint(dico1)
print('----------------')
pprint(config.value.dict())
assert dico1 == config.value.dict() assert dico1 == config.value.dict()

View File

@ -71,10 +71,9 @@ class TiramisuOptionOption:
def isleader(self): def isleader(self):
if '.' in self._path: if '.' in self._path:
parent_schema = self.config.get_schema(self._path.rsplit('.', 1)[0]) parent_schema = self.config.get_schema(self._path.rsplit('.', 1)[0])
if parent_schema['type'] == 'array':
leader = next(iter(parent_schema['properties'].keys())) leader = next(iter(parent_schema['properties'].keys()))
if parent_schema['type'] == 'array' and \ return leader == self._path
leader == self._path:
return True
return False return False
def isfollower(self): def isfollower(self):
@ -264,14 +263,14 @@ class TiramisuOptionValue(_Value):
def set(self, value): def set(self, value):
type_ = self.schema['type'] type_ = self.schema['type']
if self.schema.get('isMulti', False): remote = self.form.get(self.path, {}).get('remote', False)
if self.index is None and self.schema.get('isMulti', False):
if not isinstance(value, list): if not isinstance(value, list):
raise Exception('value must be a list') raise Exception('value must be a list')
for val in value: for val in value:
self._validate(type_, val) self._validate(type_, val)
else: else:
self._validate(type_, value) self._validate(type_, value)
remote = self.form.get(self.path, {}).get('remote', False)
self.config.modify_value(self.path, self.config.modify_value(self.path,
self.index, self.index,
value, value,
@ -501,7 +500,7 @@ class Config:
def __init__(self, def __init__(self,
json): json):
self.model_ori = json['model'] self.model_ori = json['model']
self.model = self.gen_model(json['model']) self.gen_model(json['model'])
self.form = {} self.form = {}
for option in json['form']: for option in json['form']:
if 'key' in option: if 'key' in option:
@ -519,24 +518,27 @@ class Config:
def gen_model(self, def gen_model(self,
model) -> List[Dict]: model) -> List[Dict]:
ret = {} self.model = {}
for option in model: for option in model:
key = option['key'] self.update_model(option)
if 'index' in option:
if key not in ret: def update_model(self,
ret[key] = copy(option) model):
ret[key]['value'] = {} key = model['key']
del ret[key]['index'] if 'index' in model:
del ret[key]['owner'] if key not in self.model:
if 'hidden' in ret[key]: self.model[key] = copy(model)
del ret[key]['hidden'] self.model[key]['value'] = {}
if option.get('hidden') is True: del self.model[key]['index']
ret[key]['value'][option['index']] = () del self.model[key]['owner']
if 'hidden' in self.model[key]:
del self.model[key]['hidden']
if model.get('hidden') is True:
self.model[key]['value'][model['index']] = ()
else: else:
ret[key]['value'][option['index']] = (option['value'], option['owner']) self.model[key]['value'][model['index']] = (model['value'], model['owner'])
else: else:
ret[key] = option self.model[key] = model
return ret
def __getattr__(self, def __getattr__(self,
subfunc: str) -> Any: subfunc: str) -> Any:
@ -594,14 +596,10 @@ class Config:
path: str, path: str,
index: Optional[int], index: Optional[int],
remote: bool) -> None: remote: bool) -> None:
schema = self.get_schema(path)
value = schema.get('value');
if value is None and schema.get('isMulti', False):
value = []
self.updates_value('delete', self.updates_value('delete',
path, path,
index, index,
value, None,
remote, remote,
None) None)
@ -682,8 +680,10 @@ class Config:
if value is None and self.get_schema(path).get('isMulti', False): if value is None and self.get_schema(path).get('isMulti', False):
value = [] value = []
else: else:
model = self.model.get(path, {}) if index in self.temp.get(path, {}).get('value', {}):
value = model.get('value') value = self.temp[path].get('value')
else:
value = self.model.get(path, {}).get('value')
if value is not None: if value is not None:
if index in value: if index in value:
if len(value[index]): if len(value[index]):
@ -691,7 +691,7 @@ class Config:
else: else:
value = PropertiesOptionError(None, None, None, opt_type='option') value = PropertiesOptionError(None, None, None, opt_type='option')
else: else:
value = None value = self.get_schema(path).get('default')
else: else:
value = None value = None
return value return value
@ -751,7 +751,7 @@ class Config:
del self.updates[-1] del self.updates[-1]
if update_last_action: if update_last_action:
if value is None: if action == 'delete' and value is None:
if 'value' in last_body: if 'value' in last_body:
del last_body['value'] del last_body['value']
else: else:
@ -762,7 +762,7 @@ class Config:
else: else:
data = {'action': action, data = {'action': action,
'name': path} 'name': path}
if value is not None: if action != 'delete' and value is not None:
data['value'] = value data['value'] = value
if index is not None: if index is not None:
data['index'] = index data['index'] = index
@ -777,18 +777,62 @@ class Config:
'model': self.model_ori})) 'model': self.model_ori}))
else: else:
if action == 'delete':
self.temp.setdefault(path, {})['owner'] = 'tmp'
if index is None:
value = self.default_value(path)
self.temp[path]['value'] = value
if self.option(path).option.isleader():
leadership_path = path.rsplit('.', 1)[0]
parent_schema = self.get_schema(leadership_path)
iter_leadership = list(parent_schema['properties'].keys())
for follower in iter_leadership[1:]:
for idx in range(len(value)):
follower_value = self.get_schema(follower).get('default')
# FIXME PropertiesOptionError?
self.temp.setdefault(follower, {}).setdefault('value', {})[idx] = (follower_value, 'default')
elif self.option(path).option.isleader():
old_value = self.option(path).value.get()
old_value.pop(index)
self.temp[path]['value'] = old_value
leadership_path = path.rsplit('.', 1)[0]
parent_schema = self.get_schema(leadership_path)
iter_leadership = list(parent_schema['properties'].keys())
for follower in iter_leadership[1:]:
if index in self.temp.get(follower, {}).get('value', {}):
del self.temp[follower]['value'][index]
if index in self.model.get(follower, {}).get('value', {}):
del self.model[follower]['value'][index]
else:
if index in self.temp.get(path, {}).get('value', {}):
del self.temp[path]['value'][index]
if index in self.model.get(path, {}).get('value', {}):
del self.model[path]['value'][index]
elif index is None:
self.temp.setdefault(path, {})['owner'] = 'tmp' self.temp.setdefault(path, {})['owner'] = 'tmp'
self.temp[path]['value'] = value self.temp[path]['value'] = value
else:
self.temp.setdefault(path, {}).setdefault('value', {})[index] = (value, 'tmp')
self.set_dependencies(path, value) self.set_dependencies(path, value)
self.set_not_equal(path, value) self.set_not_equal(path, value)
self.do_copy(path, value) self.do_copy(path, value)
def default_value(self, path):
schema = self.get_schema(path)
value = schema.get('value');
if value is None and schema.get('isMulti', False):
value = []
return value
def updates_data(self, data): def updates_data(self, data):
self.updates = [] self.updates = []
self.temp.clear() self.temp.clear()
# FIXME remove old key ? for key in data['updates']:
if key in self.model:
del self.model[key]
for model in data['model']: for model in data['model']:
self.model[model['key']] = model if key == model['key']:
self.update_model(model)
self.model_ori = data['model'] self.model_ori = data['model']
def test_value(self, def test_value(self,