Commit f537d4e9 authored by Julien Muchembled's avatar Julien Muchembled

BT: fix severe regression when installing objects that were exported in 2 files

For example, Python Scripts were:
- dirty in the imported BT (causing all of them to be reinstalled on upgrade)
- compiled to return None
parent d34d719c
...@@ -888,6 +888,12 @@ class ObjectTemplateItem(BaseTemplateItem): ...@@ -888,6 +888,12 @@ class ObjectTemplateItem(BaseTemplateItem):
except BrokenModified: except BrokenModified:
obj.__Broken_state__[property_name] = data obj.__Broken_state__[property_name] = data
obj._p_changed = 1 obj._p_changed = 1
else:
# Revert any work done by __setstate__.
# XXX: This is enough for all objects we currently split in 2 files,
# but __setstate__ could behave badly with the missing attribute
# and newly added types may require more than this.
self.removeProperties(obj, 1, keep_workflow_history=True)
def _importFile(self, file_name, file_obj, catalog_method_template_item = 0): def _importFile(self, file_name, file_obj, catalog_method_template_item = 0):
obj_key, file_ext = os.path.splitext(file_name) obj_key, file_ext = os.path.splitext(file_name)
......
...@@ -26,7 +26,8 @@ ...@@ -26,7 +26,8 @@
# #
############################################################################## ##############################################################################
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.ERP5TypeTestCase import \
ERP5TypeTestCase, immediateCompilation
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
from runUnitTest import tests_home from runUnitTest import tests_home
import glob import glob
...@@ -223,13 +224,11 @@ class TestBusinessTemplateTwoFileExport(ERP5TypeTestCase): ...@@ -223,13 +224,11 @@ class TestBusinessTemplateTwoFileExport(ERP5TypeTestCase):
skin_folder = self.portal.portal_skins[skin_folder_id] skin_folder = self.portal.portal_skins[skin_folder_id]
python_script_id = 'dummy_test_script' python_script_id = 'dummy_test_script'
if python_script_id in skin_folder.objectIds(): skin_folder.manage_addProduct['PythonScripts'].manage_addPythonScript(
skin_folder.manage_delObjects([python_script_id]) id=python_script_id)
skin_folder.manage_addProduct['PythonScripts'].manage_addPythonScript(id=python_script_id) skin_folder[python_script_id].ZPythonScript_edit('', "return 1")
python_script = skin_folder[python_script_id]
python_script.ZPythonScript_edit('', "context.setTitle('foo')")
python_script_kw = {"_body": "context.setTitle('foo')\n",} python_script_kw = {"_body": "return 1\n",}
self.template.edit(template_skin_id_list=[skin_folder_id+'/'+python_script_id,]) self.template.edit(template_skin_id_list=[skin_folder_id+'/'+python_script_id,])
...@@ -237,20 +236,21 @@ class TestBusinessTemplateTwoFileExport(ERP5TypeTestCase): ...@@ -237,20 +236,21 @@ class TestBusinessTemplateTwoFileExport(ERP5TypeTestCase):
'SkinTemplateItem', 'portal_skins', skin_folder_id, python_script_id) 'SkinTemplateItem', 'portal_skins', skin_folder_id, python_script_id)
import_template = self._exportAndReImport( with immediateCompilation():
import_template = self._exportAndReImport(
python_script_path, python_script_path,
".py", ".py",
python_script_kw["_body"], python_script_kw["_body"],
['_body','_code']) ['_body','_code'])
self.portal.portal_skins[skin_folder_id].manage_delObjects([python_script_id]) skin_folder.manage_delObjects(python_script_id)
import_template.install() import_template.install()
python_script_page = self.portal.portal_skins[skin_folder_id][python_script_id] script = skin_folder[python_script_id]
python_script_content = python_script_page.read() self.assertTrue(script.read().endswith(python_script_kw['_body']))
self.assertTrue(python_script_content.endswith(python_script_kw['_body'])) self.assertEqual(1, script())
def _checkTwoFileImportExportForImageInImageModule(self, def _checkTwoFileImportExportForImageInImageModule(self,
image_document_kw, image_document_kw,
......
...@@ -19,6 +19,7 @@ import time ...@@ -19,6 +19,7 @@ import time
import traceback import traceback
import urllib import urllib
import ConfigParser import ConfigParser
from contextlib import contextmanager
from cStringIO import StringIO from cStringIO import StringIO
from cPickle import dumps from cPickle import dumps
from glob import glob from glob import glob
...@@ -57,6 +58,7 @@ from Testing import ZopeTestCase ...@@ -57,6 +58,7 @@ from Testing import ZopeTestCase
from Testing.ZopeTestCase import PortalTestCase, user_name from Testing.ZopeTestCase import PortalTestCase, user_name
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from Products.DCWorkflow.DCWorkflow import ValidationFailed from Products.DCWorkflow.DCWorkflow import ValidationFailed
from Products.PythonScripts.PythonScript import PythonScript
from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
from zLOG import LOG, DEBUG from zLOG import LOG, DEBUG
...@@ -1323,13 +1325,27 @@ class lazy_func_prop(object): ...@@ -1323,13 +1325,27 @@ class lazy_func_prop(object):
self.default_dict[name] = default self.default_dict[name] = default
def __get__(self, instance, owner): def __get__(self, instance, owner):
if self.name not in instance.__dict__: if self.name not in instance.__dict__:
instance.__dict__.update(self.default_dict) self.compile(instance)
instance._orig_compile()
return instance.__dict__[self.name] return instance.__dict__[self.name]
def __set__(self, instance, value): def __set__(self, instance, value):
instance.__dict__[self.name] = value instance.__dict__[self.name] = value
def __delete__(self, instance): def __delete__(self, instance):
del instance.__dict__[self.name] del instance.__dict__[self.name]
@classmethod
def compile(cls, instance, _compile=PythonScript._compile):
instance.__dict__.update(cls.default_dict)
_compile(instance)
immediate_compilation = 0
@contextmanager
def immediateCompilation():
global immediate_compilation
immediate_compilation += 1
try:
yield
finally:
immediate_compilation -= 1
@onsetup @onsetup
def optimize(): def optimize():
...@@ -1341,13 +1357,13 @@ def optimize(): ...@@ -1341,13 +1357,13 @@ def optimize():
Expression.__init__ = __init__ Expression.__init__ = __init__
# Delay the compilations of Python Scripts until they are really executed. # Delay the compilations of Python Scripts until they are really executed.
from Products.PythonScripts.PythonScript import PythonScript
# Python Scripts are exported without those 2 attributes: # Python Scripts are exported without those 2 attributes:
PythonScript.func_code = lazy_func_prop('func_code', None) PythonScript.func_code = lazy_func_prop('func_code', None)
PythonScript.func_defaults = lazy_func_prop('func_defaults', None) PythonScript.func_defaults = lazy_func_prop('func_defaults', None)
PythonScript._orig_compile = PythonScript._compile
def _compile(self): def _compile(self):
if immediate_compilation:
return lazy_func_prop.compile(self)
# mark the script as being not compiled # mark the script as being not compiled
for name in lazy_func_prop.default_dict: for name in lazy_func_prop.default_dict:
self.__dict__.pop(name, None) self.__dict__.pop(name, None)
...@@ -1360,8 +1376,7 @@ def optimize(): ...@@ -1360,8 +1376,7 @@ def optimize():
from Acquisition import aq_parent from Acquisition import aq_parent
def _makeFunction(self, dummy=0): # CMFCore.FSPythonScript uses dummy arg. def _makeFunction(self, dummy=0): # CMFCore.FSPythonScript uses dummy arg.
self.ZCacheable_invalidate() self.ZCacheable_invalidate()
self.__dict__.update(lazy_func_prop.default_dict) lazy_func_prop.compile(self)
self._orig_compile()
if not (aq_parent(self) is None or hasattr(self, '_filepath')): if not (aq_parent(self) is None or hasattr(self, '_filepath')):
# It needs a _filepath, and has an acquisition wrapper. # It needs a _filepath, and has an acquisition wrapper.
self._filepath = self.get_filepath() self._filepath = self.get_filepath()
......
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