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"
This commit is contained in:
Emmanuel Garette 2013-05-31 23:29:20 +02:00
parent c6c422f472
commit 2751a2694a
4 changed files with 122 additions and 10 deletions

101
test/test_requires.py Normal file
View file

@ -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

View file

@ -44,8 +44,10 @@ class ConflictError(StandardError):
#____________________________________________________________ #____________________________________________________________
# miscellaneous exceptions # miscellaneous exceptions
class RequirementRecursionError(StandardError): class RequirementError(StandardError):
"a recursive loop occurs in the requirements tree" """a recursive loop occurs in the requirements tree
requires
"""
pass pass

View file

@ -820,7 +820,7 @@ def validate_requires_arg(requires, name):
if len(req) == 3: if len(req) == 3:
action = req[2] action = req[2]
inverse = False inverse = False
elif len(req) == 4: elif len(req) in [4, 5]:
action = req[2] action = req[2]
inverse = req[3] inverse = req[3]
else: else:

View file

@ -22,7 +22,7 @@
# ____________________________________________________________ # ____________________________________________________________
from time import time from time import time
from copy import copy from copy import copy
from tiramisu.error import RequirementRecursionError, PropertiesOptionError from tiramisu.error import RequirementError, PropertiesOptionError
from tiramisu.i18n import _ from tiramisu.i18n import _
@ -278,7 +278,7 @@ class Setting(object):
else: else:
raise_text = "trying to access to an option named: {0} with properties {1}" raise_text = "trying to access to an option named: {0} with properties {1}"
raise PropertiesOptionError(_(raise_text).format(opt_or_descr._name, raise PropertiesOptionError(_(raise_text).format(opt_or_descr._name,
str(properties)), str(list(properties))),
list(properties)) list(properties))
def _get_permissive(self, opt=None): def _get_permissive(self, opt=None):
@ -355,19 +355,28 @@ def apply_requires(opt, config):
if len(require) == 3: if len(require) == 3:
option, expected, action = require option, expected, action = require
inverse = False inverse = False
transitive = True
elif len(require) == 4: elif len(require) == 4:
option, expected, action, inverse = require 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) path = descr.impl_get_path_by_opt(option)
if path == optpath or path.startswith(optpath + '.'): if path == optpath or path.startswith(optpath + '.'):
raise RequirementRecursionError(_("malformed requirements " raise RequirementError(_("malformed requirements "
"imbrication detected for option: '{0}' " "imbrication detected for option: '{0}' "
"with requirement on: '{1}'").format(optpath, path)) "with requirement on: '{1}'").format(optpath, path))
try: try:
value = config.cfgimpl_get_context()._getattr(path, force_permissive=True) value = config.cfgimpl_get_context()._getattr(path, force_permissive=True)
except PropertiesOptionError, err: except PropertiesOptionError, err:
if not transitive:
continue
properties = err.proptype properties = err.proptype
raise PropertiesOptionError(_("option '{0}' has requirement's property error: " if action not in err.proptype:
"{1} {2}").format(opt._name, path, properties), properties) 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: except AttributeError:
raise AttributeError(_("required option not found: " raise AttributeError(_("required option not found: "
"{0}").format(path)) "{0}").format(path))