diff --git a/tiramisu/config.py b/tiramisu/config.py index d268787..5d5c0f2 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -38,6 +38,8 @@ class Config(object): _cfgimpl_frozen = True _cfgimpl_owner = default_owner _cfgimpl_toplevel = None +# TODO implement unicity by name +# _cfgimpl_unique_names = True def __init__(self, descr, parent=None, **overrides): self._cfgimpl_descr = descr @@ -61,6 +63,26 @@ class Config(object): else: raise ConflictConfigError('duplicate option name: ' '{0}'.format(dup._name)) + +# TODO implement unicity by name +# def _validate_duplicates_for_names(self, children): +# "validates duplicates names agains the whole config" +# rootconfig = self._cfgimpl_get_toplevel() +# if self._cfgimpl_unique_names: +# for dup in children: +# try: +# print dup._name +# try: +# print rootconfig.get(dup._name) +# except AttributeError: +# pass +# raise NotFoundError +# #rootconfig.get(dup._name) +# except NotFoundError: +# pass # no identical names, it's fine +# else: +# raise ConflictConfigError('duplicate option name: ' +# '{0}'.format(dup._name)) def _cfgimpl_build(self, overrides): self._validate_duplicates(self._cfgimpl_descr._children) @@ -424,7 +446,7 @@ class Config(object): self.cfgimpl_unfreeze() rootconfig = self._cfgimpl_get_toplevel() rootconfig.cfgimpl_enable_property('hidden') - rootconfig.cfgimpl_disable_property('disabled') + rootconfig.cfgimpl_enable_property('disabled') rootconfig._cfgimpl_mandatory = False # ____________________________________________________________ def getkey(self): diff --git a/tiramisu/option.py b/tiramisu/option.py index 277bc2b..0e7fa10 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -23,10 +23,15 @@ from tiramisu.basetype import HiddenBaseType, DisabledBaseType from tiramisu.error import (ConfigError, ConflictConfigError, NotFoundError, RequiresError, RequirementRecursionError, MandatoryError) -available_actions = ['hide', 'show', 'enable', 'disable', 'freeze', 'unfreeze'] -reverse_actions = {'hide': 'show', 'show': 'hide', - 'disable': 'enable', 'enable': 'disable', - 'freeze': 'unfreeze', 'unfreeze': 'freeze'} +requires_actions = [('hide', 'show'), ('enable', 'disable'), ('freeze', 'unfreeze')] + +available_actions = [] +reverse_actions = {} +for act1, act2 in requires_actions: + available_actions.extend([act1, act2]) + reverse_actions[act1] = act2 + reverse_actions[act2] = act1 + # ____________________________________________________________ # OptionDescription authorized group_type values group_types = ['default', 'family', 'group', 'master'] @@ -450,45 +455,51 @@ class OptionDescription(HiddenBaseType, DisabledBaseType): if isinstance(child, OptionDescription): child.enable() # ____________________________________________________________ + +def validate_requires_arg(requires, name): + # malformed requirements + config_action = [] + for req in requires: + if not type(req) == tuple and len(req) != 3: + raise RequiresError("malformed requirements for option:" + " {0}".format(name)) + action = req[2] + if action not in available_actions: + raise RequiresError("malformed requirements for option: {0}" + "unknown action: {1}".format(name, action)) + if reverse_actions[action] in config_action: + raise RequiresError("inconsistency in action types for option: {0}" + "action: {1} in contradiction with {2}\n" + " ({3})".format(name, action, + reverse_actions[action], requires)) + config_action.append(action) + +def build_actions(requires): + trigger_actions = {} + for require in requires: + action = require[2] + trigger_actions.setdefault(action, []).append(require) + return trigger_actions + def apply_requires(opt, config): - if hasattr(opt, '_requires'): - if opt._requires is not None: - # malformed requirements - rootconfig = config._cfgimpl_get_toplevel() - for req in opt._requires: - if not type(req) == tuple and len(req) in (3, 4): - raise RequiresError("malformed requirements for option:" - " {0}".format(opt._name)) - # all actions **must** be identical - actions = [req[2] for req in opt._requires] - action = actions[0] - for act in actions: - if act != action: - raise RequiresError("malformed requirements for option:" - " {0}".format(opt._name)) - # filters the callbacks + if hasattr(opt, '_requires') and opt._requires is not None: + rootconfig = config._cfgimpl_get_toplevel() + validate_requires_arg(opt._requires, opt._name) + # filters the callbacks + trigger_actions = build_actions(opt._requires) + for requires in trigger_actions.values(): matches = False - for req in opt._requires: - if len(req) == 3: - name, expected, action = req - inverted = False - if len(req) == 4: - name, expected, action, inverted = req - if inverted == 'inverted': - inverted = True + for require in requires: + name, expected, action = require path = config._cfgimpl_get_path() + '.' + opt._name if name.startswith(path): - raise RequirementRecursionError("malformed requirements imbrication " - "detected for option: '{0}' with requirement on: '{1}'".format(path, name)) - homeconfig, shortname = \ - rootconfig._cfgimpl_get_home_by_path(name) + raise RequirementRecursionError("malformed requirements " + "imbrication detected for option: '{0}' " + "with requirement on: '{1}'".format(path, name)) + homeconfig, shortname = rootconfig._cfgimpl_get_home_by_path(name) if shortname in homeconfig._cfgimpl_values: value = homeconfig._cfgimpl_values[shortname] - if (not inverted and value == expected) or \ - (inverted and value != expected): - if action not in available_actions: - raise RequiresError("malformed requirements" - " for option: {0}".format(opt._name)) + if value == expected: getattr(opt, action)() #.hide() or show() or... # FIXME generic programming opt.property_launch(action, False) matches = True