From 2751a2694ac772dadab4c113ac82e61ea8b256f4 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Fri, 31 May 2013 23:29:20 +0200 Subject: [PATCH] RequirementRecursiveError => RequirementError Properties in "apply_requires" are now transitive (but only if tested property is in properties list) New requirement option (a boolean), don't touch properties if PropertyError in "apply_requires" --- test/test_requires.py | 101 ++++++++++++++++++++++++++++++++++++++++++ tiramisu/error.py | 6 ++- tiramisu/option.py | 2 +- tiramisu/setting.py | 23 +++++++--- 4 files changed, 122 insertions(+), 10 deletions(-) create mode 100644 test/test_requires.py diff --git a/test/test_requires.py b/test/test_requires.py new file mode 100644 index 0000000..bcbb01d --- /dev/null +++ b/test/test_requires.py @@ -0,0 +1,101 @@ +# coding: utf-8 +import autopath +from tiramisu import setting +setting.expires_time = 1 +from tiramisu.option import IPOption, OptionDescription, BoolOption +from tiramisu.config import Config +from tiramisu.error import PropertiesOptionError, RequirementError +from py.test import raises + + +def test_requires(): + a = BoolOption('activate_service', '', True) + b = IPOption('ip_address_service', '', + requires=[(a, False, 'disabled')]) + od = OptionDescription('service', '', [a, b]) + c = Config(od) + c.read_write() + c.ip_address_service + c.activate_service = False + props = [] + try: + c.ip_address_service + except PropertiesOptionError, err: + props = err.proptype + assert props == ['disabled'] + + +def test_requires_transitif(): + a = BoolOption('activate_service', '', True) + b = BoolOption('activate_service_web', '', True, + requires=[(a, False, 'disabled')]) + d = IPOption('ip_address_service_web', '', + requires=[(b, False, 'disabled')]) + od = OptionDescription('service', '', [a, b, d]) + c = Config(od) + c.read_write() + c.activate_service + c.activate_service_web + c.ip_address_service_web + c.activate_service = False + # + props = [] + try: + c.activate_service_web + except PropertiesOptionError, err: + props = err.proptype + assert props == ['disabled'] + # + props = [] + try: + c.ip_address_service_web + except PropertiesOptionError, err: + props = err.proptype + assert props == ['disabled'] + + +def test_requires_transitif_hidden_disabled(): + a = BoolOption('activate_service', '', True) + b = BoolOption('activate_service_web', '', True, + requires=[(a, False, 'hidden')]) + d = IPOption('ip_address_service_web', '', + requires=[(b, False, 'disabled')]) + od = OptionDescription('service', '', [a, b, d]) + c = Config(od) + c.read_write() + c.activate_service + c.activate_service_web + c.ip_address_service_web + c.activate_service = False + # + props = [] + try: + c.activate_service_web + except PropertiesOptionError, err: + props = err.proptype + assert props == ['hidden'] + raises(RequirementError, 'c.ip_address_service_web') + + +def test_requires_not_transitif(): + a = BoolOption('activate_service', '', True) + b = BoolOption('activate_service_web', '', True, + requires=[(a, False, 'disabled')]) + d = IPOption('ip_address_service_web', '', + requires=[(b, False, 'disabled', False, False)]) + od = OptionDescription('service', '', [a, b, d]) + c = Config(od) + c.read_write() + c.activate_service + c.activate_service_web + c.ip_address_service_web + c.activate_service = False + # + props = [] + try: + c.activate_service_web + except PropertiesOptionError, err: + props = err.proptype + assert props == ['disabled'] + # + c.ip_address_service_web diff --git a/tiramisu/error.py b/tiramisu/error.py index d5049d2..1e9cea3 100644 --- a/tiramisu/error.py +++ b/tiramisu/error.py @@ -44,8 +44,10 @@ class ConflictError(StandardError): #____________________________________________________________ # miscellaneous exceptions -class RequirementRecursionError(StandardError): - "a recursive loop occurs in the requirements tree" +class RequirementError(StandardError): + """a recursive loop occurs in the requirements tree + requires + """ pass diff --git a/tiramisu/option.py b/tiramisu/option.py index 47d5afe..20135d2 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -820,7 +820,7 @@ def validate_requires_arg(requires, name): if len(req) == 3: action = req[2] inverse = False - elif len(req) == 4: + elif len(req) in [4, 5]: action = req[2] inverse = req[3] else: diff --git a/tiramisu/setting.py b/tiramisu/setting.py index c9a86f0..9a9c63a 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -22,7 +22,7 @@ # ____________________________________________________________ from time import time from copy import copy -from tiramisu.error import RequirementRecursionError, PropertiesOptionError +from tiramisu.error import RequirementError, PropertiesOptionError from tiramisu.i18n import _ @@ -278,7 +278,7 @@ class Setting(object): else: raise_text = "trying to access to an option named: {0} with properties {1}" raise PropertiesOptionError(_(raise_text).format(opt_or_descr._name, - str(properties)), + str(list(properties))), list(properties)) def _get_permissive(self, opt=None): @@ -355,19 +355,28 @@ def apply_requires(opt, config): if len(require) == 3: option, expected, action = require inverse = False + transitive = True elif len(require) == 4: option, expected, action, inverse = require + transitive = True + elif len(require) == 5: + option, expected, action, inverse, transitive = require path = descr.impl_get_path_by_opt(option) if path == optpath or path.startswith(optpath + '.'): - raise RequirementRecursionError(_("malformed requirements " - "imbrication detected for option: '{0}' " - "with requirement on: '{1}'").format(optpath, path)) + raise RequirementError(_("malformed requirements " + "imbrication detected for option: '{0}' " + "with requirement on: '{1}'").format(optpath, path)) try: value = config.cfgimpl_get_context()._getattr(path, force_permissive=True) except PropertiesOptionError, err: + if not transitive: + continue properties = err.proptype - raise PropertiesOptionError(_("option '{0}' has requirement's property error: " - "{1} {2}").format(opt._name, path, properties), properties) + if action not in err.proptype: + raise RequirementError(_("option '{0}' has requirement's property error: " + "{1} {2}").format(opt._name, path, properties), properties) + #transitive action, force expected + value = expected except AttributeError: raise AttributeError(_("required option not found: " "{0}").format(path))