[Erp5-report] r39751 nicolas.dumazet - /erp5/trunk/products/ERP5Type/dynamic/lazy_class.py

nobody at svn.erp5.org nobody at svn.erp5.org
Tue Nov 2 06:28:17 CET 2010


Author: nicolas.dumazet
Date: Tue Nov  2 06:28:10 2010
New Revision: 39751

URL: http://svn.erp5.org?rev=39751&view=rev
Log:
Nicer way to set re-initialize classes after changing their bases.

1) Do not use gc.get_referrers as this is highly inefficient.
(the returned list contains a lot of objects, some of them
are persistent objects, some of them are not classes, etc, etc...
But worse, "dead" objects with a zero reference count can be returned
by this function, and this function would "ressucitate" them.
gc.get_referrers for application code is usually a bad idea)

2) Use instead a Python metaclass to track who's been subclassing
a portal type class, and after a change on the portal type class,
we just call the efficient PortalTypeMetaClass.getSubclassList to
get descendants.

Modified:
    erp5/trunk/products/ERP5Type/dynamic/lazy_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=39751&r1=39750&r2=39751&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/dynamic/lazy_class.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/dynamic/lazy_class.py [utf8] Tue Nov  2 06:28:10 2010
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 
-import gc, sys
+import sys
 from Products.ERP5Type.Base import Base as ERP5Base
 from ExtensionClass import Base as ExtensionBase
 from ZODB.broken import Broken, PersistentBroken
@@ -13,12 +13,36 @@ ERP5BaseBroken = type('ERP5BaseBroken', 
   if x[0] not in ('__dict__', '__module__', '__weakref__')))
 
 ExtensionClass = type(ExtensionBase)
+
+class PortalTypeMetaClass(ExtensionClass):
+  """
+  Meta class that will be used by portal type classes
+  """
+  # register which classes subclass portal type classes
+  subclass_register = {} # XXX ideal defaultdict(list) wannabe
+  def __init__(cls, name, bases, dictionary):
+    """
+    This method is called when a portal type class is
+    created, or when a class inheriting a portal type
+    class is created
+    """
+    for parent in bases:
+      if issubclass(type(parent), PortalTypeMetaClass):
+        PortalTypeMetaClass.subclass_register.setdefault(parent, []).append(cls)
+
+    super(PortalTypeMetaClass, cls).__init__(name, bases, dictionary)
+
+  @classmethod
+  def getSubclassList(metacls, cls):
+    """
+    Returns classes deriving from cls
+    """
+    return metacls.subclass_register.get(cls, [])
+
 def InitializePortalTypeClass(klass):
-  # beware of the scary meta type
   ExtensionClass.__init__(klass, klass)
-  for klass in gc.get_referrers(klass):
-    if isinstance(klass, ExtensionClass):
-      InitializePortalTypeClass(klass)
+  for klass in PortalTypeMetaClass.getSubclassList(klass):
+    ExtensionClass.__init__(klass, klass)
 
 def generateLazyPortalTypeClass(portal_type_name,
                                 portal_type_class_loader):
@@ -87,4 +111,4 @@ def generateLazyPortalTypeClass(portal_t
             #    "loading attribute %s.%s..." % (name, attr))
             return load(self, attr)
 
-    return type(portal_type_name, (GhostPortalType,), dict())
+    return PortalTypeMetaClass(portal_type_name, (GhostPortalType,), dict())




More information about the Erp5-report mailing list