[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