[Erp5-report] r39348 arnaud.fontaine - in /erp5/trunk/products/ERP5Type: Core/ Dynamic/ Tool/

nobody at svn.erp5.org nobody at svn.erp5.org
Tue Oct 19 16:36:05 CEST 2010


Author: arnaud.fontaine
Date: Tue Oct 19 16:36:04 2010
New Revision: 39348

URL: http://svn.erp5.org?rev=39348&view=rev
Log:
Implement constraints for ZODB Property Sheets and generate accessor
holder classes for filesystem Property Sheets too.


Added:
    erp5/trunk/products/ERP5Type/Core/CategoryExistenceConstraint.py
      - copied, changed from r39011, erp5/trunk/products/ERP5Type/Constraint/CategoryExistence.py
    erp5/trunk/products/ERP5Type/Core/Constraint.py
      - copied, changed from r39011, erp5/trunk/products/ERP5Type/Constraint/Constraint.py
    erp5/trunk/products/ERP5Type/Core/PropertyExistenceConstraint.py
      - copied, changed from r39011, erp5/trunk/products/ERP5Type/Constraint/PropertyExistence.py
Modified:
    erp5/trunk/products/ERP5Type/Dynamic/portaltypeclass.py
    erp5/trunk/products/ERP5Type/Tool/PropertySheetTool.py

Copied: erp5/trunk/products/ERP5Type/Core/CategoryExistenceConstraint.py (from r39011, erp5/trunk/products/ERP5Type/Constraint/CategoryExistence.py)
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/CategoryExistenceConstraint.py?p2=erp5/trunk/products/ERP5Type/Core/CategoryExistenceConstraint.py&p1=erp5/trunk/products/ERP5Type/Constraint/CategoryExistence.py&r1=39011&r2=39348&rev=39348&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Constraint/CategoryExistence.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/CategoryExistenceConstraint.py [utf8] Tue Oct 19 16:36:04 2010
@@ -1,8 +1,9 @@
 ##############################################################################
 #
-# Copyright (c) 2002, 2005 Nexedi SARL and Contributors. All Rights Reserved.
-#                    Sebastien Robin <seb 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>
+#                         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
@@ -27,21 +28,23 @@
 #
 ##############################################################################
 
-from Constraint import Constraint
+from Products.ERP5Type.Core.Constraint import Constraint
+from AccessControl import ClassSecurityInfo
+from Products.ERP5Type import Permissions
 
-class CategoryExistence(Constraint):
-  """This constraint checks if an object respects the existence of 
-    a category, without acquisition.
-
-    Configuration example:
-    { 'id'            : 'category_existence',
-      'description'   : 'Category causality must be defined',
-      'type'          : 'CategoryExistence',
-      'portal_type'   : ('Person', 'Organisation'),
-      'causality'     : None,
-      'condition'     : 'python: object.getPortalType() == 'Foo',
-    },
+class CategoryExistenceConstraint(Constraint):
   """
+  This constraint checks whether a category has been defined on this
+  object (without acquisition). This is only relevant for ZODB
+  Property Sheets (filesystem Property Sheets rely on
+  Products.ERP5Type.Constraint.CategoryExistence instead).
+  """
+  meta_type = 'ERP5 Category Existence Constraint'
+  portal_type = 'Category Existence Constraint'
+
+  # Declarative security
+  security = ClassSecurityInfo()
+  security.declareObjectProtected(Permissions.AccessContentsInformation)
 
   _message_id_list = [ 'message_category_not_set',
                        'message_category_not_associated_with_portal_type' ]
@@ -55,17 +58,19 @@ class CategoryExistence(Constraint):
     return len(obj.getCategoryMembershipList(base_category,
                                              portal_type=portal_type))
 
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            'checkConsistency')
   def checkConsistency(self, obj, fixit=0):
-    """Check the object's consistency.
     """
-    if not self._checkConstraintCondition(obj):
-      return []
+    Check the object's consistency.
+    """
     error_list = []
-    portal_type = self.constraint_definition.get('portal_type', ())
+    if not self.test(obj):
+      return []
+
+    portal_type = self.getConstraintPortalTypeList() or ()
     # For each attribute name, we check if defined
-    for base_category in self.constraint_definition.keys():
-      if base_category in ('portal_type', ):
-        continue
+    for base_category in self.getConstraintBaseCategoryList() or ():
       mapping = dict(base_category=base_category)
       # Check existence of base category
       if base_category not in obj.getBaseCategoryList():
@@ -74,29 +79,21 @@ class CategoryExistence(Constraint):
         error_message = 'message_category_not_set'
       else:
         error_message = None
-      
+
       # Raise error
       if error_message:
-        error_list.append(self._generateError(obj,
-                  self._getMessage(error_message), mapping))
+        error_list.append(
+          self._generateError(obj,
+                              self._getMessage(error_message), mapping))
     return error_list
 
-
-class CategoryAcquiredExistence(CategoryExistence):
-  """This constraint checks if an object respects the existence of a category,
-  with acquisition.
-
-    Configuration example:
-    { 'id'            : 'category_existence',
-      'description'   : 'Category causality must be defined',
-      'type'          : 'CategoryExistence',
-      'portal_type'   : ('Person', 'Organisation'),
-      'causality'     : None,
-      'condition'     : 'python: object.getPortalType() == 'Foo',
-    },
+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):
     return len(obj.getAcquiredCategoryMembershipList(base_category,
                                              portal_type=portal_type))
-

Copied: erp5/trunk/products/ERP5Type/Core/Constraint.py (from r39011, erp5/trunk/products/ERP5Type/Constraint/Constraint.py)
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/Constraint.py?p2=erp5/trunk/products/ERP5Type/Core/Constraint.py&p1=erp5/trunk/products/ERP5Type/Constraint/Constraint.py&r1=39011&r2=39348&rev=39348&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Constraint/Constraint.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/Constraint.py [utf8] Tue Oct 19 16:36:04 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>
-#                    Courteaud Romain <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>
+#                         Courteaud Romain <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,91 +29,62 @@
 #
 ##############################################################################
 
-from Products.CMFCore.Expression import Expression
 from Products.ERP5Type.interfaces import IConstraint
 from Products.ERP5Type.ConsistencyMessage import ConsistencyMessage
 from zope.interface import implements
+from Products.ERP5Type.Core.Predicate import Predicate
+from AccessControl import ClassSecurityInfo
+from Products.ERP5Type import Permissions
+from Products.ERP5Type.Utils import UpperCase
+
+class Constraint(Predicate):
+  """
+  Constraint implementation (only relevant for ZODB Property sheets,
+  use Products.ERP5Type.Constraint instead for filesystem Property
+  Sheets) relying on Predicate
+  """
+  meta_type = 'ERP5 Constraint'
+  portal_type = 'Constraint'
+
+  # Declarative security
+  security = ClassSecurityInfo()
+  security.declareObjectProtected(Permissions.AccessContentsInformation)
 
-class Constraint:
+  __allow_access_to_unprotected_subobjects__ = 1
+  implements( IConstraint, )
+
+  _message_id_list = []
+
+  def _getMessage(self, message_id):
     """
-      Default Constraint implementation
+    Get the message corresponding to this message_id.
     """
-    __allow_access_to_unprotected_subobjects__ = 1
-    implements( IConstraint, )
-
-    _message_id_list = []
+    return getattr(self, 'get' + UpperCase(message_id))()
 
-    def __init__(self, id=None, description=None, type=None,
-                 condition=None, **constraint_definition):
-      """Initialize a constraint.
-      """
-      self.id = id
-      self.description = description
-      self.type = type
-      self.constraint_definition = dict()
-      self.message_id_dict = dict()
-      self.edit(id, description, type, condition, **constraint_definition)
-
-    def edit(self, id=None, description=None, type=None, condition=None,
-        **constraint_definition):
-      """Edit the constraint instance.
-      """
-      if id is not None:
-        self.id = id
-      if description is not None:
-        self.description = description
-      if type is not None:
-        self.type = type
-      self.condition = condition
-      for key, value in constraint_definition.items():
-        if key in self._message_id_list:
-          self.message_id_dict[key] = value
-        else:
-          self.constraint_definition[key] = value
-
-    def _getMessage(self, message_id):
-      """Get the message corresponding to this message_id.
-      """
-      if message_id in self.message_id_dict:
-        return self.message_id_dict[message_id]
-      return getattr(self, message_id)
-      
-    def _generateError(self, obj, error_message, mapping={}):
-      """Generic method used to generate error in checkConsistency.
-      """
-      if error_message is not None:
-        msg = ConsistencyMessage(self, 
-                                 object_relative_url=obj.getRelativeUrl(),
-                                 message=error_message, 
-                                 mapping=mapping)
-        return msg
-
-    def _checkConstraintCondition(self, obj):
-      """
-        method that will check if the TALES condition is true.
-        It should be called by checkConsistency, which should ignore
-        constraints if TALES is False
-      """
-      from Products.ERP5Type.Utils import createExpressionContext
-      condition = getattr(self, 'condition', None)
-      if condition not in (None, ''):
-        expression = Expression(condition)
-        econtext = createExpressionContext(obj)
-        if not expression(econtext):
-          return 0 # a condition was defined and is False
-      return 1 # no condition or a True condition was defined
-
-    def checkConsistency(self, obj, fixit=0, **kw):
-      """
-        Default method is to return no error.
-      """
-      errors = []
-      return errors
-
-    def fixConsistency(self, obj, **kw):
-      """
-        Default method is to call checkConsistency with
-        fixit set to 1
-      """
-      return self.checkConsistency(obj, fixit=1, **kw)
+  def _generateError(self, obj, error_message, mapping={}):
+    """
+    Generic method used to generate error in checkConsistency.
+    """
+    if error_message is not None:
+      msg = ConsistencyMessage(self,
+                               object_relative_url=obj.getRelativeUrl(),
+                               message=error_message,
+                               mapping=mapping)
+      return msg
+
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            'checkConsistency')
+  def checkConsistency(self, obj, fixit=0, **kw):
+    """
+    Default method is to return no error.
+    """
+    errors = []
+    return errors
 
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            'fixConsistency')
+  def fixConsistency(self, obj, **kw):
+    """
+    Default method is to call checkConsistency with fixit set to 1
+    """
+    return self.checkConsistency(obj, fixit=1, **kw)

Copied: erp5/trunk/products/ERP5Type/Core/PropertyExistenceConstraint.py (from r39011, erp5/trunk/products/ERP5Type/Constraint/PropertyExistence.py)
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Core/PropertyExistenceConstraint.py?p2=erp5/trunk/products/ERP5Type/Core/PropertyExistenceConstraint.py&p1=erp5/trunk/products/ERP5Type/Constraint/PropertyExistence.py&r1=39011&r2=39348&rev=39348&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Constraint/PropertyExistence.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Core/PropertyExistenceConstraint.py [utf8] Tue Oct 19 16:36:04 2010
@@ -1,8 +1,9 @@
 ##############################################################################
 #
-# Copyright (c) 2002, 2005 Nexedi SARL and Contributors. All Rights Reserved.
-#                    Sebastien Robin <seb 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>
+#                         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
@@ -27,23 +28,31 @@
 #
 ##############################################################################
 
-from Constraint import Constraint
+from Products.ERP5Type.Core.Constraint import Constraint
+from AccessControl import ClassSecurityInfo
+from Products.ERP5Type import Permissions
 
-class PropertyExistence(Constraint):
+class PropertyExistenceConstraint(Constraint):
   """
-    This method checks if an object respects the existence of a property.
-
-    For example we can check if every invoice line has a price defined
-    on it.
-    Configuration example:
-    { 'id'            : 'property_existence',
-      'description'   : 'Property price must be defined',
-      'type'          : 'PropertyExistence',
-      'price'         : None,
-      'condition'     : 'python: object.getPortalType() == 'Foo',
-    },
+  This constraint checks whether a property has been defined on this
+  object. This is only relevant for ZODB Property Sheets (filesystem
+  Property Sheets rely on Products.ERP5Type.Constraint.PropertyExistence
+  instead).
+
+  For example, if we would like to check whether an invoice line has a
+  'price' property defined on it, we would create a 'Property
+  Existence Constraint' within that property sheet and add 'price' to
+  the 'Properties' field, then set the 'Predicate' if necessary (known
+  as 'condition' for filesystem Property Sheets).
   """
+  meta_type = 'ERP5 Property Existence Constraint'
+  portal_type = 'Property Existence Constraint'
+
+  # Declarative security
+  security = ClassSecurityInfo()
+  security.declareObjectProtected(Permissions.AccessContentsInformation)
 
+  # Define by default error messages
   _message_id_list = ['message_no_such_property',
                       'message_property_not_set']
   message_no_such_property =  "Property existence error for property "\
@@ -51,14 +60,18 @@ class PropertyExistence(Constraint):
   message_property_not_set = "Property existence error for property "\
             "${property_id}, this property is not defined"
 
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            'checkConsistency')
   def checkConsistency(self, obj, fixit=0):
-    """Check the object's consistency.
     """
-    if not self._checkConstraintCondition(obj):
-      return []
+    Check the object's consistency.
+    """
     error_list = []
+    if not self.test(obj):
+      return []
+
     # For each attribute name, we check if defined
-    for property_id in self.constraint_definition.keys():
+    for property_id in self.getConstraintPropertyList() or ():
       # Check existence of property
       mapping = dict(property_id=property_id)
       if not obj.hasProperty(property_id):

Modified: erp5/trunk/products/ERP5Type/Dynamic/portaltypeclass.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Dynamic/portaltypeclass.py?rev=39348&r1=39347&r2=39348&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Dynamic/portaltypeclass.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Dynamic/portaltypeclass.py [utf8] Tue Oct 19 16:36:04 2010
@@ -38,8 +38,9 @@ import lazyclass
 from Products.ERP5Type.Globals import InitializeClass
 from Products.ERP5Type.Utils import setDefaultClassProperties
 from Products.ERP5Type import document_class_registry, mixin_class_registry
+from Products.ERP5Type import PropertySheet as FilesystemPropertySheet
 from ExtensionClass import Base as ExtensionBase
-from zLOG import LOG, ERROR, BLATHER
+from zLOG import LOG, ERROR, INFO
 
 def _import_class(classpath):
   try:
@@ -57,22 +58,49 @@ def _import_class(classpath):
     raise ImportError('Could not import document class %s' % classpath)
 
 def _create_accessor_holder_class(property_sheet_tool,
+                                  property_sheet_module,
                                   property_sheet_name):
   """
   If the given Property Sheet exists in portal_property_sheets, then
   generate its accessor holder
   """
-  try:
-    return property_sheet_tool.createPropertySheetAccessorHolder(
-      getattr(property_sheet_tool,
-              property_sheet_name))
-
-  except AttributeError:
-    # Not too critical
-    LOG("ERP5Type.Dynamic", ERROR,
-        "Ignoring missing Property Sheet " + property_sheet_name)
 
-    return None
+def _fill_accessor_holder_list(accessor_holder_list,
+                               create_accessor_holder_func,
+                               property_sheet_name_set,
+                               accessor_holder_module,
+                               property_sheet_module):
+  """
+  Fill the accessor holder list with the given Property Sheets (which
+  could be coming either from the filesystem or ZODB)
+  """
+  for property_sheet_name in property_sheet_name_set:
+    try:
+      # Get the already generated accessor holder
+      accessor_holder_list.append(getattr(accessor_holder_module,
+                                          property_sheet_name))
+
+    except AttributeError:
+      # Generate the accessor holder as it has not been done yet
+      try:
+        accessor_holder_class = \
+          create_accessor_holder_func(getattr(property_sheet_module,
+                                              property_sheet_name))
+
+      except AttributeError:
+        # Not too critical
+        LOG("ERP5Type.Dynamic", ERROR,
+            "Ignoring missing Property Sheet " + property_sheet_name)
+
+      else:
+        setattr(accessor_holder_module, property_sheet_name,
+                accessor_holder_class)
+
+        accessor_holder_list.append(accessor_holder_class)
+
+        LOG("ERP5Type.Dynamic", INFO,
+            "Created accessor holder for %s in %s" % (property_sheet_name,
+                                                      accessor_holder_module))
 
 def portal_type_factory(portal_type_name):
   """
@@ -134,33 +162,27 @@ def portal_type_factory(portal_type_name
           "Could not load interfaces or Mixins for portal type %s" \
               % portal_type)
 
-    # Initialize Property Sheets accessor holders
-    import erp5.accessor_holder
-
-    # Get the ZODB Property Sheets for this Portal Type
-    property_sheet_name_set = set(
-      portal_type.getNewStyleTypePropertySheetList() or [])
-
-    for property_sheet_name in property_sheet_name_set:
-      try:
-        # Get the already generated accessor holder
-        accessor_holder_list.append(getattr(erp5.accessor_holder,
-                                            property_sheet_name))
-
-      except AttributeError:
-        # Generate the accessor holder as it has not been done yet
-        accessor_holder_class = \
-            _create_accessor_holder_class(site.portal_property_sheets,
-                                          property_sheet_name)
-
-        if accessor_holder_class is not None:
-          setattr(erp5.accessor_holder, property_sheet_name,
-                  accessor_holder_class)
-
-          accessor_holder_list.append(accessor_holder_class)
+    import erp5
 
-          LOG("ERP5Type.Dynamic", BLATHER,
-              "Created accessor holder for %s" % property_sheet_name)
+    # Initialize filesystem Property Sheets accessor holders
+    _fill_accessor_holder_list(
+      accessor_holder_list,
+      site.portal_property_sheets.createFilesystemPropertySheetAccessorHolder,
+      set(portal_type.getTypePropertySheetList() or ()),
+      erp5.filesystem_accessor_holder,
+      FilesystemPropertySheet)
+
+    # Initialize ZODB Property Sheets accessor holders
+    _fill_accessor_holder_list(
+      accessor_holder_list,
+      site.portal_property_sheets.createZodbPropertySheetAccessorHolder,
+      set(portal_type.getTypeZodbPropertySheetList() or ()),
+      erp5.zodb_accessor_holder,
+      site.portal_property_sheets)
+
+    LOG("ERP5Type.Dynamic", INFO,
+        "%s: accessor_holder_list: %s" % (portal_type_name,
+                                          accessor_holder_list))
 
   if type_class is not None:
     type_class = document_class_registry.get(type_class)
@@ -176,7 +198,7 @@ def portal_type_factory(portal_type_name
 
   baseclasses = [type_class] + accessor_holder_list + mixin_class_list
 
-  LOG("ERP5Type.Dynamic", BLATHER,
+  LOG("ERP5Type.Dynamic", INFO,
       "Portal type %s loaded with bases %s" \
           % (portal_type_name, repr(baseclasses)))
 
@@ -193,8 +215,13 @@ def initializeDynamicModules():
       holds document classes that have no physical import path,
       for example classes created through ClassTool that are in
       $INSTANCE_HOME/Document
-    erp5.accessor_holder
-      holds accessors of ZODB Property Sheet
+    erp5.zodb_accessor_holder
+      holds accessors of ZODB Property Sheets
+    erp5.filesystem_accessor_holder
+      holds accessors of filesystem Property Sheets
+
+  XXX: there should be only one accessor_holder once the code is
+       stable and all the Property Sheets have been migrated
   """
   def portal_type_loader(portal_type_name):
     """
@@ -206,8 +233,11 @@ def initializeDynamicModules():
   sys.modules["erp5"] = erp5
   erp5.document = ModuleType("erp5.document")
   sys.modules["erp5.document"] = erp5.document
-  erp5.accessor_holder = ModuleType("erp5.accessor_holder")
-  sys.modules["erp5.accessor_holder"] = erp5.accessor_holder
+
+  erp5.zodb_accessor_holder = ModuleType("erp5.zodb_accessor_holder")
+  sys.modules["erp5.zodb_accessor_holder"] = erp5.zodb_accessor_holder
+  erp5.filesystem_accessor_holder = ModuleType("erp5.filesystem_accessor_holder")
+  sys.modules["erp5.filesystem_accessor_holder"] = erp5.filesystem_accessor_holder
 
   portal_type_container = dynamicmodule.dynamicmodule('erp5.portal_type',
                                                       portal_type_loader)
@@ -249,6 +279,18 @@ def initializeDynamicModules():
   erp5.temp_portal_type = dynamicmodule.dynamicmodule('erp5.temp_portal_type',
                                                    temp_portal_type_loader)
 
+def _clear_accessor_holder_module(module):
+  """
+  Clear the given accessor holder module (either for filesystem or
+  ZODB)
+
+  XXX: Merge into synchronizeDynamicModules as soon as we get rid of
+       these two accessor holder modules
+  """
+  for property_sheet_id in module.__dict__.keys():
+    if not property_sheet_id.startswith('__'):
+      delattr(module, property_sheet_id)
+
 last_sync = 0
 def synchronizeDynamicModules(context, force=False):
   """
@@ -262,7 +304,7 @@ def synchronizeDynamicModules(context, f
     and send out an invalidation to other nodes
   """
   return # XXX disabled for now
-  LOG("ERP5Type.Dynamic", BLATHER, "Resetting dynamic classes")
+  LOG("ERP5Type.Dynamic", INFO, "Resetting dynamic classes")
 
   portal = context.getPortalObject()
 
@@ -291,6 +333,7 @@ def synchronizeDynamicModules(context, f
       type(ExtensionBase).__init__(klass, klass)
 
   # Clear accessor holders of ZODB Property Sheets
-  for accessor_name in erp5.accessor_holder.__dict__.keys():
-    if not accessor_name.startswith('__'):
-      delattr(erp5.accessor_holder, accessor_name)
+  _clear_accessor_holder_module(erp5.zodb_accessor_holder)
+
+  # Clear accessor holders of filesystem Property Sheets
+  _clear_accessor_holder_module(erp5.filesystem_accessor_holder)

Modified: erp5/trunk/products/ERP5Type/Tool/PropertySheetTool.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Tool/PropertySheetTool.py?rev=39348&r1=39347&r2=39348&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Tool/PropertySheetTool.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Tool/PropertySheetTool.py [utf8] Tue Oct 19 16:36:04 2010
@@ -38,12 +38,6 @@ from Products.ERP5Type.Utils import setD
 
 from zLOG import LOG, ERROR, BLATHER
 
-class AccessorHolder(object):
-  """
-  Base class of an accessor holder class for Property Sheets
-  """
-  pass
-
 class PropertySheetTool(BaseTool):
   """
   Provides a configurable registry of property sheets
@@ -87,8 +81,6 @@ class PropertySheetTool(BaseTool):
     """
     Create a new Property Sheet in portal_property_sheets from a given
     filesystem-based Property Sheet definition.
-
-    XXX: Implement constraints
     """
     new_property_sheet = self.newContent(id=klass.__name__,
                                          portal_type='Property Sheet')
@@ -151,7 +143,8 @@ class PropertySheetTool(BaseTool):
     Export a given ZODB Property Sheet to its filesystem definition as
     tuple (properties, categories, constraints)
 
-    XXX: Implement constraints
+    XXX: Move this code and the accessor generation code (from Utils)
+         within their respective documents
     """
     properties = []
     constraints = []
@@ -170,26 +163,21 @@ class PropertySheetTool(BaseTool):
       elif portal_type == "Dynamic Category Property":
         categories.append(property.exportToFilesystemDefinition())
 
-    return (properties, categories, constraints, )
-
-  security.declarePrivate('createPropertySheetAccessorHolder')
-  def createPropertySheetAccessorHolder(self, property_sheet):
+      elif portal_type.endswith('Constraint'):
+        from Acquisition import aq_base
+        constraints.append(aq_base(property.asContext()))
+
+    return (properties, categories, constraints)
+
+  def _createCommonPropertySheetAccessorHolder(self,
+                                               property_holder,
+                                               property_sheet_id,
+                                               accessor_holder_module_name):
+    """
+    Create a new accessor holder class from the given Property Holder
+    within the given accessor holder module (when the migration will
+    be finished, there should only be one accessor holder module)
     """
-    Create a new accessor holder from the given Property Sheet (the
-    accessors are created through a Property Holder)
-
-    XXX: Workflows?
-    """
-    property_holder = PropertyHolder()
-
-    definition_tuple = \
-        self.exportPropertySheetToFilesystemDefinitionTuple(property_sheet)
-
-    # Prepare the Property Holder
-    property_holder._properties, \
-      property_holder._categories, \
-      property_holder._constraints = definition_tuple
-
     setDefaultClassProperties(property_holder)
 
     try:
@@ -197,16 +185,26 @@ class PropertySheetTool(BaseTool):
     except:
       import traceback
       LOG("Tool.PropertySheetTool", ERROR,
-          "Could not generate accessor holder class for %s: %s" % \
-          (property_sheet.getTitle(), traceback.format_exc()))
+          "Could not generate accessor holder class for %s (module=%s): %s" %\
+          (property_sheet_id,
+           accessor_holder_module_name,
+           traceback.format_exc()))
 
       return None
 
     # Create the new accessor holder class and set its module properly
-    accessor_holder_class = type(property_sheet.getId(),
-                                 (AccessorHolder,), {})
-
-    accessor_holder_class.__module__ = 'erp5.accessor_holder'
+    accessor_holder_class = type(property_sheet_id, (object,), dict(
+      __module__ = accessor_holder_module_name,
+      constraints = property_holder.constraints,
+      # The following attributes have been defined only because they
+      # are being used in ERP5Type.Utils when getting all the
+      # property_sheets of the property_holder (then, they are added
+      # to the local properties, categories and constraints lists)
+      _properties = property_holder._properties,
+      # Necessary for getBaseCategoryList
+      _categories = property_holder._categories,
+      _constraints = property_holder._constraints
+      ))
 
     # Set all the accessors (defined by a tuple) from the Property
     # Holder to the new accessor holder class (code coming from
@@ -227,3 +225,46 @@ class PropertySheetTool(BaseTool):
       setattr(accessor_holder_class, id, accessor)
 
     return accessor_holder_class
+
+  security.declarePrivate('createFilesystemPropertySheetAccessorHolder')
+  def createFilesystemPropertySheetAccessorHolder(self, property_sheet):
+    """
+    Create a new accessor holder from the given filesystem Property
+    Sheet (the accessors are created through a Property Holder)
+
+    XXX: Workflows?
+    XXX: Remove as soon as the migration is finished
+    """
+    property_holder = PropertyHolder()
+
+    property_holder._properties = getattr(property_sheet, '_properties', [])
+    property_holder._categories = getattr(property_sheet, '_categories', [])
+    property_holder._constraints = getattr(property_sheet, '_constraints', [])
+
+    return self._createCommonPropertySheetAccessorHolder(
+      property_holder,
+      property_sheet.__name__,
+      'erp5.filesystem_accessor_holder')
+
+  security.declarePrivate('createZodbPropertySheetAccessorHolder')
+  def createZodbPropertySheetAccessorHolder(self, property_sheet):
+    """
+    Create a new accessor holder from the given ZODB Property Sheet
+    (the accessors are created through a Property Holder)
+
+    XXX: Workflows?
+    """
+    definition_tuple = \
+      self.exportPropertySheetToFilesystemDefinitionTuple(property_sheet)
+
+    property_holder = PropertyHolder()
+
+    # Prepare the Property Holder
+    property_holder._properties, \
+      property_holder._categories, \
+      property_holder._constraints = definition_tuple
+
+    return self._createCommonPropertySheetAccessorHolder(
+      property_holder,
+      property_sheet.getId(),
+      'erp5.zodb_accessor_holder')




More information about the Erp5-report mailing list