[Erp5-report] r42929 arnaud.fontaine - in /erp5/trunk/products: ERP5/Document/ ERP5Type/Cor...
nobody at svn.erp5.org
nobody at svn.erp5.org
Wed Feb 2 13:52:45 CET 2011
Author: arnaud.fontaine
Date: Wed Feb 2 13:52:44 2011
New Revision: 42929
URL: http://svn.erp5.org?rev=42929&view=rev
Log:
* Allow import of Filesystem Constraints to ZODB Constraints for
Property Sheets and export of ZODB Constraints to Filesystem
Constraints.
* Merge CategoryAcquiredExistenceConstraint into CategoryExistenceConstraint
and CategoryAcquiredMembershipArityConstraint into
CategoryMembershipArityConstraint.
* Fix constraint_portal_type for CategoryExistenceConstraint and
CategoryMembershipArityConstraint for ZODB Constraints which must be
a TALES Expression, like filesystem Constraints.
* Add tests to check import and export of ZODB Constraints.
Modified:
erp5/trunk/products/ERP5/Document/AccountingTransactionBalanceConstraint.py
erp5/trunk/products/ERP5/Document/ResourceMeasuresConsistencyConstraint.py
erp5/trunk/products/ERP5/Document/TradeModelLineCellConsistencyConstraint.py
erp5/trunk/products/ERP5/Document/TransactionQuantityValueFeasabilityConstraint.py
erp5/trunk/products/ERP5/Document/TransactionQuantityValueValidityConstraint.py
erp5/trunk/products/ERP5Type/Core/AttributeEqualityConstraint.py
erp5/trunk/products/ERP5Type/Core/CategoryAcquiredMembershipArityConstraint.py
erp5/trunk/products/ERP5Type/Core/CategoryExistenceConstraint.py
erp5/trunk/products/ERP5Type/Core/CategoryMembershipArityConstraint.py
erp5/trunk/products/ERP5Type/Core/CategoryRelatedMembershipArityConstraint.py
erp5/trunk/products/ERP5Type/Core/ContentExistenceConstraint.py
erp5/trunk/products/ERP5Type/Core/PropertyExistenceConstraint.py
erp5/trunk/products/ERP5Type/Core/PropertyTypeValidityConstraint.py
erp5/trunk/products/ERP5Type/Core/TALESConstraint.py
erp5/trunk/products/ERP5Type/Tool/PropertySheetTool.py
erp5/trunk/products/ERP5Type/mixin/constraint.py
erp5/trunk/products/ERP5Type/tests/testDynamicClassGeneration.py
Modified: erp5/trunk/products/ERP5/Document/AccountingTransactionBalanceConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/AccountingTransactionBalanceConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/AccountingTransactionBalanceConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/AccountingTransactionBalanceConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -32,7 +32,7 @@ from Products.ERP5Type import PropertySh
class AccountingTransactionBalanceConstraint(ConstraintMixin):
"""
- Check that accounting transaction total debit and total credit are equals.
+ Check that accounting transaction total debit and total credit are equal.
This is only relevant for ZODB Property Sheets (filesystem Property
Sheets rely on Products.ERP5.Constraint.AccountingTransactionBalance
@@ -41,6 +41,8 @@ class AccountingTransactionBalanceConstr
meta_type = 'ERP5 Accounting Transaction Balance Constraint'
portal_type = 'Accounting Transaction Balance Constraint'
+ __compatibility_class_name__ = 'AccountingTransactionBalance'
+
property_sheets = ConstraintMixin.property_sheets + \
(PropertySheet.AccountingTransactionBalanceConstraint,)
@@ -89,3 +91,6 @@ class AccountingTransactionBalanceConstr
break
return error_list
+
+ _message_id_tuple = ('message_transaction_not_balanced_for_source',
+ 'message_transaction_not_balanced_for_destination')
Modified: erp5/trunk/products/ERP5/Document/ResourceMeasuresConsistencyConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/ResourceMeasuresConsistencyConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/ResourceMeasuresConsistencyConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/ResourceMeasuresConsistencyConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -43,6 +43,8 @@ class ResourceMeasuresConsistencyConstra
meta_type = 'ERP5 Resource Measures Consistency Constraint'
portal_type = 'Resource Measures Consistency Constraint'
+ __compatibility_class_name__ = 'ResourceMeasuresConsistency'
+
property_sheets = ConstraintMixin.property_sheets + \
(PropertySheet.ResourceMeasuresConsistencyConstraint,)
@@ -103,3 +105,9 @@ class ResourceMeasuresConsistencyConstra
error('message_missing_metric_type', metric_type=quantity)
return error_list
+
+ _message_id_tuple = ('message_measure_no_quantity_unit',
+ 'message_measure_no_quantity',
+ 'message_duplicate_metric_type',
+ 'message_duplicate_default_measure',
+ 'message_missing_metric_type')
Modified: erp5/trunk/products/ERP5/Document/TradeModelLineCellConsistencyConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/TradeModelLineCellConsistencyConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/TradeModelLineCellConsistencyConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/TradeModelLineCellConsistencyConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -42,6 +42,8 @@ class TradeModelLineCellConsistencyConst
meta_type = 'ERP5 Trade Model Line Cell Consistency Constraint'
portal_type = 'Trade Model Line Cell Consistency Constraint'
+ __compatibility_class_name__ = 'TradeModelLineCellConsistency'
+
property_sheets = ConstraintMixin.property_sheets + \
(PropertySheet.TradeModelLineCellConsistencyConstraint,)
@@ -57,3 +59,20 @@ class TradeModelLineCellConsistencyConst
mapping=dict(line=document.getTitle()))]
return []
+
+ _message_id_tuple = ('message_cell_inexistance',)
+
+ @staticmethod
+ def _convertFromFilesystemDefinition(base_id):
+ """
+ @see ERP5Type.mixin.constraint.ConstraintMixin._convertFromFilesystemDefinition
+ """
+ yield dict(base_id=base_id)
+
+ def exportToFilesystemDefinitionDict(self):
+ filesystem_definition_dict = super(TradeModelLineCellConsistencyConstraint,
+ self).exportToFilesystemDefinitionDict()
+
+ filesystem_definition_dict['base_id'] = self.getBaseId()
+
+ return filesystem_definition_dict
Modified: erp5/trunk/products/ERP5/Document/TransactionQuantityValueFeasabilityConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/TransactionQuantityValueFeasabilityConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/TransactionQuantityValueFeasabilityConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/TransactionQuantityValueFeasabilityConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -41,6 +41,8 @@ class TransactionQuantityValueFeasabilit
meta_type = 'ERP5 Transaction Quantity Value Feasability Constraint'
portal_type = 'Transaction Quantity Value Feasability Constraint'
+ __compatibility_class_name__ = 'TransactionQuantityValueFeasability'
+
def _checkConsistency(self, object, fixit=0):
"""
Check if the quantity of the transaction is possible
Modified: erp5/trunk/products/ERP5/Document/TransactionQuantityValueValidityConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/TransactionQuantityValueValidityConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/TransactionQuantityValueValidityConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/TransactionQuantityValueValidityConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -38,6 +38,8 @@ class TransactionQuantityValueValidityCo
meta_type = 'ERP5 Transaction Quantity Value Validity Constraint'
portal_type = 'Transaction Quantity Value Validity Constraint'
+ __compatibility_class_name__ = 'TransactionQuantityValueValidity'
+
def _checkConsistency(self, object, fixit=0):
"""
Check if the quantity of the transaction is greater than the
Modified: erp5/trunk/products/ERP5Type/Core/AttributeEqualityConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/AttributeEqualityConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Core/AttributeEqualityConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/AttributeEqualityConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -35,6 +35,7 @@ from Products.ERP5Type.Core.PropertyExis
from Products.ERP5Type.mixin.constraint import ConstraintMixin
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
+from Products.CMFCore.Expression import Expression
class AttributeEqualityConstraint(PropertyExistenceConstraint):
"""
@@ -58,6 +59,8 @@ class AttributeEqualityConstraint(Proper
meta_type = 'ERP5 Attribute Equality Constraint'
portal_type = 'Attribute Equality Constraint'
+ __compatibility_class_name__ = 'AttributeEquality'
+
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
@@ -67,7 +70,7 @@ class AttributeEqualityConstraint(Proper
def _checkConsistency(self, obj, fixit=False):
"""
- Check the object's consistency.
+ Check the object's consistency
"""
attribute_name = self.getConstraintAttributeName()
@@ -113,3 +116,32 @@ class AttributeEqualityConstraint(Proper
return [error]
return []
+
+ _message_id_tuple = ('message_property_not_set',
+ 'message_invalid_attribute_value',
+ 'message_invalid_attribute_value_fixed')
+
+ @staticmethod
+ def _convertFromFilesystemDefinition(**property_dict):
+ """
+ @see ERP5Type.mixin.constraint.ConstraintMixin._convertFromFilesystemDefinition
+
+ One constraint per property is created. Filesystem definition example:
+ { 'id' : 'title',
+ 'description' : 'Title must be "ObjectTitle"',
+ 'type' : 'AttributeEquality',
+ 'title' : 'ObjectTitle',
+ 'condition' : 'python: object.getPortalType() == 'Foo',
+ }
+ """
+ for name, value in property_dict.iteritems():
+ yield dict(name=value)
+
+ def exportToFilesystemDefinitionDict(self):
+ filesystem_definition_dict = super(AttributeEqualityConstraint,
+ self).exportToFilesystemDefinitionDict()
+
+ filesystem_definition_dict[self.getConstraintAttributeName()] = \
+ Expression(self.getConstraintAttributeValue())
+
+ return filesystem_definition_dict
Modified: erp5/trunk/products/ERP5Type/Core/CategoryAcquiredMembershipArityConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/CategoryAcquiredMembershipArityConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Core/CategoryAcquiredMembershipArityConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/CategoryAcquiredMembershipArityConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -1,57 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002-2010 Nexedi SARL and Contributors. All Rights Reserved.
-# Sebastien Robin <seb 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
-# 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.
-#
-##############################################################################
-
-from Products.ERP5Type.Core.CategoryMembershipArityConstraint \
- import CategoryMembershipArityConstraint
-
-class CategoryAcquiredMembershipArityConstraint(CategoryMembershipArityConstraint):
- """
- This constraint checks if an object respects the arity with
- Acquisition.
-
- This is only relevant for ZODB Property Sheets (filesystem Property
- Sheets rely on Products.ERP5Type.Constraint.CategoryAcquiredMembershipArity
- instead).
-
- For example, if we would like to check whether the object respects a
- minimum arity of '1' and a maximum arity of '1 for the Portal Type
- 'Organisation' and the Base Category 'source', then we would create
- a 'Category Acquired Membership Arity Constraint' within that
- Property Sheet and set 'Minimum arity' to '1', 'Maximum Arity' to
- '1', 'Portal Types' to 'Organisation', 'Base Categories' to
- 'source', then set the 'Predicate' if necessary (known as
- 'condition' for filesystem Property Sheets).
- """
- meta_type = 'ERP5 Category Acquired Membership Arity Constraint'
- portal_type = 'Category Acquired Membership Arity Constraint'
-
- def _calculateArity(self, obj, base_category_list, portal_type_list):
- return len(obj.getAcquiredCategoryMembershipList(
- base_category_list, portal_type=portal_type_list))
Modified: erp5/trunk/products/ERP5Type/Core/CategoryExistenceConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/CategoryExistenceConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Core/CategoryExistenceConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/CategoryExistenceConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -29,13 +29,15 @@
##############################################################################
from Products.ERP5Type.mixin.constraint import ConstraintMixin
+from Products.CMFCore.Expression import Expression
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
class CategoryExistenceConstraint(ConstraintMixin):
"""
This constraint checks whether a category has been defined on this
- object (without acquisition).
+ object (with or without acquisition depending on use_acquisition
+ value).
This is only relevant for ZODB Property Sheets (filesystem Property
Sheets rely on Products.ERP5Type.Constraint.CategoryExistence
@@ -44,6 +46,8 @@ class CategoryExistenceConstraint(Constr
meta_type = 'ERP5 Category Existence Constraint'
portal_type = 'Category Existence Constraint'
+ __compatibility_class_name__ = 'CategoryExistence'
+
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
@@ -52,8 +56,13 @@ class CategoryExistenceConstraint(Constr
(PropertySheet.CategoryExistenceConstraint,)
def _calculateArity(self, obj, base_category, portal_type_list):
- return len(obj.getCategoryMembershipList(base_category,
- portal_type=portal_type_list))
+ if self.getUseAcquisition():
+ category_membership_list_function = obj.getAcquiredCategoryMembershipList
+ else:
+ category_membership_list_function = obj.getCategoryMembershipList
+
+ return len(category_membership_list_function(base_category,
+ portal_type=portal_type_list))
def _checkConsistency(self, obj, fixit=0):
"""
@@ -81,13 +90,54 @@ class CategoryExistenceConstraint(Constr
return error_list
-class CategoryAcquiredExistenceConstraint(CategoryExistenceConstraint):
- """
- This constraint checks whether a category has been defined on this
- object (with acquisition). This is only relevant for ZODB Property
- Sheets (filesystem Property Sheets rely on
- Products.ERP5Type.Constraint.CategoryExistence instead).
- """
- def _calculateArity(self, obj, base_category, portal_type_list):
- return len(obj.getAcquiredCategoryMembershipList(
- base_category, portal_type=portal_type_list))
+ _message_id_tuple = ('message_category_not_set',
+ 'message_category_not_associated_with_portal_type')
+
+ @staticmethod
+ def _preConvertBaseFromFilesystemDefinition(filesystem_definition_dict):
+ """
+ CategoryExistence and CategoryAcquiredExistence filesystem
+ Constraints have been merged into a single Document for ZODB
+ Constraint by adding 'use_acquisition' attribute
+ """
+ return dict(use_acquisition=(filesystem_definition_dict['type'] == \
+ 'CategoryAcquiredExistence'))
+
+ @staticmethod
+ def _convertFromFilesystemDefinition(portal_type=(),
+ **base_category_dict):
+ """
+ @see ERP5Type.mixin.constraint.ConstraintMixin._convertFromFilesystemDefinition
+
+ Filesystem definition example:
+ { 'id' : 'category_existence',
+ 'description' : 'Category causality must be defined',
+ 'type' : 'CategoryExistence',
+ 'portal_type' : ('Person', 'Organisation'),
+ 'causality' : None,
+ 'condition' : 'python: object.getPortalType() == 'Foo',
+ }
+ """
+ constraint_portal_type_str = isinstance(portal_type, Expression) and \
+ portal_type.text or 'python: ' + repr(portal_type)
+
+ yield dict(constraint_base_category_list=base_category_dict.keys(),
+ constraint_portal_type=constraint_portal_type_str)
+
+ def exportToFilesystemDefinitionDict(self):
+ filesystem_definition_dict = super(CategoryExistenceConstraint,
+ self).exportToFilesystemDefinitionDict()
+
+ # There is only one ZODB Constraint class for filesystem
+ # Constraints CategoryExistence and CategoryAcquiredExistence
+ # constraints
+ if self.getUseAcquisition():
+ filesystem_definition_dict['type'] = 'CategoryAcquiredExistence'
+
+ filesystem_definition_dict['portal_type'] = \
+ Expression(self.getConstraintPortalType())
+
+ for category in self.getConstraintBaseCategoryList():
+ filesystem_definition_dict[category] = 1
+
+ return filesystem_definition_dict
Modified: erp5/trunk/products/ERP5Type/Core/CategoryMembershipArityConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/CategoryMembershipArityConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Core/CategoryMembershipArityConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/CategoryMembershipArityConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -29,12 +29,14 @@
##############################################################################
from Products.ERP5Type.mixin.constraint import ConstraintMixin
+from Products.CMFCore.Expression import Expression
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
class CategoryMembershipArityConstraint(ConstraintMixin):
"""
- This constraint checks if an object respects the arity.
+ This constraint checks if an object respects the arity (with or
+ without acquisition depending on use_acquisition value).
This is only relevant for ZODB Property Sheets (filesystem Property
Sheets rely on Products.ERP5Type.Constraint.CategoryMembershipArity
@@ -52,6 +54,8 @@ class CategoryMembershipArityConstraint(
meta_type = 'ERP5 Category Membership Arity Constraint'
portal_type = 'Category Membership Arity Constraint'
+ __compatibility_class_name__ = 'CategoryMembershipArity'
+
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
@@ -102,3 +106,73 @@ class CategoryMembershipArityConstraint(
return [self._generateError(obj,
self._getMessage(message_id),
mapping)]
+
+
+ _message_id_tuple = ('message_arity_too_small',
+ 'message_arity_not_in_range',
+ 'message_arity_with_portal_type_too_small',
+ 'message_arity_with_portal_type_not_in_range')
+
+ @staticmethod
+ def _preConvertBaseFromFilesystemDefinition(filesystem_definition_dict):
+ """
+ CategoryAcquiredMembershipArity and CategoryMembershipArity
+ filesystem Constraints have been merged into a single Document for
+ ZODB Constraint by adding 'use_acquisition' attribute
+ """
+ return dict(use_acquisition=(filesystem_definition_dict['type'] == \
+ 'CategoryAcquiredMembershipArity'))
+
+ @staticmethod
+ def _convertFromFilesystemDefinition(min_arity,
+ portal_type=(),
+ max_arity=None,
+ base_category=()):
+ """
+ @see ERP5Type.mixin.constraint.ConstraintMixin._convertFromFilesystemDefinition
+
+ Filesystem definition example:
+ { 'id' : 'source',
+ 'description' : '',
+ 'type' : 'CategoryMembershipArity',
+ 'min_arity' : '1',
+ 'max_arity' : '1',
+ 'portal_type' : ('Organisation', ),
+ 'base_category' : ('source',)
+ 'condition' : 'python: object.getPortalType() == 'Foo',
+ }
+ """
+ constraint_portal_type_str = isinstance(portal_type, Expression) and \
+ portal_type.text or 'python: ' + repr(portal_type)
+
+ zodb_property_dict = dict(
+ min_arity=int(min_arity),
+ constraint_portal_type=constraint_portal_type_str,
+ constraint_base_category_list=base_category)
+
+ if max_arity is not None:
+ zodb_property_dict['max_arity'] = int(max_arity)
+
+ yield zodb_property_dict
+
+ def exportToFilesystemDefinitionDict(self):
+ filesystem_definition_dict = super(CategoryMembershipArityConstraint,
+ self).exportToFilesystemDefinitionDict()
+
+ # There is only one ZODB Constraint class for filesystem
+ # Constraints CategoryMembershipArity and
+ # CategoryAcquiredMembershipArity constraints
+ if self.getUseAcquisition():
+ filesystem_definition_dict['type'] = 'CategoryAcquiredMembershipArity'
+
+ filesystem_definition_dict['min_arity'] = str(self.getMinArity())
+
+ if self.hasMaxArity():
+ filesystem_definition_dict['max_arity'] = str(self.getMaxArity())
+
+ filesystem_definition_dict['portal_type'] = \
+ Expression(self.getConstraintPortalType())
+
+ filesystem_definition_dict['base_category'] = self.getConstraintBaseCategoryList()
+
+ return filesystem_definition_dict
Modified: erp5/trunk/products/ERP5Type/Core/CategoryRelatedMembershipArityConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/CategoryRelatedMembershipArityConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Core/CategoryRelatedMembershipArityConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/CategoryRelatedMembershipArityConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -57,6 +57,8 @@ class CategoryRelatedMembershipArityCons
meta_type = 'ERP5 Category Related Membership Arity Constraint'
portal_type = 'Category Related Membership Arity Constraint'
+ __compatibility_class_name__ = 'CategoryRelatedMembershipArity'
+
property_sheets = CategoryMembershipArityConstraint.property_sheets + \
(PropertySheet.CategoryRelatedMembershipArityConstraint,)
Modified: erp5/trunk/products/ERP5Type/Core/ContentExistenceConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/ContentExistenceConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Core/ContentExistenceConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/ContentExistenceConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -28,6 +28,7 @@
##############################################################################
from Products.ERP5Type.mixin.constraint import ConstraintMixin
+from Products.CMFCore.Expression import Expression
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
@@ -53,6 +54,8 @@ class ContentExistenceConstraint(Constra
meta_type = 'ERP5 Content Existence Constraint'
portal_type = 'Content Existence Constraint'
+ __compatibility_class_name__ = 'ContentExistence'
+
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
@@ -87,3 +90,32 @@ class ContentExistenceConstraint(Constra
return [self._generateError(obj,
self._getMessage(message_id),
mapping)]
+
+ _message_id_tuple = ('message_no_subobject',
+ 'message_no_subobject_portal_type')
+
+ @staticmethod
+ def _convertFromFilesystemDefinition(portal_type=()):
+ """
+ @see ERP5Type.mixin.constraint.ConstraintMixin._convertFromFilesystemDefinition
+
+ Filesystem definition example:
+ { 'id' : 'line',
+ 'description' : 'Object have to contain a Line',
+ 'type' : 'ContentExistence',
+ 'portal_type' : ('Line', ),
+ }
+ """
+ constraint_portal_type_str = isinstance(portal_type, Expression) and \
+ portal_type.text or 'python: ' + repr(portal_type)
+
+ yield dict(constraint_portal_type=constraint_portal_type_str)
+
+ def exportToFilesystemDefinitionDict(self):
+ filesystem_definition_dict = super(ContentExistenceConstraint,
+ self).exportToFilesystemDefinitionDict()
+
+ filesystem_definition_dict['portal_type'] = \
+ Expression(self.getConstraintPortalType())
+
+ return filesystem_definition_dict
Modified: erp5/trunk/products/ERP5Type/Core/PropertyExistenceConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/PropertyExistenceConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Core/PropertyExistenceConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/PropertyExistenceConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -50,6 +50,8 @@ class PropertyExistenceConstraint(Constr
meta_type = 'ERP5 Property Existence Constraint'
portal_type = 'Property Existence Constraint'
+ __compatibility_class_name__ = 'PropertyExistence'
+
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
@@ -71,7 +73,7 @@ class PropertyExistenceConstraint(Constr
def _checkConsistency(self, obj, fixit=False):
"""
- Check the object's consistency.
+ Check the object's consistency
"""
error_list = []
# For each attribute name, we check if defined
@@ -83,3 +85,29 @@ class PropertyExistenceConstraint(Constr
dict(property_id=property_id)))
return error_list
+
+ _message_id_tuple = ('message_no_such_property',)
+
+ @staticmethod
+ def _convertFromFilesystemDefinition(**property_dict):
+ """
+ @see ERP5Type.mixin.constraint.ConstraintMixin._convertFromFilesystemDefinition
+
+ Filesystem definition example:
+ { 'id' : 'property_existence',
+ 'description' : 'Property price must be defined',
+ 'type' : 'PropertyExistence',
+ 'price' : None,
+ 'condition' : 'python: object.getPortalType() == 'Foo',
+ }
+ """
+ yield dict(constraint_property_list=property_dict.keys())
+
+ def exportToFilesystemDefinitionDict(self):
+ filesystem_definition_dict = super(PropertyExistenceConstraint,
+ self).exportToFilesystemDefinitionDict()
+
+ for constraint_property in self.getConstraintPropertyList():
+ filesystem_definition_dict[constraint_property] = None
+
+ return filesystem_definition_dict
Modified: erp5/trunk/products/ERP5Type/Core/PropertyTypeValidityConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/PropertyTypeValidityConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Core/PropertyTypeValidityConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/PropertyTypeValidityConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -44,6 +44,8 @@ class PropertyTypeValidityConstraint(Con
meta_type = 'ERP5 Property Type Validity Constraint'
portal_type = 'Property Type Validity Constraint'
+ __compatibility_class_name__ = 'PropertyTypeValidity'
+
property_sheets = ConstraintMixin.property_sheets + \
(PropertySheet.PropertyTypeValidityConstraint,)
@@ -133,3 +135,8 @@ class PropertyTypeValidityConstraint(Con
obj.setProperty(property_id, oldvalue)
return error_list
+
+ _message_id_tuple = ('message_unknown_type',
+ 'message_incorrect_type',
+ 'message_incorrect_type_fix_failed',
+ 'message_incorrect_type_fixed')
Modified: erp5/trunk/products/ERP5Type/Core/TALESConstraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/TALESConstraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Core/TALESConstraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/TALESConstraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -61,6 +61,8 @@ class TALESConstraint(ConstraintMixin):
meta_type = 'ERP5 TALES Constraint'
portal_type = 'TALES Constraint'
+ __compatibility_class_name__ = 'TALESConstraint'
+
property_sheets = ConstraintMixin.property_sheets + \
(PropertySheet.TALESConstraint,)
@@ -86,3 +88,18 @@ class TALESConstraint(ConstraintMixin):
mapping=dict(error=str(e)))]
return []
+
+ _message_id_tuple = ('message_expression_false',
+ 'message_expression_error')
+
+ @staticmethod
+ def _convertFromFilesystemDefinition(expression):
+ yield dict(expression=expression)
+
+ def exportToFilesystemDefinitionDict(self):
+ filesystem_definition_dict = super(TALESConstraint,
+ self).exportToFilesystemDefinitionDict()
+
+ filesystem_definition_dict['expression'] = self.getExpression()
+
+ return filesystem_definition_dict
Modified: erp5/trunk/products/ERP5Type/Tool/PropertySheetTool.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Tool/PropertySheetTool.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Tool/PropertySheetTool.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Tool/PropertySheetTool.py [utf8] Wed Feb 2 13:52:44 2011
@@ -78,6 +78,10 @@ class PropertySheetTool(BaseTool):
return 'Standard Property'
+ _merged_portal_type_dict = {
+ 'CategoryAcquiredExistence': 'Category Existence Constraint',
+ 'CategoryAcquiredMembershipArity': 'Category Membership Arity Constraint'}
+
security.declareProtected(Permissions.ModifyPortalContent,
'createPropertySheetFromFilesystemClass')
def createPropertySheetFromFilesystemClass(self, klass):
@@ -85,7 +89,9 @@ class PropertySheetTool(BaseTool):
Create a new Property Sheet in portal_property_sheets from a given
filesystem-based Property Sheet definition.
"""
- new_property_sheet = self.newContent(id=klass.__name__,
+ new_property_sheet_name = klass.__name__
+
+ new_property_sheet = self.newContent(id=new_property_sheet_name,
portal_type='Property Sheet')
types_tool = self.getPortalObject().portal_types
@@ -112,6 +118,41 @@ class PropertySheetTool(BaseTool):
portal_type_class.importFromFilesystemDefinition(new_property_sheet,
category)
+ # Get filesystem Constraint names to be able to map them properly
+ # to ZODB Constraint Portal Types as some filesystem constraint
+ # names are 'NAMEConstraint' or 'NAME'
+ from Products.ERP5Type import Constraint as FilesystemConstraint
+ filesystem_constraint_class_name_list = [
+ class_name for class_name in FilesystemConstraint.__dict__ \
+ if class_name[0] != '_' ]
+
+ # Mapping between the filesystem 'type' field and Portal Types ID
+ portal_type_dict = {}
+ for search_result in types_tool.searchFolder(id='% Constraint'):
+ portal_type_id = search_result.getId()
+ constraint_class_name = portal_type_id.replace(' ', '')
+
+ if constraint_class_name not in filesystem_constraint_class_name_list:
+ constraint_class_name = constraint_class_name.replace('Constraint', '')
+
+ if constraint_class_name not in filesystem_constraint_class_name_list:
+ raise ValueError, "PropertySheet %s: Constraint %s: No Portal " \
+ "Type defined for type '%s'" % (new_property_sheet_name,
+ constraint['id'],
+ constraint['type'])
+
+ portal_type_dict[constraint_class_name] = portal_type_id
+
+ portal_type_dict.update(self._merged_portal_type_dict)
+
+ for constraint in getattr(klass, '_constraints', ()):
+ portal_type = portal_type_dict[constraint['type']]
+ portal_type_class = types_tool.getPortalTypeClass(portal_type)
+
+ # Create the new constraint
+ portal_type_class.importFromFilesystemDefinition(new_property_sheet,
+ constraint)
+
return new_property_sheet
security.declareProtected(Permissions.ManagePortal,
Modified: erp5/trunk/products/ERP5Type/mixin/constraint.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/mixin/constraint.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/mixin/constraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/mixin/constraint.py [utf8] Wed Feb 2 13:52:44 2011
@@ -52,6 +52,15 @@ class ConstraintMixin(Predicate):
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
+ # IDs of error messages defined in each Constraint, only used when
+ # importing or exporting from/to filesystem Constraint
+ _message_id_tuple = ()
+
+ # Store the filesystem name of the ZODB Constraint as there are
+ # several different naming for filesystem constraints (*only* useful
+ # for exportToFilesystemDefinitionDict)
+ __compatibility_class_name__ = None
+
__allow_access_to_unprotected_subobjects__ = 1
implements( IConstraint, )
@@ -104,6 +113,15 @@ class ConstraintMixin(Predicate):
wrapping removed) in order to maintain compatibility and be able
to use setDefaultProperties
+ NOTE: A filesystem constraint is defined by a dict, then depending
+ on the 'type' of the constraint, the appropriate class in
+ ERP5Type.Constraint is instanciated with the dict. This is no
+ longer needed for ZODB Constraints because they are already
+ Documents.
+
+ @see exportToFilesystemDefinitionDict() to export a ZODB
+ Constraint as a dict.
+
XXX: remove as soon as the code is stable
"""
return self.asContext()
@@ -118,3 +136,106 @@ class ConstraintMixin(Predicate):
return None
return Expression(expression_string)(createExpressionContext(obj))
+
+ @staticmethod
+ def _preConvertBaseFromFilesystemDefinition(filesystem_definition_dict):
+ """
+ Call before actually converting the attributes common to all
+ constraints
+ """
+ return dict()
+
+ @staticmethod
+ def _convertFromFilesystemDefinition(*args, **kw):
+ """
+ Convert a filesystem property dict to a ZODB Property dict which
+ will be given to newContent().
+
+ Only attributes specific to this constraint will be given as
+ parameters, e.g. not the ones common to all constraints such as
+ 'id', 'description', 'type' and 'condition' and error messages
+ defined in '_message_id_tuple' class attribute.
+
+ @see importFromFilesystemDefinition
+ """
+ yield dict()
+
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'importFromFilesystemDefinition')
+ @classmethod
+ def importFromFilesystemDefinition(cls, context, filesystem_definition_dict):
+ """
+ Import the filesystem definition to a ZODB Constraint, without its
+ condition as it is now a Predicate and has to be converted
+ manually.
+
+ Several ZODB Constraints may be created to handle Constraints such
+ as Attribute Equality which defines an attribute name and its
+ expected value, thus ending up creating one ZODB Constraint per
+ attribute/expected value
+ """
+ # Copy the dictionnary as it is going to be modified to remove all
+ # the common properties in order to have a dictionnary containing
+ # only properties specific to the current constraint
+ filesystem_definition_copy_dict = filesystem_definition_dict.copy()
+
+ # This dict only contains definition attributes common to *all*
+ # ZODB Constraints
+ base_constraint_definition_dict = \
+ cls._preConvertBaseFromFilesystemDefinition(filesystem_definition_copy_dict)
+
+ base_constraint_definition_dict['portal_type'] = cls.portal_type
+
+ base_constraint_definition_dict['reference'] = \
+ filesystem_definition_copy_dict.pop('id')
+
+ base_constraint_definition_dict['description'] = \
+ filesystem_definition_copy_dict.pop('description', '')
+
+ if 'condition' in filesystem_definition_copy_dict:
+ base_constraint_definition_dict['test_tales_expression'] = \
+ filesystem_definition_copy_dict.pop('condition')
+
+ # The type is meaningless for ZODB Constraints as it is the portal
+ # type itself
+ filesystem_definition_copy_dict.pop('type')
+
+ # Add specific error messages defined on the constraint document
+ for message_name in cls._message_id_tuple:
+ if message_name in filesystem_definition_copy_dict:
+ base_constraint_definition_dict[message_name] = \
+ filesystem_definition_copy_dict.pop(message_name)
+
+ # Call the method defined in the Constraint document which returns
+ # N dictionnaries containing only attributes specific to the
+ # Constraint
+ constraint_definition_generator = \
+ cls._convertFromFilesystemDefinition(**filesystem_definition_copy_dict)
+
+ # Create all the constraint in the current ZODB Property Sheet
+ for constraint_definition_dict in constraint_definition_generator:
+ constraint_definition_dict.update(base_constraint_definition_dict)
+ context.newContent(**constraint_definition_dict)
+
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'exportToFilesystemDefinitionDict')
+ def exportToFilesystemDefinitionDict(self):
+ """
+ Export the ZODB Constraint as a filesystem definition dict,
+ meaningful *only* for testing that a filesystem Constraint has
+ been properly converted
+
+ @see exportToFilesystemDefinition()
+ """
+ filesystem_definition_dict = dict(
+ id=self.getReference(),
+ description=self.getDescription(),
+ type=self.__compatibility_class_name__)
+
+ if self.hasTestTalesExpression():
+ filesystem_definition_dict['condition'] = self.getTestTalesExpression()
+
+ for message_id in self._message_id_tuple:
+ filesystem_definition_dict[message_id] = self._getMessage(message_id)
+
+ return filesystem_definition_dict
Modified: erp5/trunk/products/ERP5Type/tests/testDynamicClassGeneration.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/tests/testDynamicClassGeneration.py?rev=42929&r1=42928&r2=42929&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/tests/testDynamicClassGeneration.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/tests/testDynamicClassGeneration.py [utf8] Wed Feb 2 13:52:44 2011
@@ -1029,16 +1029,17 @@ class TestZodbImportFilesystemPropertySh
# Some fields may not defined a default value (such as 'id')
continue
- def _checkPropertyField(self,
- property_sheet_name,
- field_name,
- filesystem_value,
- zodb_value):
+ def _checkPropertyOrConstraintField(self,
+ property_sheet_name,
+ field_name,
+ filesystem_value,
+ zodb_value):
"""
- Check whether the given filesystem property value and the given
- ZODB property value are equal
+ Check whether the given filesystem property or constraint value
+ and the given ZODB property value are equal
"""
- if isinstance(zodb_value, (list, tuple)):
+ if isinstance(zodb_value, (list, tuple)) and \
+ isinstance(filesystem_value, (list, tuple)):
self.failIfDifferentSet(
zodb_value, filesystem_value,
msg="%s: %s: filesystem value: %s, ZODB value: %s" % \
@@ -1067,43 +1068,44 @@ class TestZodbImportFilesystemPropertySh
(property_sheet_name, field_name, filesystem_value,
zodb_value))
- def _checkPropertyDefinitionTuple(self,
- property_sheet_name,
- filesystem_property_tuple,
- zodb_property_tuple):
+ def _checkPropertyOrConstraintDefinitionTuple(self,
+ property_sheet_name,
+ filesystem_property_tuple,
+ zodb_property_tuple):
"""
- Check whether all properties have been properly converted from
- the filesystem to the ZODB Property Sheet
+ Check whether all properties or constraints have been properly
+ converted from the filesystem to the ZODB Property Sheet
"""
- # Check whether all the properties are present in the given ZODB
- # Property Sheet
+ # Check whether all the properties or constraints are present in
+ # the given ZODB Property Sheet
self.assertEqual(
len(filesystem_property_tuple), len(zodb_property_tuple),
msg="%s: too many properties: filesystem: %s, ZODB: %s" % \
(property_sheet_name, filesystem_property_tuple, zodb_property_tuple))
- # Map filesystem property IDs to their definition
+ # Map filesystem property or constraint IDs to their definition
filesystem_property_id_dict = {}
for property_dict in filesystem_property_tuple:
filesystem_property_id_dict[property_dict['id']] = property_dict
- # Check each property defined in ZODB against the filesystem dict
- # defined before
+ # Check each property or constraint defined in ZODB against the
+ # filesystem dict defined before
for zodb_property_dict in zodb_property_tuple:
# Meaningful to ensure that there is no missing field within a
- # property
+ # property or constraint
validated_field_counter = 0
filesystem_property_dict = \
filesystem_property_id_dict[zodb_property_dict['id']]
- # Check each property field
+ # Check each property or constraint field
for field_name, zodb_value in zodb_property_dict.iteritems():
if field_name in filesystem_property_dict:
- self._checkPropertyField(property_sheet_name,
- field_name,
- filesystem_property_dict[field_name],
- zodb_value)
+ self._checkPropertyOrConstraintField(
+ property_sheet_name, field_name,
+ filesystem_property_dict[field_name],
+ zodb_value)
+
# As we are using accessors when exporting the ZODB Property
# Sheet to its filesystem definition, there may be additional
# fields set to their default value
@@ -1162,8 +1164,6 @@ class TestZodbImportFilesystemPropertySh
Create Property Sheets on portal_property_sheets from their
definition on the filesystem and then test that they are
equivalent
-
- TODO: Constraints
"""
portal = self.getPortalObject().portal_property_sheets
@@ -1172,6 +1172,7 @@ class TestZodbImportFilesystemPropertySh
for name, klass in PropertySheet.__dict__.iteritems():
if name[0] == '_' or isinstance(klass, basestring):
continue
+
filesystem_property_sheet = klass
property_sheet_name = name
@@ -1183,20 +1184,26 @@ class TestZodbImportFilesystemPropertySh
zodb_property_sheet = portal.createPropertySheetFromFilesystemClass(
filesystem_property_sheet)
- zodb_property_tuple, zodb_category_tuple, zodb_constraint_tuple = \
+ zodb_property_tuple, zodb_category_tuple, zodb_constraint_class_tuple = \
portal.exportPropertySheetToFilesystemDefinitionTuple(
zodb_property_sheet)
- self._checkPropertyDefinitionTuple(property_sheet_name,
- getattr(filesystem_property_sheet,
- '_properties', []),
- zodb_property_tuple)
+ self._checkPropertyOrConstraintDefinitionTuple(
+ property_sheet_name,
+ getattr(filesystem_property_sheet, '_properties', []),
+ zodb_property_tuple)
self._checkCategoryTuple(property_sheet_name,
getattr(filesystem_property_sheet,
'_categories', []),
zodb_category_tuple)
+ self._checkPropertyOrConstraintDefinitionTuple(
+ property_sheet_name, getattr(filesystem_property_sheet,
+ '_constraints', []),
+ [ zodb_constraint_class.exportToFilesystemDefinitionDict() \
+ for zodb_constraint_class in zodb_constraint_class_tuple ])
+
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestPortalTypeClass))
More information about the Erp5-report
mailing list