Commit a462aa1c authored by Julien Muchembled's avatar Julien Muchembled

When uninstalling document item, restore document class from product if any

This fixes TestBusinessTemplate.test_168_DocumentUninstallIsEffective

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@39835 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 92495f23
......@@ -3380,6 +3380,21 @@ class DocumentTemplateItem(BaseTemplateItem):
{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(BaseTemplateItem):
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(BaseTemplateItem):
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(BaseTemplateItem):
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):
......
......@@ -6712,7 +6712,6 @@ class TestBusinessTemplate(ERP5TypeTestCase, LogInterceptor):
# 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(ERP5TypeTestCase, LogInterceptor):
'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):
......
......@@ -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()
......@@ -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_hook,
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_hook,
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, create=1, instance_home=None):
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=None):
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=None):
# 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/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment