From 5a7887b9d5c90873f95da71d0294910825226984 Mon Sep 17 00:00:00 2001
From: Arnaud Fontaine <arnaud.fontaine@nexedi.com>
Date: Thu, 1 Mar 2012 15:14:12 +0900
Subject: [PATCH] Move resetting of package to component_package as it has
 always should been there.

---
 product/ERP5/ERP5Site.py                      |  2 +-
 product/ERP5Type/Tool/ComponentTool.py        | 29 ++++------------
 product/ERP5Type/dynamic/component_package.py | 34 ++++++++++++++++---
 product/ERP5Type/mixin/component.py           |  4 +--
 4 files changed, 39 insertions(+), 30 deletions(-)

diff --git a/product/ERP5/ERP5Site.py b/product/ERP5/ERP5Site.py
index 690f05c6ac..fd2a1b615f 100644
--- a/product/ERP5/ERP5Site.py
+++ b/product/ERP5/ERP5Site.py
@@ -348,7 +348,7 @@ class ERP5Site(FolderMixIn, CMFSite, CacheCookieMixin):
       except AttributeError:
         reset_portal_type = False
 
-      synchronizeDynamicModules(self, force=reset_portal_type)
+      synchronizeDynamicModules(self, force=True)
     return self
 
   def manage_beforeDelete(self, item, container):
diff --git a/product/ERP5Type/Tool/ComponentTool.py b/product/ERP5Type/Tool/ComponentTool.py
index 6f1c0cd0e8..97ef9603bb 100644
--- a/product/ERP5Type/Tool/ComponentTool.py
+++ b/product/ERP5Type/Tool/ComponentTool.py
@@ -44,9 +44,9 @@ from zLOG import LOG, INFO, WARNING
 last_sync = -1
 class ComponentTool(BaseTool):
   """
-  This tool provides methods to load the the different types of
-  components of the ERP5 framework: Document classes, interfaces,
-  mixin classes, fields, accessors, etc.
+  This tool provides methods to load the the different types of components of
+  the ERP5 framework: Document classes, interfaces, mixin classes, fields,
+  accessors, etc.
   """
   id = "portal_components"
   meta_type = "ERP5 Component Tool"
@@ -55,22 +55,6 @@ class ComponentTool(BaseTool):
   security = ClassSecurityInfo()
   security.declareObjectProtected(Permissions.AccessContentsInformation)
 
-  def _resetModule(self, module):
-    for name, klass in module.__dict__.items():
-      if not (name[0] != '_' and isinstance(klass, ModuleType)):
-        continue
-
-      full_module_name = "%s.%s" % (module.__name__, name)
-
-      LOG("ERP5Type.Tool.ComponentTool", INFO, "Resetting " + full_module_name)
-
-      if name.endswith('_version'):
-        self._resetModule(getattr(module, name))
-
-      # The module must be deleted first
-      del sys.modules[full_module_name]
-      delattr(module, name)
-
   security.declareProtected(Permissions.ResetDynamicClasses, 'reset')
   def reset(self, force=True, reset_portal_type=True):
     """
@@ -103,16 +87,15 @@ class ComponentTool(BaseTool):
 
     with Base.aq_method_lock:
       for content_type in allowed_content_type_list:
-        module_name = content_type.split(' ')[0].lower()
+        package_name = content_type.split(' ')[0].lower()
 
         try:
-          module = getattr(erp5.component, module_name)
+          package = getattr(erp5.component, package_name)
         # XXX-arnau: not everything is defined yet...
         except AttributeError:
           pass
         else:
-          module._resetRegistry()
-          self._resetModule(module)
+          package.reset()
 
     if reset_portal_type:
       type_tool.resetDynamicDocumentsOnceAtTransactionBoundary()
diff --git a/product/ERP5Type/dynamic/component_package.py b/product/ERP5Type/dynamic/component_package.py
index ddee651e29..b8fadafd87 100644
--- a/product/ERP5Type/dynamic/component_package.py
+++ b/product/ERP5Type/dynamic/component_package.py
@@ -35,7 +35,7 @@ import threading
 
 from Products.ERP5.ERP5Site import getSite
 from types import ModuleType
-from zLOG import LOG, INFO
+from zLOG import LOG, INFO, BLATHER
 
 class ComponentVersionPackage(ModuleType):
   """
@@ -123,9 +123,6 @@ class ComponentDynamicPackage(ModuleType):
 
     return self.__registry_dict
 
-  def _resetRegistry(self):
-    self.__registry_dict.clear()
-
   def find_module(self, fullname, path=None):
     # Ignore imports with a path which are filesystem-only and any
     # absolute imports which does not start with this package prefix,
@@ -264,3 +261,32 @@ class ComponentDynamicPackage(ModuleType):
         setattr(self, component_name, new_module)
 
       return new_module
+
+  def reset(self, sub_package=None):
+    """
+    Reset the content of the current package and its version package as well
+    recursively. This method must be called within a lock to avoid side
+    effects
+    """
+    if sub_package is None:
+      # Clear the Component registry
+      self.__registry_dict.clear()
+      package = self
+    else:
+      package = sub_package
+
+    for name, module in package.__dict__.items():
+      if name[0] == '_' or not isinstance(module, ModuleType):
+        continue
+
+      # Reset the content of the version package before resetting it
+      elif isinstance(module, ComponentVersionPackage):
+        self.reset(sub_package=module)
+
+      module_name = "%s.%s" % (package.__name__, name)
+      LOG("ERP5Type.Tool.ComponentTool", BLATHER, "Resetting " + module_name)
+
+      # The module must be deleted first from sys.modules to avoid imports in
+      # the meantime
+      del sys.modules[module_name]
+      delattr(package, name)
diff --git a/product/ERP5Type/mixin/component.py b/product/ERP5Type/mixin/component.py
index c7894a53d0..bd3afa2e39 100644
--- a/product/ERP5Type/mixin/component.py
+++ b/product/ERP5Type/mixin/component.py
@@ -150,7 +150,7 @@ class ComponentMixin(PropertyRecordableMixin, Base):
 
   _message_reference_not_set = "Reference must be set"
   _message_invalid_reference = "Reference cannot end with '_version' or "\
-      "start with '_' or be equal to find_module or load_module"
+      "start with '_' or be equal to find_module, load_module or reset"
 
   _message_version_not_set = "Version must be set"
   _message_invalid_version = "Version cannot start with '_'"
@@ -177,7 +177,7 @@ class ComponentMixin(PropertyRecordableMixin, Base):
 
     elif (reference.endswith('_version') or
           reference[0] == '_' or
-          reference in ('find_module', 'load_module')):
+          reference in ('find_module', 'load_module', 'reset')):
       error_list.append(
         ConsistencyMessage(self,
                            object_relative_url,
-- 
2.30.9