diff --git a/ChangeLog b/ChangeLog index ba6bfc9..065b37d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +Thu Jan 12 19:49:41 2017 +0200 Emmanuel Garette + * can mix inversed and non inversed requires + Wed Jan 11 22:56:30 2017 +0200 Emmanuel Garette * copy the context in carry_out_calculation diff --git a/test/test_requires.py b/test/test_requires.py index b428f28..2ea010c 100644 --- a/test/test_requires.py +++ b/test/test_requires.py @@ -595,8 +595,35 @@ def test_requires_requirement_append(): def test_requires_different_inverse(): a = BoolOption('activate_service', '', True) - a - raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': True, 'action': 'disabled', 'inverse': True}, {'option': a, 'expected': True, 'action': 'disabled', 'inverse': False}])") + b = IPOption('ip_address_service', '', requires=[ + {'option': a, 'expected': True, 'action': 'disabled', 'inverse': True}, + {'option': a, 'expected': True, 'action': 'disabled', 'inverse': False}]) + od = OptionDescription('service', '', [a, b]) + c = Config(od) + c.read_write() + raises(PropertiesOptionError, 'c.ip_address_service') + c.activate_service = False + raises(PropertiesOptionError, 'c.ip_address_service') + + +def test_requires_different_inverse_unicode(): + a = BoolOption('activate_service', '', True) + d = StrOption('activate_other_service', '', 'val2') + b = IPOption('ip_address_service', '', requires=[ + {'option': a, 'expected': True, 'action': 'disabled', 'inverse': True}, + {'option': d, 'expected': 'val1', 'action': 'disabled', 'inverse': False}]) + od = OptionDescription('service', '', [a, d, b]) + c = Config(od) + c.read_write() + assert c.ip_address_service == None + c.activate_service = False + raises(PropertiesOptionError, 'c.ip_address_service') + c.activate_service = True + assert c.ip_address_service == None + c.activate_other_service = 'val1' + raises(PropertiesOptionError, 'c.ip_address_service') + c.activate_service = False + raises(PropertiesOptionError, 'c.ip_address_service') def test_requires_recursive_path(): diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index d45f6a4..14d2668 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -27,7 +27,7 @@ from ..i18n import _ from ..setting import log, undefined, debug from ..autolib import carry_out_calculation from ..error import (ConfigError, ValueWarning, PropertiesOptionError, - display_list) + display_list) from ..storage import get_storages_option from . import MasterSlaves @@ -885,7 +885,7 @@ def validate_requires_arg(multi, requires, name): the description of the requires dictionary """ ret_requires = {} - config_action = {} + config_action = set() # start parsing all requires given by user (has dict) # transforme it to a tuple @@ -938,32 +938,29 @@ def validate_requires_arg(multi, requires, name): if expected is not None: err = option._validate(expected) if err: - raise ValueError(_('malformed requirements second argument ' + raise ValueError(_('malformed requirements expected value ' 'must be valid for option {0}' ': {1}').format(name, err)) - if action in config_action: - if inverse != config_action[action]: # pragma: optional cover - raise ValueError(_("inconsistency in action types" - " for option: {0}" - " action: {1}").format(name, action)) - else: - config_action[action] = inverse + config_action.add(action) if action not in ret_requires: ret_requires[action] = {} if option not in ret_requires[action]: - ret_requires[action][option] = (option, [expected], action, - inverse, transitive, same_action) + ret_requires[action][option] = {} + if inverse not in ret_requires[action][option]: + ret_requires[action][option][inverse] = (option, [expected], action, + inverse, transitive, same_action) else: - ret_requires[action][option][1].append(expected) + ret_requires[action][option][inverse][1].append(expected) # transform dict to tuple ret = [] for opt_requires in ret_requires.values(): ret_action = [] - for require in opt_requires.values(): - ret_action.append((require[0], tuple(require[1]), require[2], - require[3], require[4], require[5])) + for requires in opt_requires.values(): + for require in requires.values(): + ret_action.append((require[0], tuple(require[1]), require[2], + require[3], require[4], require[5])) ret.append(tuple(ret_action)) - return frozenset(config_action.keys()), tuple(ret) + return frozenset(config_action), tuple(ret) class SymLinkOption(OnlyOption):