From 0555eb0b6cf07cad0522b61099234c0a75fe8842 Mon Sep 17 00:00:00 2001
From: Nicolas Dumazet <nicolas.dumazet@nexedi.com>
Date: Mon, 29 Nov 2010 06:06:14 +0000
Subject: [PATCH] rename __ghostbase__ to __isghost__ for clarity and comment
 extensively

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@40828 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 product/ERP5Type/dynamic/lazy_class.py | 40 +++++++++++++++++---------
 1 file changed, 27 insertions(+), 13 deletions(-)

diff --git a/product/ERP5Type/dynamic/lazy_class.py b/product/ERP5Type/dynamic/lazy_class.py
index 997730cc3d..67b1e185b0 100644
--- a/product/ERP5Type/dynamic/lazy_class.py
+++ b/product/ERP5Type/dynamic/lazy_class.py
@@ -78,6 +78,12 @@ class PortalTypeMetaClass(GhostBaseMetaClass):
 
   - Tracks subclasses of portal type classes
   - Takes care of ghosting/unghosting
+
+  Instances of this metaclass have __isghost__ class attributes.
+  - If True, this attribute marks classes awaiting a load from the
+    ZODB. An instance of GhostBaseMetaClass should be in the mro()
+    and will be removed after loading.
+  - If False, the class is fully-loaded and functional.
   """
 
   # register which classes subclass portal type classes
@@ -93,7 +99,7 @@ class PortalTypeMetaClass(GhostBaseMetaClass):
       if issubclass(type(parent), PortalTypeMetaClass):
         PortalTypeMetaClass.subclass_register.setdefault(parent, []).append(cls)
 
-    cls.__ghostbase__ = None
+    cls.__isghost__ = True
     super(GhostBaseMetaClass, cls).__init__(name, bases, dictionary)
 
   @classmethod
@@ -132,17 +138,25 @@ class PortalTypeMetaClass(GhostBaseMetaClass):
       InitializeClass(subclass)
 
   def restoreGhostState(cls):
-    if cls.__ghostbase__ is not None:
+    """
+    Insert in the __bases__ hierarchy an instance of GhostBaseMetaClass
+    that will force reloading the class.
+    - mro before reset:
+       erp5.portal_type.XXX, *TAIL
+    - after reset:
+       erp5.portal_type.XXX, GhostBaseMetaClass instance, *TAIL
+    """
+    if not cls.__isghost__:
       for attr in cls.__dict__.keys():
         if attr not in ('__module__',
                         '__doc__',
-                        '__ghostbase__',
+                        '__isghost__',
                         'portal_type'):
           delattr(cls, attr)
       # generate a ghostbase that derives from all previous bases
       ghostbase = GhostBaseMetaClass('GhostBase', cls.__bases__, {})
       cls.__bases__ = (ghostbase,)
-      cls.__ghostbase__ = None
+      cls.__isghost__ = True
       cls.resetAcquisitionAndSecurity()
 
   def __getattr__(cls, name):
@@ -155,15 +169,21 @@ class PortalTypeMetaClass(GhostBaseMetaClass):
     if cls.__module__ != 'erp5.portal_type':
       return getattr(cls.__bases__[0], name)
 
-    if not name.startswith('__') and cls.__ghostbase__ is None:
+    if not name.startswith('__') and cls.__isghost__:
       cls.loadClass()
       return getattr(cls, name)
 
     raise AttributeError
 
   def loadClass(cls):
+    """
+    - mro before load:
+      erp5.portal_type.XXX, GhostBaseMetaClass instance, *TAIL
+    - mro after:
+      erp5.portal_type.XXX, *new_bases_fetched_from_ZODB
+    """
     # Do not load the class again if it has already been loaded
-    if cls.__ghostbase__ is not None:
+    if not cls.__isghost__:
       return
 
     # cls might be a subclass of a portal type class
@@ -191,13 +211,7 @@ class PortalTypeMetaClass(GhostBaseMetaClass):
       else:
         base_list, interface_list, attribute_dict = class_definition
 
-
-      # save the old bases to be able to restore a ghost state later
-      if klass.__ghostbase__ is None:
-        # but only do it if we're in the innermost call, otherwise
-        # klass.__bases__ might just be the Document without accessor
-        # holders, and we would override the real ghost class
-        klass.__ghostbase__ = klass.__bases__
+      klass.__isghost__ = False
       klass.__bases__ = base_list
 
       for key, value in attribute_dict.iteritems():
-- 
2.30.9