RequirementRecursiveError => RequirementError
authorEmmanuel Garette <egarette@cadoles.com>
Fri, 31 May 2013 21:29:20 +0000 (23:29 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Fri, 31 May 2013 21:30:00 +0000 (23:30 +0200)
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 [new file with mode: 0644]
tiramisu/error.py
tiramisu/option.py
tiramisu/setting.py

diff --git a/test/test_requires.py b/test/test_requires.py
new file mode 100644 (file)
index 0000000..bcbb01d
--- /dev/null
@@ -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
index d5049d2..1e9cea3 100644 (file)
@@ -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
 
 
index 47d5afe..20135d2 100644 (file)
@@ -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:
index c9a86f0..9a9c63a 100644 (file)
@@ -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))