From 552cd3740d1761625f3d445d7244fcb0032bde99 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 9 May 2019 20:32:43 +0200 Subject: [PATCH] todict: better support for callback --- tests/dict/data/number1.json | 2 +- tests/dict/data/number1_frozen.json | 2 +- tests/dict/data/number1_mod_value.json | 2 +- tests/dict/data/number1_value.json | 2 +- tiramisu/api.py | 9 +- tiramisu/todict.py | 178 ++++++++++++------------- 6 files changed, 97 insertions(+), 98 deletions(-) diff --git a/tests/dict/data/number1.json b/tests/dict/data/number1.json index 301a6c6..788167b 100644 --- a/tests/dict/data/number1.json +++ b/tests/dict/data/number1.json @@ -14,7 +14,7 @@ "model": {}, "form": { "options.integer": { - "allowedpattern": "[0-9]", + "pattern": "^[0-9]+$", "type": "input" }, "null": [ diff --git a/tests/dict/data/number1_frozen.json b/tests/dict/data/number1_frozen.json index b544a46..5da6f60 100644 --- a/tests/dict/data/number1_frozen.json +++ b/tests/dict/data/number1_frozen.json @@ -18,7 +18,7 @@ }, "form": { "options.integer": { - "allowedpattern": "[0-9]", + "pattern": "^[0-9]+$", "type": "input" }, "null": [ diff --git a/tests/dict/data/number1_mod_value.json b/tests/dict/data/number1_mod_value.json index 42475b4..3a435f3 100644 --- a/tests/dict/data/number1_mod_value.json +++ b/tests/dict/data/number1_mod_value.json @@ -21,7 +21,7 @@ "form": { "options.integer": { "clearable": true, - "allowedpattern": "[0-9]", + "pattern": "^[0-9]+$", "type": "input" }, "null": [ diff --git a/tests/dict/data/number1_value.json b/tests/dict/data/number1_value.json index e84388c..66d33ca 100644 --- a/tests/dict/data/number1_value.json +++ b/tests/dict/data/number1_value.json @@ -21,7 +21,7 @@ "form": { "options.integer": { "clearable": true, - "allowedpattern": "[0-9]", + "pattern": "^[0-9]+$", "type": "input" }, "null": [ diff --git a/tiramisu/api.py b/tiramisu/api.py index 533ced7..3d269a3 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -271,6 +271,7 @@ class _TiramisuOptionOption(_TiramisuOptionOptionDescription): if isinstance(option, RegexpOption): return option._regexp.pattern if type == 'integer': + # FIXME negative too! return r'^[0-9]+$' if type == 'domainname': return option.impl_get_extra('_domain_re').pattern @@ -384,11 +385,11 @@ class TiramisuOptionProperty(CommonTiramisuOption): """Remove new property for an option""" option = self._option_bag.option props = self._settings.getproperties(self._option_bag, - apply_requires=False) + apply_requires=False) self._settings.setproperties(self._option_bag.path, - props - {prop}, - self._option_bag, - self._option_bag.config_bag.context) + props - {prop}, + self._option_bag, + self._option_bag.config_bag.context) def reset(self): """Reset all personalised properties""" diff --git a/tiramisu/todict.py b/tiramisu/todict.py index 74e301c..bfd56b4 100644 --- a/tiramisu/todict.py +++ b/tiramisu/todict.py @@ -46,68 +46,54 @@ class Callbacks(object): def add(self, path, childapi, - options, schema, force_store_value): - self.callbacks.append((path, childapi, options, schema, force_store_value)) + if self.remotable == 'all' or childapi.option.isoptiondescription(): + return + callback, callback_params = childapi.option.callbacks() + if callback is None: # FIXME ? and force_store_value and self.clearable != 'all': + return + self.callbacks.append((callback, callback_params, path, childapi, schema, force_store_value)) - def manage_callbacks(self, - path, - childapi, - options, - callback, - callback_params, - form, - schema): - if callback_params is not None: - remote = True - for callback_param in callback_params.args: - if isinstance(callback_param, ParamContext): - raise ValueError(_('context is not supported from now for {}').format(path)) - if isinstance(callback_param, ParamOption): - if callback.__name__ == 'tiramisu_copy': - if self.clearable == 'minimum': - form.setdefault(path, {})['clearable'] = True - if form.get(path, {}).get('remote') is not True and form[options[callback_param.option]].get('remote', False) is not True: - form.setdefault(options[callback_param.option], {}) - form[options[callback_param.option]].setdefault('copy', []).append(path) - remote = False - elif options.get(callback_param.option) is not None: - #form.setdefault(options[callback_param.option], {}) - form.setdefault(path, {}) - form[path]['remote'] = True - #break - if remote: - if self.remotable == 'none': - raise ValueError(_('option {} only works when remotable is not "none"').format(path)) - form.setdefault(path, {})['remote'] = True - else: - if 'expire' not in childapi.property.get() and childapi.owner.isdefault(): - schema[path]['value'] = childapi.value.get() - if self.clearable == 'minimum': - form.setdefault(path, {})['clearable'] = True - else: - if self.remotable == 'none': - raise ValueError(_('option {} only works when remotable is not "none"').format(path)) - # FIXME is not default, show calculate - form.setdefault(path, {})['remote'] = True + def process_properties(self, form): + for callback, callback_params, path, childapi, schema, force_store_value in self.callbacks: + has_option = False + if callback_params is not None: + for callback_param in callback_params.args: + if isinstance(callback_param, ParamContext): + raise ValueError(_('context is not supported from now for {}').format(path)) + if isinstance(callback_param, ParamOption): + has_option = True + if callback.__name__ != 'tiramisu_copy' or 'expire' in childapi.option.properties(): + if self.remotable == 'none': + raise ValueError(_('option {} only works when remotable is not "none"').format(path)) + form[callback_param.option.impl_getpath()]['remote'] = True + remote = True + if not has_option and form.get(path, {}).get('remote') == False: + if 'expire' in childapi.option.properties(): + if self.remotable == 'none': + raise ValueError(_('option {} only works when remotable is not "none"').format(path)) + form.setdefault(path, {})['remote'] = True + elif childapi.owner.isdefault(): + # get calculated value and set clearable + schema[path]['value'] = childapi.value.get() + if self.clearable == 'minimum': + form.setdefault(path, {})['clearable'] = True + def manage_callbacks(self, form): + for callback, callback_params, path, childapi, schema, force_store_value in self.callbacks: + if callback_params is not None: + for callback_param in callback_params.args: + if isinstance(callback_param, ParamOption) and callback.__name__ == 'tiramisu_copy': + opt_path = callback_param.option.impl_getpath() + if form.get(opt_path, {}).get('remote') is not True: + form.setdefault(opt_path, {}) + form[opt_path].setdefault('copy', []).append(path) def process(self, form): - for path, childapi, options, schema, force_store_value in self.callbacks: - if not childapi.option.isoptiondescription(): - callback, callback_params = childapi.option.callbacks() - if callback is not None: - if force_store_value and self.clearable != 'all': - return - self.manage_callbacks(path, - childapi, - options, - callback, - callback_params, - form, - schema) + self.process_properties(form) + self.manage_callbacks(form) class Consistencies(object): @@ -158,7 +144,6 @@ class Requires(object): self.remotable = tiramisu_web.remotable def manage_requires(self, - require_obj, childapi, path, form, @@ -170,58 +155,63 @@ class Requires(object): transitive, same_action, operator = require if transitive is False: # transitive to "False" not supported yet for a requirement - if require_obj.remotable == 'none': + if self.remotable == 'none': raise ValueError('require set for {} but remotable is "none"' ''.format(path)) form.setdefault(path, {'key': path})['remote'] = True return if same_action is False: # same_action to "False" not supported yet for a requirement - if require_obj.remotable == 'none': + if self.remotable == 'none': raise ValueError('require set for {} but remotable is "none"' ''.format(path)) form.setdefault(path, {'key': path})['remote'] = True return if operator == 'and': # operator "and" not supported yet for a requirement - if require_obj.remotable == 'none': + if self.remotable == 'none': raise ValueError('require set for {} but remotable is "none"' ''.format(path)) form.setdefault(path, {'key': path})['remote'] = True return for option, expected in options: - option_path = require_obj.options.get(option) + option_path = self.options.get(option) if option_path is not None and action in action_hide: if current_action is None: current_action = action elif current_action != action: - if require_obj.remotable == 'none': + if self.remotable == 'none': raise ValueError('require set for {} but remotable is "none"' ''.format(path)) form.setdefault(option_path, {'key': option_path})['remote'] = True + if inverse: + act = 'show' + inv_act = 'hide' + else: + act = 'hide' + inv_act = 'show' for exp in expected: - if inverse: - act = 'show' - inv_act = 'hide' - else: - act = 'hide' - inv_act = 'show' - require_obj.requires.setdefault(path, - {'expected': {}} - )['expected'].setdefault(exp, - {}).setdefault(act, - []).append(option_path) - if isinstance(option, ChoiceOption): - for value in require_obj.config.unrestraint.option(option_path).value.list(): - if value not in expected: - require_obj.requires.setdefault(path, - {'expected': {}} - )['expected'].setdefault(value, - {}).setdefault(inv_act, - []).append(option_path) - require_obj.requires[path].setdefault('default', {}).setdefault(inv_act, []).append(option_path) + self.requires.setdefault(path, + {'expected': {}} + )['expected'].setdefault(exp, + {}).setdefault(act, + []).append(option_path) + if isinstance(option, ChoiceOption): + choice_obj = self.config.unrestraint.option(option_path) + values = self.tiramisu_web.get_enum(choice_obj, + choice_obj.option.ismulti(), + option_path, + choice_obj.option.properties()) + for value in values: + if value not in expected: + self.requires.setdefault(path, + {'expected': {}} + )['expected'].setdefault(value, + {}).setdefault(inv_act, + []).append(option_path) + self.requires[path].setdefault('default', {}).setdefault(inv_act, []).append(option_path) else: - if require_obj.remotable == 'none': + if self.remotable == 'none': raise ValueError('require set for {} but remotable est "none"' ''.format(path)) form.setdefault(option_path, {'key': option_path})['remote'] = True @@ -234,8 +224,7 @@ class Requires(object): self.options[child] = path current_action = None - self.manage_requires(self, - childapi, + self.manage_requires(childapi, path, form, ACTION_HIDE, @@ -384,7 +373,6 @@ class TiramisuDict: childapi) self.callbacks.add(path, childapi, - self.requires.options, schema, 'force_store_value' in props_no_requires) childapi_option = childapi.option @@ -503,12 +491,22 @@ class TiramisuDict: schema[path]['autoFreeze'] = True if web_type == 'choice': - schema[path]['enum'] = childapi.value.list() - empty_is_required = not childapi.option.isfollower() and is_multi - if (empty_is_required and not 'empty' in props_no_requires) or \ - (not empty_is_required and not 'mandatory' in props_no_requires): - schema[path]['enum'] = [''] + list(schema[path]['enum']) + schema[path]['enum'] = self.get_enum(childapi, + is_multi, + path, + props_no_requires) + def get_enum(self, + childapi, + is_multi, + path, + props_no_requires): + values = childapi.value.list() + empty_is_required = not childapi.option.isfollower() and is_multi + if '' not in values and ((empty_is_required and not 'empty' in props_no_requires) or \ + (not empty_is_required and not 'mandatory' in props_no_requires)): + values = [''] + list(values) + return values def gen_form(self, form,