better symlink support and submulti

This commit is contained in:
Emmanuel Garette 2019-04-17 19:15:30 +02:00
parent 64699bfba1
commit ceae0be2ce
8 changed files with 64 additions and 28 deletions

View File

@ -1 +1 @@
{"unicode1_leadership_requires_follower_value.options.unicode1.unicode1": ["test", "pas test"], "unicode1_leadership_requires_follower_value.options.unicode1.unicode2": ["super1", null], "unicode1_leadership_requires_follower_value.options.unicode1.unicode3": ["super1", "cannot access to option \"Unicode follower 2\" because has property \"hidden\" (the value of \"Values 'test' must show 'Unicode follower 2'\" is not \"test\")"]} {"unicode1_leadership_requires_follower_value.options.unicode1.unicode1": ["test", "pas test"], "unicode1_leadership_requires_follower_value.options.unicode1.unicode2": ["super1", null], "unicode1_leadership_requires_follower_value.options.unicode1.unicode3": ["super1", "ne peut acc\u00e9der \u00e0 l'option \"Unicode follower 2\" a cause de la propri\u00e9t\u00e9 \"hidden\" (la valeur de \"Values 'test' must show 'Unicode follower 2'\" n'est pas \"test\")"]}

View File

@ -1 +1 @@
{"unicode1_leadership_requires_value.options.unicode.unicode": ["test", "val2"], "unicode1_leadership_requires_value.options.unicode.unicode1": ["super1", "super2"], "unicode1_leadership_requires_value.options.unicode.unicode2": ["pas test", "test"], "unicode1_leadership_requires_value.options.unicode.unicode3": [null, "cannot access to option \"Unicode follower 3\" because has property \"hidden\" (the value of \"Values 'test' must show 'Unicode follower 3'\" is not \"test\")"]} {"unicode1_leadership_requires_value.options.unicode.unicode": ["test", "val2"], "unicode1_leadership_requires_value.options.unicode.unicode1": ["super1", "super2"], "unicode1_leadership_requires_value.options.unicode.unicode2": ["pas test", "test"], "unicode1_leadership_requires_value.options.unicode.unicode3": [null, "ne peut acc\u00e9der \u00e0 l'option \"Unicode follower 3\" a cause de la propri\u00e9t\u00e9 \"hidden\" (la valeur de \"Values 'test' must show 'Unicode follower 3'\" n'est pas \"test\")"]}

View File

@ -1 +1 @@
{"unicode1_multi_mandatory.options.unicode": {"null": ["empty", "mandatory"]}} {"unicode1_multi_mandatory.options.unicode": {"null": ["mandatory", "empty"]}}

View File

@ -1 +1 @@
{"options.unicode1.unicode1": ["test", "pas test"], "options.unicode1.unicode2": ["super1", null], "options.unicode1.unicode3": ["super1", "cannot access to option \"Unicode follower 2\" because has property \"hidden\" (the value of \"Values 'test' must show 'Unicode follower 2'\" is not \"test\")"]} {"options.unicode1.unicode1": ["test", "pas test"], "options.unicode1.unicode2": ["super1", null], "options.unicode1.unicode3": ["super1", "ne peut acc\u00e9der \u00e0 l'option \"Unicode follower 2\" a cause de la propri\u00e9t\u00e9 \"hidden\" (la valeur de \"Values 'test' must show 'Unicode follower 2'\" n'est pas \"test\")"]}

View File

@ -1 +1 @@
{"options.unicode.unicode": ["test", "val2"], "options.unicode.unicode1": ["super1", "super2"], "options.unicode.unicode2": ["pas test", "test"], "options.unicode.unicode3": [null, "cannot access to option \"Unicode follower 3\" because has property \"hidden\" (the value of \"Values 'test' must show 'Unicode follower 3'\" is not \"test\")"]} {"options.unicode.unicode": ["test", "val2"], "options.unicode.unicode1": ["super1", "super2"], "options.unicode.unicode2": ["pas test", "test"], "options.unicode.unicode3": [null, "ne peut acc\u00e9der \u00e0 l'option \"Unicode follower 3\" a cause de la propri\u00e9t\u00e9 \"hidden\" (la valeur de \"Values 'test' must show 'Unicode follower 3'\" n'est pas \"test\")"]}

View File

@ -1 +1 @@
{"options.unicode": {"null": ["empty", "mandatory"]}} {"options.unicode": {"null": ["mandatory", "empty"]}}

View File

@ -26,7 +26,7 @@ def error_to_str(dico):
for key, value in dico.items(): for key, value in dico.items():
if isinstance(value, list): if isinstance(value, list):
for idx, val in enumerate(value): for idx, val in enumerate(value):
if (isinstance(val, str) and val.startswith('cannot access to')) or isinstance(val, PropertiesOptionError): if (isinstance(val, str) and (val.startswith('cannot access to') or val.startswith('ne peut accéder'))) or isinstance(val, PropertiesOptionError):
dico[key][idx] = "PropertiesOptionError" dico[key][idx] = "PropertiesOptionError"
return dico return dico
@ -188,15 +188,23 @@ def test_prop2():
def test_info(): def test_info():
debug = False
# debug = True
for filename in list_data(): for filename in list_data():
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)
with open(filename[:-4] + 'info', 'r') as fh: with open(filename[:-4] + 'info', 'r') as fh:
dico = loads(fh.read()) dico = loads(fh.read())
if debug:
from pprint import pprint
pprint(json)
print('-------------------')
pprint(dico)
for key, values in dico.items(): for key, values in dico.items():
for info, value in values.items(): for info, value in values.items():
assert getattr(config.option(key).option, info)() == value, 'error for {} in {}'.format(info, filename) assert getattr(config.option(key).option, info)() == value, 'error for {} info {} in {}'.format(key, info, filename)
def test_mod(): def test_mod():

View File

@ -87,16 +87,23 @@ class TiramisuOptionOption:
def ismulti(self) -> bool: def ismulti(self) -> bool:
return self.schema.get('isMulti', False) return self.schema.get('isMulti', False)
def issubmulti(self) -> bool:
return self.schema.get('isSubMulti', False)
def type(self) -> str: def type(self) -> str:
if self.isleadership(): if self.isleadership():
return 'leadership' return 'leadership'
if self.isoptiondescription(): if self.isoptiondescription():
return 'optiondescription' return 'optiondescription'
if self.issymlinkoption():
return self.config.get_schema(self.schema['opt_path'])['type']
return self.schema['type'] return self.schema['type']
def properties(self) -> List[str]: def properties(self) -> List[str]:
model = self.model.get(self._path, {}) model = self.model.get(self._path, {})
return self.config.get_properties(self.model, self._path, None) if self.isfollower():
model = model.get(None, {})
return self.config.get_properties(model, self._path, None)
def requires(self) -> None: def requires(self) -> None:
# FIXME # FIXME
@ -255,9 +262,9 @@ class TiramisuOptionValue(_Value):
return return
if type_ == 'choice': if type_ == 'choice':
if value not in self.schema['enum']: if value not in self.schema['enum']:
raise Exception('value {} is not in {}'.format(value, self.schema['enum'])) raise ValueError('value {} is not in {}'.format(value, self.schema['enum']))
elif not isinstance(value, TYPE[type_]): elif not isinstance(value, TYPE[type_]):
raise Exception('value {} is not a valid {} '.format(value, type_)) raise ValueError('value {} is not a valid {} '.format(value, type_))
def set(self, value): def set(self, value):
type_ = self.schema['type'] type_ = self.schema['type']
@ -266,9 +273,17 @@ class TiramisuOptionValue(_Value):
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) if self.schema.get('isSubMulti', False):
for v in val:
self._validate(type_, v)
else:
self._validate(type_, val)
else: else:
self._validate(type_, value) if self.schema.get('isSubMulti', False):
for val in value:
self._validate(type_, val)
else:
self._validate(type_, value)
self.config.modify_value(self.path, self.config.modify_value(self.path,
self.index, self.index,
value, value,
@ -481,9 +496,18 @@ class ContextValue(_Value):
def mandatory(self): def mandatory(self):
for key, value in self.dict().items(): for key, value in self.dict().items():
if self.model.get(key, {}).get('required') and \ if self.config.isfollower(key):
value is None or \ # FIXME test with index
(self.schema.get('isMulti') and (None in value or '' in value)): if self.model.get(key, {}).get(None, {}).get('required'):
if self.config.get_schema(key).get('isSubMulti'):
for val in value:
if not val or None in val or '' in val:
yield key
break
elif None in value or '' in value:
yield key
elif value is None or \
(self.config.get_schema(key).get('isMulti') and (not value or None in value or '' in value)):
yield key yield key
@ -495,7 +519,6 @@ class Config:
raise Exception('incompatible tiramisu-json format version (got {}, expected {})'.format(json.get('version', '0.0'), TIRAMISU_JSON_VERSION)) raise Exception('incompatible tiramisu-json format version (got {}, expected {})'.format(json.get('version', '0.0'), TIRAMISU_JSON_VERSION))
self.model = json['model'] self.model = json['model']
self.form = json['form'] self.form = json['form']
self.form = {}
# support pattern # support pattern
for key, option in json['form'].items(): for key, option in json['form'].items():
if key != 'null': if key != 'null':
@ -580,7 +603,7 @@ class Config:
only_raises=True): only_raises=True):
props = model.get('properties', [])[:] props = model.get('properties', [])[:]
if model.get('required'): if model.get('required'):
if self.get_schema(path).get('isMulti', False): if self.get_schema(path).get('isMulti', False) and not self.isfollower(path):
props.append('empty') props.append('empty')
else: else:
props.append('mandatory') props.append('mandatory')
@ -630,7 +653,7 @@ class Config:
index: Optional[int]) -> bool: index: Optional[int]) -> bool:
for property_, needs in {'hidden': True, 'display': False}.items(): for property_, needs in {'hidden': True, 'display': False}.items():
if property_ in self.temp.get(path, {}): if property_ in self.temp.get(path, {}):
value = self.temp[path][property_] return self.temp[path][property_]
else: else:
if self.isfollower(path): if self.isfollower(path):
if self.model.get(path, {}).get('null', {}).get(property_, None) == needs: if self.model.get(path, {}).get('null', {}).get(property_, None) == needs:
@ -645,36 +668,41 @@ class Config:
def get_value(self, def get_value(self,
path: str, path: str,
index: int=None) -> Any: index: int=None) -> Any:
schema = self.get_schema(path)
if schema['type'] == 'symlink':
path = schema['opt_path']
schema = self.get_schema(path)
if index is None: if index is None:
if 'value' in self.temp.get(path, {}): if 'value' in self.temp.get(path, {}):
value = self.temp[path]['value'] value = self.temp[path]['value']
else: else:
value = self.model.get(path, {}).get('value') value = self.model.get(path, {}).get('value')
if value is None and self.get_schema(path).get('isMulti', False): if value is None and schema.get('isMulti', False):
value = [] value = []
else: else:
index = str(index) index = str(index)
if 'delete' in self.temp.get(path, {}): if 'delete' in self.temp.get(path, {}):
value = None value = None
elif index in self.temp.get(path, {}): elif index in self.temp.get(path, {}) and 'delete' in self.temp[path][index]:
if 'delete' in self.temp[path][index]: value = None
value = None elif 'value' in self.temp.get(path, {}).get(index, {}):
else: value = self.temp[path]
value = self.temp[path]
else: else:
value = self.model.get(path) value = self.model.get(path)
if self.isfollower(path): if self.isfollower(path):
if self.is_hidden(path, index): if self.is_hidden(path, index):
value = PropertiesOptionError(None, None, None, opt_type='option') value = PropertiesOptionError(None, None, None, opt_type='option')
elif value is not None and index in value: elif value is not None and 'value' in value.get(index, {}):
value = value[index]['value'] value = value[index]['value']
else: else:
value = self.get_schema(path).get('default') value = schema.get('default')
else: else:
if value is not None and index in value and 'value' in value[index]: if value is not None and index in value and 'value' in value[index]:
value = value[index]['value'] value = value[index]['value']
else: else:
value = self.get_schema(path).get('default') value = schema.get('default')
if value is None and schema.get('isSubMulti', False):
value = []
return value return value
def get_owner(self, def get_owner(self,