[Erp5-report] r39754 nicolas.dumazet - /erp5/trunk/products/ERP5Type/dynamic/

nobody at svn.erp5.org nobody at svn.erp5.org
Tue Nov 2 08:08:59 CET 2010


Author: nicolas.dumazet
Date: Tue Nov  2 08:08:58 2010
New Revision: 39754

URL: http://svn.erp5.org?rev=39754&view=rev
Log:
move ghostify/unghostify-cation and ghost creation to portal type metaclass

Makes the code more efficient, and much more readable.

Modified:
    erp5/trunk/products/ERP5Type/dynamic/lazy_class.py
    erp5/trunk/products/ERP5Type/dynamic/portal_type_class.py

Modified: erp5/trunk/products/ERP5Type/dynamic/lazy_class.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/dynamic/lazy_class.py?rev=39754&r1=39753&r2=39754&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/dynamic/lazy_class.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/dynamic/lazy_class.py [utf8] Tue Nov  2 08:08:58 2010
@@ -7,12 +7,50 @@ from ExtensionClass import ExtensionClas
 from ZODB.broken import Broken, PersistentBroken
 from zLOG import LOG, ERROR, BLATHER
 
+from portal_type_class import generatePortalTypeClass
+
 # PersistentBroken can't be reused directly
 # because its « layout differs from 'GhostPortalType' »
 ERP5BaseBroken = type('ERP5BaseBroken', (Broken, ERP5Base), dict(x
   for x in PersistentBroken.__dict__.iteritems()
   if x[0] not in ('__dict__', '__module__', '__weakref__')))
 
+class GhostPortalType(ERP5Base): #SimpleItem
+    """
+    Ghost state for a portal type that is not loaded.
+
+    One instance of this class exists per portal type class on the system.
+    When an object of this portal type is loaded (a new object is created,
+    or an attribute of an existing object is accessed) this class will
+    change the bases of the portal type class so that it points to the
+    correct Document+Mixin+interfaces+AccessorHolder classes.
+    """
+    def __init__(self, *args, **kw):
+        self.__class__.loadClass()
+        getattr(self, '__init__')(*args, **kw)
+
+    def __getattribute__(self, attr):
+        """
+        This is only called once to load the class.
+        Because __bases__ is changed, the behavior of this object
+        will change after the first call.
+        """
+        # Class must be loaded if '__of__' is requested because otherwise,
+        # next call to __getattribute__ would lose any acquisition wrapper.
+        if attr in ('__class__',
+                    '__getnewargs__',
+                    '__getstate__',
+                    '__dict__',
+                    '__module__',
+                    '__name__',
+                    '__repr__',
+                    '__str__') or attr[:3] in ('_p_', '_v_'):
+            return super(GhostPortalType, self).__getattribute__(attr)
+        #LOG("ERP5Type.Dynamic", BLATHER,
+        #    "loading attribute %s.%s..." % (name, attr))
+        self.__class__.loadClass()
+        return getattr(self, attr)
+
 class PortalTypeMetaClass(ExtensionClass):
   """
   Meta class that will be used by portal type classes
@@ -54,71 +92,44 @@ class PortalTypeMetaClass(ExtensionClass
       pmc_init_of(subcls)
       InitializeClass(subcls)
 
-def generateLazyPortalTypeClass(portal_type_name,
-                                portal_type_class_loader):
-    def load(self, attr):
-        # self might be a subclass of a portal type class
-        # we need to find the right parent class to change
-        for klass in self.__class__.__mro__:
-          # XXX hardcoded, this doesnt look too good
-          if klass.__module__ == "erp5.portal_type":
-            break
-        else:
-          raise AttributeError("Could not find a portal type class in class hierarchy")
-
-        portal_type = klass.__name__
-        try:
-          baseclasses, attributes = portal_type_class_loader(portal_type)
-        except AttributeError:
-          LOG("ERP5Type.Dynamic", ERROR,
-              "Could not access Portal Type Object for type %r"
-              % portal_type, error=sys.exc_info())
-          baseclasses = (ERP5BaseBroken, )
-          attributes = {}
-
-        # save the old bases to be able to restore a ghost state later
-        klass.__ghostbase__ = klass.__bases__
-        klass.__bases__ = baseclasses
-
-        for key, value in attributes.iteritems():
-          setattr(klass, key, value)
-
-        klass.resetAcquisitionAndSecurity()
-
-        return getattr(self, attr)
-
-    class GhostPortalType(ERP5Base): #SimpleItem
-        """
-        Ghost state for a portal type that is not loaded.
+  def restoreGhostState(cls):
+    ghostbase = getattr(cls, '__ghostbase__', None)
+    if ghostbase is not None:
+      for attr in cls.__dict__.keys():
+        if attr not in ('__module__', '__doc__',):
+          delattr(cls, attr)
+      cls.__bases__ = ghostbase
+      cls.resetAcquisitionAndSecurity()
+
+  def loadClass(cls):
+    # cls might be a subclass of a portal type class
+    # we need to find the right class to change
+    for klass in cls.__mro__:
+      # XXX hardcoded, this doesnt look too good
+      if klass.__module__ == "erp5.portal_type":
+        break
+    else:
+      raise AttributeError("Could not find a portal type class in"
+                           " class hierarchy")
+
+    portal_type = klass.__name__
+    try:
+      baseclasses, attributes = generatePortalTypeClass(portal_type)
+    except AttributeError:
+      LOG("ERP5Type.Dynamic", ERROR,
+          "Could not access Portal Type Object for type %r"
+          % portal_type, error=sys.exc_info())
+      baseclasses = (ERP5BaseBroken, )
+      attributes = {}
+
+    # save the old bases to be able to restore a ghost state later
+    klass.__ghostbase__ = klass.__bases__
+    klass.__bases__ = baseclasses
 
-        One instance of this class exists per portal type class on the system.
-        When an object of this portal type is loaded (a new object is created,
-        or an attribute of an existing object is accessed) this class will
-        change the bases of the portal type class so that it points to the
-        correct Document+Mixin+interfaces+AccessorHolder classes.
-        """
-        def __init__(self, *args, **kw):
-            load(self, '__init__')(*args, **kw)
+    for key, value in attributes.iteritems():
+      setattr(klass, key, value)
 
-        def __getattribute__(self, attr):
-            """
-            This is only called once to load the class.
-            Because __bases__ is changed, the behavior of this object
-            will change after the first call.
-            """
-            # Class must be loaded if '__of__' is requested because otherwise,
-            # next call to __getattribute__ would lose any acquisition wrapper.
-            if attr in ('__class__',
-                        '__getnewargs__',
-                        '__getstate__',
-                        '__dict__',
-                        '__module__',
-                        '__name__',
-                        '__repr__',
-                        '__str__') or attr[:3] in ('_p_', '_v_'):
-                return super(GhostPortalType, self).__getattribute__(attr)
-            #LOG("ERP5Type.Dynamic", BLATHER,
-            #    "loading attribute %s.%s..." % (name, attr))
-            return load(self, attr)
+    klass.resetAcquisitionAndSecurity()
 
-    return PortalTypeMetaClass(portal_type_name, (GhostPortalType,), dict())
+def generateLazyPortalTypeClass(portal_type_name):
+    return PortalTypeMetaClass(portal_type_name, (GhostPortalType,), {})

Modified: erp5/trunk/products/ERP5Type/dynamic/portal_type_class.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/dynamic/portal_type_class.py?rev=39754&r1=39753&r2=39754&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/dynamic/portal_type_class.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/dynamic/portal_type_class.py [utf8] Tue Nov  2 08:08:58 2010
@@ -33,7 +33,6 @@ import inspect
 from types import ModuleType
 
 from dynamic_module import registerDynamicModule
-from lazy_class import generateLazyPortalTypeClass
 
 from Products.ERP5Type.Base import _aq_reset
 from Products.ERP5Type.Globals import InitializeClass
@@ -182,6 +181,7 @@ def generatePortalTypeClass(portal_type_
 
   return tuple(baseclasses), dict(portal_type=portal_type_name)
 
+from lazy_class import generateLazyPortalTypeClass
 def initializeDynamicModules():
   """
   Create erp5 module and its submodules
@@ -201,13 +201,6 @@ def initializeDynamicModules():
   XXX: there should be only one accessor_holder once the code is
        stable and all the Property Sheets have been migrated
   """
-  def loadPortalTypeClass(portal_type_name):
-    """
-    Returns a lazily-loaded "portal-type as a class"
-    """
-    return generateLazyPortalTypeClass(portal_type_name,
-                                       generatePortalTypeClass)
-
   erp5 = ModuleType("erp5")
   sys.modules["erp5"] = erp5
   erp5.document = ModuleType("erp5.document")
@@ -219,7 +212,7 @@ def initializeDynamicModules():
   sys.modules["erp5.filesystem_accessor_holder"] = erp5.filesystem_accessor_holder
 
   portal_type_container = registerDynamicModule('erp5.portal_type',
-                                                loadPortalTypeClass)
+                                                generateLazyPortalTypeClass)
 
   erp5.portal_type = portal_type_container
 
@@ -302,13 +295,7 @@ def synchronizeDynamicModules(context, f
 
   for class_name, klass in inspect.getmembers(erp5.portal_type,
                                               inspect.isclass):
-    ghostbase = getattr(klass, '__ghostbase__', None)
-    if ghostbase is not None:
-      for attr in klass.__dict__.keys():
-        if attr != '__module__':
-          delattr(klass, attr)
-      klass.__bases__ = ghostbase
-      klass.resetAcquisitionAndSecurity()
+    klass.restoreGhostState()
 
   # Clear accessor holders of ZODB Property Sheets
   _clearAccessorHolderModule(erp5.zodb_accessor_holder)




More information about the Erp5-report mailing list