[Erp5-report] r40636 arnaud.fontaine - in /erp5/trunk/products/ERP5Type: Core/ PropertyShee...
nobody at svn.erp5.org
nobody at svn.erp5.org
Thu Nov 25 05:53:46 CET 2010
Author: arnaud.fontaine
Date: Thu Nov 25 05:53:46 2010
New Revision: 40636
URL: http://svn.erp5.org?rev=40636&view=rev
Log:
Add Attribute Equality Constraint for ZODB Property Sheets
Added:
erp5/trunk/products/ERP5Type/Core/AttributeEqualityConstraint.py
- copied, changed from r40345, erp5/trunk/products/ERP5Type/Constraint/AttributeEquality.py
erp5/trunk/products/ERP5Type/PropertySheet/AttributeEqualityConstraint.py
Modified:
erp5/trunk/products/ERP5Type/PropertySheet/__init__.py
erp5/trunk/products/ERP5Type/mixin/constraint.py
erp5/trunk/products/ERP5Type/tests/testDynamicClassGeneration.py
Copied: erp5/trunk/products/ERP5Type/Core/AttributeEqualityConstraint.py (from r40345, erp5/trunk/products/ERP5Type/Constraint/AttributeEquality.py)
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/AttributeEqualityConstraint.py?p2=erp5/trunk/products/ERP5Type/Core/AttributeEqualityConstraint.py&p1=erp5/trunk/products/ERP5Type/Constraint/AttributeEquality.py&r1=40345&r2=40636&rev=40636&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Constraint/AttributeEquality.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/AttributeEqualityConstraint.py [utf8] Thu Nov 25 05:53:46 2010
@@ -1,9 +1,10 @@
##############################################################################
#
-# Copyright (c) 2002, 2005 Nexedi SARL and Contributors. All Rights Reserved.
-# Sebastien Robin <seb at nexedi.com>
-# Jean-Paul Smets <jp at nexedi.com>
-# Romain Courteaud <romain at nexedi.com>
+# Copyright (c) 2002-2010 Nexedi SARL and Contributors. All Rights Reserved.
+# Sebastien Robin <seb at nexedi.com>
+# Jean-Paul Smets <jp at nexedi.com>
+# Romain Courteaud <romain at nexedi.com>
+# Arnaud Fontaine <arnaud.fontaine at nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
@@ -28,21 +29,40 @@
#
##############################################################################
-from PropertyExistence import PropertyExistence
+from Products.ERP5Type.mixin.constraint import ConstraintMixin
+from AccessControl import ClassSecurityInfo
+from Products.ERP5Type import Permissions, PropertySheet
+from Products.CMFCore.Expression import Expression
+from Products.ERP5Type.Utils import createExpressionContext
-class AttributeEquality(PropertyExistence):
+class AttributeEqualityConstraint(ConstraintMixin):
"""
- This constraint class allows to check / fix
- attribute values.
- Configuration example:
- { 'id' : 'title',
- 'description' : 'Title must be "ObjectTitle"',
- 'type' : 'AttributeEquality',
- 'title' : 'ObjectTitle',
- 'condition' : 'python: object.getPortalType() == 'Foo',
- },
+ This constraint checks the values of a given attribute name on this
+ object. This is only relevant for ZODB Property Sheets (filesystem
+ Property Sheets rely on Products.ERP5Type.Constraint.PropertyExistence
+ instead). Note that the attribute expected value is now a TALES
+ Expression to be able to use any Python type and not only strings.
+
+ For example, if we would like to check whether the attribute 'title'
+ has 'ObjectTitle' as its value, we would create a 'Attribute
+ Equality Constraint' within that Property Sheet and set 'title' as
+ the 'Attribute Name' and 'python: "ObjectTitle"' as the 'Attribute
+ Value', then set the 'Predicate' if necessary (known as 'condition'
+ for filesystem Property Sheets).
"""
+ meta_type = 'ERP5 Attribute Equality Constraint'
+ portal_type = 'Attribute Equality Constraint'
+
+ # Declarative security
+ security = ClassSecurityInfo()
+ security.declareObjectProtected(Permissions.AccessContentsInformation)
+ property_sheets = (PropertySheet.SimpleItem,
+ PropertySheet.Predicate,
+ PropertySheet.Reference,
+ PropertySheet.AttributeEqualityConstraint)
+
+ # Define by default error messages
_message_id_list = ['message_invalid_attribute_value',
'message_invalid_attribute_value_fixed']
message_invalid_attribute_value = "Attribute ${attribute_name} "\
@@ -50,44 +70,60 @@ class AttributeEquality(PropertyExistenc
message_invalid_attribute_value_fixed = "Attribute ${attribute_name} "\
"value is ${current_value} but should be ${expected_value} (Fixed)"
- def checkConsistency(self, obj, fixit=0):
- """Check the object's consistency.
- We will make sure that each non None constraint_definition is
- satisfied (equality)
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'checkConsistency')
+ def checkConsistency(self, obj, fixit=False):
+ """
+ Check the object's consistency.
"""
- if not self._checkConstraintCondition(obj):
+ if not self.test(obj):
return []
- errors = PropertyExistence.checkConsistency(self, obj, fixit=fixit)
- for attribute_name, expected_value in self.constraint_definition.items():
- message_id = None
- mapping = dict()
- # If property does not exist, error will be raised by
- # PropertyExistence Constraint.
- if obj.hasProperty(attribute_name):
- identical = 1
- if isinstance(expected_value, (list, tuple)):
- # List type
- if len(obj.getProperty(attribute_name)) != len(expected_value):
- identical = 0
- else:
- for item in obj.getProperty(attribute_name):
- if item not in expected_value:
- identical = 0
- break
+
+ attribute_name = self.getConstraintAttributeName()
+
+ # If property does not exist, error will be raised by
+ # PropertyExistence Constraint, but the value has to be set at
+ # least once as there is no need to perform any check if it is the
+ # default value
+ if obj.hasProperty(attribute_name):
+ identical = True
+
+ # The expected value of the attribute is a TALES Expression
+ attribute_expected_value_expression = Expression(
+ self.getConstraintAttributeValue())
+
+ attribute_expected_value = attribute_expected_value_expression(
+ createExpressionContext(obj))
+
+ attribute_value = obj.getProperty(attribute_name)
+
+ if isinstance(attribute_expected_value, (list, tuple)):
+ # List type
+ if len(attribute_value) != len(attribute_expected_value):
+ identical = False
else:
- # Other type
- identical = (expected_value == obj.getProperty(attribute_name))
- if not identical:
- message_id = 'message_invalid_attribute_value'
- mapping(attribute_name=attribute_name,
- attribute_value=obj.getProperty(attribute_name),
- expected_value=expected_value)
- # Generate error
- if message_id is not None:
+ for item in attribute_value:
+ if item not in attribute_expected_value:
+ identical = False
+ break
+ else:
+ # Other primitive type
+ identical = (attribute_expected_value == attribute_value)
+
+ if not identical:
+ # Generate error and fix it if required
if fixit:
- obj._setProperty(attribute_name, expected_value)
+ obj._setProperty(attribute_name, attribute_expected_value)
message_id = 'message_invalid_attribute_value_fixed'
- errors.append(self._generateError(obj,
- self._getMessage(message_id), mapping))
- return errors
+ else:
+ message_id = 'message_invalid_attribute_value'
+
+ error = self._generateError(
+ obj, self._getMessage(message_id),
+ dict(attribute_name=attribute_name,
+ attribute_value=attribute_value,
+ expected_value=attribute_expected_value))
+
+ return [error]
+ return []
Added: erp5/trunk/products/ERP5Type/PropertySheet/AttributeEqualityConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/PropertySheet/AttributeEqualityConstraint.py?rev=40636&view=auto
==============================================================================
--- erp5/trunk/products/ERP5Type/PropertySheet/AttributeEqualityConstraint.py (added)
+++ erp5/trunk/products/ERP5Type/PropertySheet/AttributeEqualityConstraint.py [utf8] Thu Nov 25 05:53:46 2010
@@ -0,0 +1,46 @@
+##############################################################################
+#
+# Copyright (c) 2010 Nexedi SARL and Contributors. All Rights Reserved.
+# Arnaud Fontaine <arnaud.fontaine at nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+class AttributeEqualityConstraint:
+ """
+ Define an Attribute Equality Constraint for ZODB Property Sheets
+ """
+ _properties = (
+ { 'id': 'constraint_attribute_name',
+ 'type': 'string',
+ 'description' : 'Attribute name whose values are checked' },
+ { 'id': 'constraint_attribute_value',
+ 'type': 'string',
+ 'description' : 'Valid values of the Attribute' },
+ { 'id': 'message_invalid_attribute_value',
+ 'type': 'string',
+ 'description' : 'Error message when the attribute value is invalid' },
+ { 'id': 'message_invalid_attribute_value_fixed',
+ 'type': 'string',
+ 'description' : 'Error message when the attribute value is invalid but has been fixed' },
+ )
Modified: erp5/trunk/products/ERP5Type/PropertySheet/__init__.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/PropertySheet/__init__.py?rev=40636&r1=40635&r2=40636&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/PropertySheet/__init__.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/PropertySheet/__init__.py [utf8] Thu Nov 25 05:53:46 2010
@@ -19,3 +19,4 @@ from AcquiredProperty import AcquiredPro
from DynamicCategoryProperty import DynamicCategoryProperty
from CategoryExistenceConstraint import CategoryExistenceConstraint
from PropertyExistenceConstraint import PropertyExistenceConstraint
+from AttributeEqualityConstraint import AttributeEqualityConstraint
Modified: erp5/trunk/products/ERP5Type/mixin/constraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/mixin/constraint.py?rev=40636&r1=40635&r2=40636&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/mixin/constraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/mixin/constraint.py [utf8] Thu Nov 25 05:53:46 2010
@@ -42,6 +42,10 @@ class ConstraintMixin(Predicate):
Mixin Constraint implementation (only relevant for ZODB Property
sheets, use Products.ERP5Type.Constraint instead for filesystem
Property Sheets) relying on Predicate
+
+ @todo: Add code to import constraints requiring a new TALES
+ Expression field in predicate to be able to import
+ 'condition' properly
"""
# Declarative security
security = ClassSecurityInfo()
Modified: erp5/trunk/products/ERP5Type/tests/testDynamicClassGeneration.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/tests/testDynamicClassGeneration.py?rev=40636&r1=40635&r2=40636&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/tests/testDynamicClassGeneration.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/tests/testDynamicClassGeneration.py [utf8] Thu Nov 25 05:53:46 2010
@@ -284,7 +284,10 @@ class TestZodbPropertySheet(ERP5TypeTest
id=base_category_id, portal_type='Base Category')
# Create a dummy sub-category
- new_base_category.newContent(reference='sub_category',
+ new_base_category.newContent(reference='sub_category1',
+ portal_type='Category')
+
+ new_base_category.newContent(reference='sub_category2',
portal_type='Category')
if operation_type == 'change':
@@ -343,6 +346,25 @@ class TestZodbPropertySheet(ERP5TypeTest
# XXX
# constraint_portal_type=('TODO',))
+ def _newAttributeEqualityConstraint(self):
+ """
+ Create a new Attribute Equality Constraint within test Property
+ Sheet
+ """
+ # For testing primitive type as attribute value
+ self.test_property_sheet.newContent(
+ reference='test_attribute_equality_constraint',
+ portal_type='Attribute Equality Constraint',
+ constraint_attribute_name='title',
+ constraint_attribute_value='python: "my_valid_title"')
+
+ # For testing list type as attribute value
+ self.test_property_sheet.newContent(
+ reference='test_attribute_list_equality_constraint',
+ portal_type='Attribute Equality Constraint',
+ constraint_attribute_name='categories_list',
+ constraint_attribute_value='python: ("sub_category1", "sub_category2")')
+
def afterSetUp(self):
"""
Create a test Property Sheet (and its properties)
@@ -369,6 +391,10 @@ class TestZodbPropertySheet(ERP5TypeTest
# Sheet
self._newCategoryExistenceConstraint()
+ # Create an Attribute Equality Constraint in the test Property
+ # Sheet
+ self._newAttributeEqualityConstraint()
+
# Create all the test Properties
for operation_type in ('change', 'delete', 'assign'):
self._newStandardProperty(operation_type)
@@ -503,19 +529,19 @@ class TestZodbPropertySheet(ERP5TypeTest
# Category Property
self.assertHasAttribute(new_person, 'setTestCategoryPropertyAssign')
- new_person.setTestCategoryPropertyAssign('sub_category')
+ new_person.setTestCategoryPropertyAssign('sub_category1')
self.assertEquals(new_person.getTestCategoryPropertyAssign(),
- 'sub_category')
+ 'sub_category1')
# Dynamic Category Property
self.assertHasAttribute(new_person,
'setTestDynamicCategoryPropertyAssign')
- new_person.setTestDynamicCategoryPropertyAssign('sub_category')
+ new_person.setTestDynamicCategoryPropertyAssign('sub_category1')
self.assertEquals(new_person.getTestDynamicCategoryPropertyAssign(),
- 'sub_category')
+ 'sub_category1')
finally:
# Perform a commit here because Workflow interactions keeps a
@@ -729,10 +755,6 @@ class TestZodbPropertySheet(ERP5TypeTest
constraint_reference,
setter_function,
value):
- """
- Check whether the given constraint has been properly defined and
- checkConsistency() is correct
- """
constraint = self._getConstraintByReference(constraint_reference)
self.failIfEqual(None, constraint)
self.assertEquals(1, len(constraint.checkConsistency(self.test_module)))
@@ -745,9 +767,8 @@ class TestZodbPropertySheet(ERP5TypeTest
Take the test module and check whether the Property Existence
Constraint is available. Until the property has been set to a
value, the constraint should fail
-
- @see ERP5Type.Base.Base.hasProperty
"""
+ # See ERP5Type.Base.Base.hasProperty()
self._checkConstraint('test_property_existence_constraint',
self.test_module.setTestStandardPropertyConstraint,
'foobar')
@@ -760,7 +781,38 @@ class TestZodbPropertySheet(ERP5TypeTest
"""
self._checkConstraint('test_category_existence_constraint',
self.test_module.setTestCategoryPropertyConstraint,
- 'sub_category')
+ 'sub_category1')
+
+ def testAttributeEqualityConstraint(self):
+ """
+ Take the test module and check whether the Attribute Equality
+ Constraint is available. Until the attribute to be checked has
+ been set to its expected value, the constraint should fail. The
+ purpose is to test only primitive types (e.g. not list)
+ """
+ # As checkConsistency calls hasProperty before checking the value,
+ # the property to be tested has to be set at least once (whatever
+ # the value)
+ self.test_module.setTitle('invalid_value')
+
+ self._checkConstraint('test_attribute_equality_constraint',
+ self.test_module.setTitle,
+ 'my_valid_title')
+
+ def testAttributeListEqualityConstraint(self):
+ """
+ Take the test module and check whether the Attribute Equality
+ Constraint is available. Until the attribute to be checked has
+ been set to its expected value (a list of categories), the
+ constraint should fail. The purpose is to test only list types
+
+ @see testAttributeEqualityConstraint
+ """
+ self.test_module.setCategoryList(('sub_category1',))
+
+ self._checkConstraint('test_attribute_list_equality_constraint',
+ self.test_module.setCategoryList,
+ ('sub_category1', 'sub_category2'))
TestZodbPropertySheet = skip("ZODB Property Sheets code is not enabled yet")(
TestZodbPropertySheet)
More information about the Erp5-report
mailing list