[Erp5-report] r39835 jm - in /erp5/trunk/products: ERP5/Document/ ERP5/tests/ ERP5Type/

nobody at svn.erp5.org nobody at svn.erp5.org
Wed Nov 3 14:24:11 CET 2010


Author: jm
Date: Wed Nov  3 14:24:07 2010
New Revision: 39835

URL: http://svn.erp5.org?rev=39835&view=rev
Log:
When uninstalling document item, restore document class from product if any

This fixes TestBusinessTemplate.test_168_DocumentUninstallIsEffective

Modified:
    erp5/trunk/products/ERP5/Document/BusinessTemplate.py
    erp5/trunk/products/ERP5/tests/testBusinessTemplate.py
    erp5/trunk/products/ERP5Type/InitGenerator.py
    erp5/trunk/products/ERP5Type/Utils.py

Modified: erp5/trunk/products/ERP5/Document/BusinessTemplate.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/BusinessTemplate.py?rev=39835&r1=39834&r2=39835&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/BusinessTemplate.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/BusinessTemplate.py [utf8] Wed Nov  3 14:24:07 2010
@@ -3380,6 +3380,21 @@ class DocumentTemplateItem(BaseTemplateI
                 {path : ['Removed', self.__class__.__name__[:-12]]})
     return modified_object_list
 
+  def _resetDynamicModules(self):
+    # before any import, flush all ZODB caches to force a DB reload
+    # otherwise we could have objects trying to get commited while
+    # holding reference to a class that is no longer the same one as
+    # the class in its import location and pickle doesn't tolerate it.
+    # First we do a savepoint to dump dirty objects to temporary
+    # storage, so that all references to them can be freed.
+    transaction.savepoint(optimistic=True)
+    # Then we need to flush from all caches, not only the one from this
+    # connection
+    portal = self.getPortalObject()
+    portal._p_jar.db().cacheMinimize()
+    synchronizeDynamicModules(portal, force=True)
+    gc.collect()
+
   def install(self, context, trashbin, **kw):
     update_dict = kw.get('object_to_update')
     force = kw.get('force')
@@ -3393,7 +3408,6 @@ class DocumentTemplateItem(BaseTemplateI
               continue
           text = self._objects[id]
           path, name = posixpath.split(id)
-          # This raises an exception if the file already exists.
           try:
             self.local_file_writer_name(name, text, create=0)
           except IOError, error:
@@ -3405,19 +3419,7 @@ class DocumentTemplateItem(BaseTemplateI
           if self.local_file_importer_name is None:
             continue
           if need_reset:
-            # before any import, flush all ZODB caches to force a DB reload
-            # otherwise we could have objects trying to get commited while
-            # holding reference to a class that is no longer the same one as
-            # the class in its import location and pickle doesn't tolerate it.
-            # First we do a savepoint to dump dirty objects to temporary
-            # storage, so that all references to them can be freed.
-            transaction.savepoint(optimistic=True)
-            # Then we need to flush from all caches, not only the one from this
-            # connection
-            portal = self.getPortalObject()
-            portal._p_jar.db().cacheMinimize()
-            synchronizeDynamicModules(portal, force=True)
-            gc.collect()
+            self._resetDynamicModules()
             need_reset = False
           self.local_file_importer_name(name)
     else:
@@ -3435,8 +3437,11 @@ class DocumentTemplateItem(BaseTemplateI
       object_keys = [object_path]
     else:
       object_keys = self._archive.keys()
-    for key in object_keys:
-      self.local_file_remover_name(key)
+    if object_keys:
+      if isinstance(self, DocumentTemplateItem):
+        self._resetDynamicModules()
+      for key in object_keys:
+        self.local_file_remover_name(key)
     BaseTemplateItem.uninstall(self, context, **kw)
 
   def export(self, context, bta, **kw):

Modified: erp5/trunk/products/ERP5/tests/testBusinessTemplate.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/tests/testBusinessTemplate.py?rev=39835&r1=39834&r2=39835&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/tests/testBusinessTemplate.py [utf8] (original)
+++ erp5/trunk/products/ERP5/tests/testBusinessTemplate.py [utf8] Wed Nov  3 14:24:07 2010
@@ -6712,7 +6712,6 @@ class TestBusinessTemplate(ERP5TypeTestC
     # check the previously existing instance now behaves as the overriden class
     self.assertTrue(getattr(portal.another_file, 'isClassOverriden', False))
 
-  @expectedFailure
   def test_168_DocumentUninstallIsEffective(self):
     portal = self.portal
     # Test_167 above needs to have been run
@@ -6720,11 +6719,8 @@ class TestBusinessTemplate(ERP5TypeTestC
                    'isClassOverriden',
                    False):
       self.test_167_InstanceAndRelatedClassDefinedInSameBT()
-    self.uninstallBusinessTemplate('test_data')
-    transaction.commit()
-    self.tic()
+    self.uninstallBusinessTemplate('test_bt')
     # check both File instances no longer behave like being overriden
-    self.assertFalse(getattr(portal.some_file, 'isClassOverriden', False))
     self.assertFalse(getattr(portal.another_file, 'isClassOverriden', False))
 
   def test_getBusinessTemplateUrl(self):

Modified: erp5/trunk/products/ERP5Type/InitGenerator.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/InitGenerator.py?rev=39835&r1=39834&r2=39835&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/InitGenerator.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/InitGenerator.py [utf8] Wed Nov  3 14:24:07 2010
@@ -30,46 +30,39 @@
 
 
 import os, re, string, sys
+from Products.ERP5Type import document_class_registry
 from Products.ERP5Type.Globals import package_home, InitializeClass
 
 from zLOG import LOG
 
-global product_document_registry
-product_document_registry = []
-global product_interactor_registry
+product_document_registry = {}
 product_interactor_registry = []
-global interactor_class_id_registry 
 interactor_class_id_registry = {}
 
 def getProductDocumentPathList():
-  result = product_document_registry
-  result.sort()
-  return result
+  return sorted((k, os.path.dirname(sys.modules[v.rsplit('.', 1)[0]].__file__))
+                for k,v in product_document_registry.iteritems())
 
-def InitializeDocument(document_class, document_path=None):
-  global product_document_registry
+def InitializeDocument(class_id, class_path):
   # Register class in ERP5Type.Document
-  product_document_registry.append(((document_class, document_path)))
+  product_document_registry[class_id] = class_path
 
 def getProductInteractorPathList():
-  result = product_interactor_registry
-  result.sort()
-  return result
+  return sorted(product_interactor_registry)
 
 def InitializeInteractor(interactor_class, interactor_path=None):
-  global product_interactor_registry
   # Register class in ERP5Type.Interactor
   product_interactor_registry.append(((interactor_class, interactor_path)))
 
 def initializeProductDocumentRegistry():
   from Utils import importLocalDocument
-  for (class_id, document_path) in product_document_registry:
-    importLocalDocument(class_id, path=document_path)
+  for (class_id, class_path) in product_document_registry.iteritems():
+    importLocalDocument(class_id, class_path=class_path)
     #from Testing import ZopeTestCase
     #ZopeTestCase._print('Added product document to ERP5Type repository: %s (%s) \n' % (class_id, document_path))
     #LOG('Added product document to ERP5Type repository: %s (%s)' % (class_id, document_path), 0, '')
     #print 'Added product document to ERP5Type repository: %s (%s)' % (class_id, document_path)
-    
+
 def initializeProductInteractorRegistry():
   from Utils import importLocalInteractor
   for (class_id, interactor_path) in product_interactor_registry:
@@ -77,10 +70,8 @@ def initializeProductInteractorRegistry(
       importLocalInteractor(class_id, path=interactor_path)
 
 def registerInteractorClass(class_id, klass):
-  global interactor_class_id_registry
   interactor_class_id_registry[class_id] = klass
 
 def installInteractorClassRegistry():
-  global interactor_class_id_registry
-  for class_id, klass in interactor_class_id_registry.items():
+  for klass in interactor_class_id_registry.itervalues():
     klass().install()

Modified: erp5/trunk/products/ERP5Type/Utils.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Utils.py?rev=39835&r1=39834&r2=39835&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Utils.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Utils.py [utf8] Wed Nov  3 14:24:07 2010
@@ -87,7 +87,7 @@ def simple_decorator(decorator):
   return new_decorator
 
 from Products.ERP5Type import Permissions
-
+from Products.ERP5Type import document_class_registry
 from Products.ERP5Type.Accessor.Constant import PropertyGetter as \
     PropertyConstantGetter
 from Products.ERP5Type.Accessor.Constant import Getter as ConstantGetter
@@ -470,7 +470,6 @@ def updateGlobals(this_module, global_ho
     for module_id in module_id_list:
       import_method(module_id, path=path, is_erp5_type=is_erp5_type)
 
-  from Products.ERP5Type import document_class_registry
   module_name = this_module.__name__
   # Return core document_class list (for ERP5Type only)
   # this was introduced to permit overriding ERP5Type Document classes
@@ -478,14 +477,12 @@ def updateGlobals(this_module, global_ho
   path, core_module_id_list = getModuleIdList(product_path, 'Core')
   for document in core_module_id_list:
     module_path = '.'.join((module_name, 'Core', document, document))
-    document_class_registry[document] = module_path
-    InitializeDocument(document, document_path=path)
+    InitializeDocument(document, module_path)
   # Return document_class list
   path, module_id_list = getModuleIdList(product_path, 'Document')
   for document in module_id_list:
     module_path = '.'.join((module_name, 'Document', document, document))
-    document_class_registry[document] = module_path
-    InitializeDocument(document, document_path=path)
+    InitializeDocument(document, module_path)
 
   # Return interactor_class list
   path, interactor_id_list = getModuleIdList(product_path, 'Interactor')
@@ -803,6 +800,14 @@ def removeLocalDocument(class_id):
     f = os.path.join(path, "%s.%s" % (class_id, ext))
     if os.path.exists(f):
       os.remove(f)
+  if document_class_registry.pop(class_id, None):
+    # restore original class (from product) if any
+    from Products.ERP5Type.InitGenerator import product_document_registry
+    product_path = product_document_registry.get(class_id)
+    if product_path:
+      importLocalDocument(class_id, class_path=product_path)
+    else:
+      pass # XXX Do we need to clean up ?
 
 def readLocalDocument(class_id):
   instance_home = getConfiguration().instancehome
@@ -826,22 +831,14 @@ def writeLocalDocument(class_id, text, c
   if create:
     if os.path.exists(path):
       raise IOError, 'the file %s is already present' % path
+  # check there is no syntax error (that's the most we can do at this time)
+  compile(text, path, 'exec')
   f = open(path, 'w')
   try:
     f.write(text)
   finally:
     f.close()
 
-  module_path = "erp5.document"
-  classpath = "%s.%s" % (module_path, class_id)
-  module = imp.load_source(classpath, path)
-  import erp5.document
-  setattr(erp5.document, class_id, getattr(module, class_id))
-
-  # and register correctly the new document
-  from Products.ERP5Type import document_class_registry
-  document_class_registry[class_id] = classpath
-
 def setDefaultClassProperties(property_holder):
   """Initialize default properties for ERP5Type Documents.
   """
@@ -917,17 +914,16 @@ class PersistentMigrationMixin(object):
 
 from Globals import Persistent, PersistentMapping
 
-def importLocalDocument(class_id, path=None):
+def importLocalDocument(class_id, path=None, class_path=None):
   """Imports a document class and registers it in ERP5Type Document
   repository ( Products.ERP5Type.Document )
   """
   import Products.ERP5Type.Document
   import Permissions
 
-  from Products.ERP5Type import document_class_registry
-  if path and 'products' in path.lower(): # XXX
-    classpath = document_class_registry[class_id]
-    module_path = classpath.rsplit('.', 1)[0]
+  if class_path:
+    assert path is None
+    module_path = class_path.rsplit('.', 1)[0]
     module = __import__(module_path, {}, {}, (module_path,))
   else:
     # local document in INSTANCE_HOME/Document/
@@ -937,11 +933,11 @@ def importLocalDocument(class_id, path=N
       path = os.path.join(instance_home, "Document")
     path = os.path.join(path, "%s.py" % class_id)
     module_path = "erp5.document"
-    classpath = "%s.%s" % (module_path, class_id)
-    module = imp.load_source(classpath, path)
+    class_path = "%s.%s" % (module_path, class_id)
+    module = imp.load_source(class_path, path)
     import erp5.document
     setattr(erp5.document, class_id, getattr(module, class_id))
-    document_class_registry[class_id] = classpath
+  document_class_registry[class_id] = class_path
 
   ### Migration
   module_name = "Products.ERP5Type.Document.%s" % class_id
@@ -986,7 +982,6 @@ def importLocalDocument(class_id, path=N
   # XXX really?
   return klass, tuple()
 
-
 def initializeLocalRegistry(directory_name, import_local_method):
   """
   Initialize local directory.
@@ -1049,7 +1044,6 @@ def initializeProduct( context,
   """
   module_name = this_module.__name__
 
-  from Products.ERP5Type import document_class_registry
   # Content classes are exceptions and should be registered here.
   # other products were all already registered in updateGlobals()
   # because getModuleIdList works fine for Document/ and Core/




More information about the Erp5-report mailing list