[Erp5-report] r38348 jm - in /erp5/trunk/products: ERP5/Document/ ERP5Type/tests/
nobody at svn.erp5.org
nobody at svn.erp5.org
Tue Sep 14 13:27:33 CEST 2010
Author: jm
Date: Tue Sep 14 13:27:31 2010
New Revision: 38348
URL: http://svn.erp5.org?rev=38348&view=rev
Log:
Speed up installation of Python Scripts and prepare clean up of XML
Before this patch, a Python Script was compiled several times during its
installation. Now, it is compiled only once.
'_code', 'func_code' and 'func_defaults' attributes are also not required
anymore in the XML representation of Python Scripts. This will allow to remove
this garbage for XML in the future.
For the moment, we have to provide forward compatibility with old revision of
ERP5 product, so this patch does not change exported XML.
Modified:
erp5/trunk/products/ERP5/Document/BusinessTemplate.py
erp5/trunk/products/ERP5Type/tests/ERP5TypeTestCase.py
Modified: erp5/trunk/products/ERP5/Document/BusinessTemplate.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/BusinessTemplate.py?rev=38348&r1=38347&r2=38348&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/BusinessTemplate.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/BusinessTemplate.py [utf8] Tue Sep 14 13:27:31 2010
@@ -577,7 +577,7 @@ class BaseTemplateItem(Implicit, Persist
def importFile(self, bta, **kw):
bta.importFiles(item=self)
- def removeProperties(self, obj):
+ def removeProperties(self, obj, export):
"""
Remove unneeded properties for export
"""
@@ -587,7 +587,8 @@ class BaseTemplateItem(Implicit, Persist
attr_list = [ '_dav_writelocks', '_filepath', '_owner', 'uid',
'workflow_history', '__ac_local_roles__' ]
- attr_list += {
+ if export:
+ attr_list += {
'ERP5 Python Script': ('_lazy_compilation', 'Python_magic'),
}.get(meta_type, ())
@@ -599,7 +600,13 @@ class BaseTemplateItem(Implicit, Persist
if not obj.getProperty('business_template_include_content', 1):
obj.deletePdfContent()
elif meta_type == 'ERP5 Python Script':
- obj._code = None
+ if export:
+ # XXX forward compatibility: set to None instead of deleting '_code'
+ # so that old BT code can import recent BT
+ obj._code = None
+ else:
+ # save result of automatic compilation
+ obj._p_changed = 1
elif interfaces.IIdGenerator.providedBy(obj):
for dict_name in ('last_max_id_dict', 'last_id_dict'):
if getattr(obj, dict_name, None) is not None:
@@ -717,7 +724,7 @@ class ObjectTemplateItem(BaseTemplateIte
relative_url = '/'.join([url,id])
obj = p.unrestrictedTraverse(relative_url)
obj = obj._getCopy(context)
- obj = self.removeProperties(obj)
+ obj = self.removeProperties(obj, 1)
id_list = obj.objectIds() # FIXME duplicated variable name
if hasattr(aq_base(obj), 'groups'): # XXX should check metatype instead
# we must keep groups because they are deleted along with subobjects
@@ -744,7 +751,7 @@ class ObjectTemplateItem(BaseTemplateIte
except AttributeError:
raise AttributeError, "Could not find object '%s' during business template processing." % relative_url
_recursiveRemoveUid(obj)
- obj = self.removeProperties(obj)
+ obj = self.removeProperties(obj, 1)
id_list = obj.objectIds()
if hasattr(aq_base(obj), 'groups'): # XXX should check metatype instead
# we must keep groups because they are deleted along with subobjects
@@ -836,7 +843,7 @@ class ObjectTemplateItem(BaseTemplateIte
# FIXME: Why not use the importXML function directly? Are there any BT5s
# with actual .zexp files on the wild?
obj = connection.importFile(file_obj, customImporters=customImporters)
- self.removeProperties(obj)
+ self.removeProperties(obj, 0)
self._objects[file_name[:-4]] = obj
def preinstall(self, context, installed_item, **kw):
@@ -847,7 +854,7 @@ class ObjectTemplateItem(BaseTemplateIte
for path in self._objects:
if installed_item._objects.has_key(path):
upgrade_list.append((path,
- self.removeProperties(installed_item._objects[path])))
+ self.removeProperties(installed_item._objects[path], 0)))
else: # new object
modified_object_list[path] = 'New', type_name
# update _p_jar property of objects cleaned by removeProperties
@@ -1038,10 +1045,6 @@ class ObjectTemplateItem(BaseTemplateIte
# install object
obj = self._objects[path]
- if getattr(obj, 'meta_type', None) in ('Script (Python)',
- 'ERP5 Python Script'):
- if getattr(obj, '_code') is None:
- obj._compile()
if getattr(aq_base(obj), 'groups', None) is not None:
# we must keep original order groups
# because they change when we add subobjects
@@ -1379,7 +1382,7 @@ class PathTemplateItem(ObjectTemplateIte
obj = obj.__of__(context)
_recursiveRemoveUid(obj)
id_list = obj.objectIds()
- obj = self.removeProperties(obj)
+ obj = self.removeProperties(obj, 1)
if hasattr(aq_base(obj), 'groups'):
# we must keep groups because it's ereased when we delete subobjects
groups = deepcopy(obj.groups)
@@ -1496,7 +1499,7 @@ class CategoryTemplateItem(ObjectTemplat
relative_url = '/'.join([url,id])
obj = p.unrestrictedTraverse(relative_url)
obj = obj._getCopy(context)
- obj = self.removeProperties(obj)
+ obj = self.removeProperties(obj, 1)
id_list = obj.objectIds()
if id_list:
self.build_sub_objects(context, id_list, relative_url)
@@ -1512,7 +1515,7 @@ class CategoryTemplateItem(ObjectTemplat
obj = p.unrestrictedTraverse(relative_url)
obj = obj._getCopy(context)
_recursiveRemoveUid(obj)
- obj = self.removeProperties(obj)
+ obj = self.removeProperties(obj, 1)
include_sub_categories = obj.__of__(context).getProperty('business_template_include_sub_categories', 0)
id_list = obj.objectIds()
if len(id_list) > 0 and include_sub_categories:
@@ -1828,10 +1831,6 @@ class WorkflowTemplateItem(ObjectTemplat
self._backupObject(action, trashbin, container_path, object_id, keep_subobjects=1)
container.manage_delObjects([object_id])
obj = self._objects[path]
- if getattr(obj, 'meta_type', None) in ('Script (Python)',
- 'ERP5 Python Script'):
- if getattr(obj, '_code') is None:
- obj._compile()
obj = obj._getCopy(container)
container._setObject(object_id, obj)
obj = container._getOb(object_id)
@@ -2634,7 +2633,7 @@ class CatalogMethodTemplateItem(ObjectTe
obj=obj.aq_parent
connection=obj._p_jar
obj = connection.importFile(file, customImporters=customImporters)
- self.removeProperties(obj)
+ self.removeProperties(obj, 0)
self._objects[file_name[:-4]] = obj
else:
LOG('Business Template', 0, 'Skipping file "%s"' % (file_name, ))
@@ -2727,7 +2726,7 @@ class ActionTemplateItem(ObjectTemplateI
continue
raise NotFound('Action %r not found' % id)
key = posixpath.join(url[-2], url[-1], value)
- self._objects[key] = self.removeProperties(action)
+ self._objects[key] = self.removeProperties(action, 1)
self._objects[key].wl_clearLocks()
def install(self, context, trashbin, **kw):
@@ -5060,8 +5059,8 @@ Business Template is a set of definition
f1 = StringIO() # for XML export of New Object
f2 = StringIO() # For XML export of Installed Object
# Remove unneeded properties
- new_object = new_item.removeProperties(new_object)
- installed_object = installed_item.removeProperties(installed_object)
+ new_object = new_item.removeProperties(new_object, 1)
+ installed_object = installed_item.removeProperties(installed_object, 1)
# XML Export in memory
OFS.XMLExportImport.exportXML(new_object._p_jar, new_object._p_oid, f1)
OFS.XMLExportImport.exportXML(installed_object._p_jar,
Modified: erp5/trunk/products/ERP5Type/tests/ERP5TypeTestCase.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/tests/ERP5TypeTestCase.py?rev=38348&r1=38347&r2=38348&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/tests/ERP5TypeTestCase.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/tests/ERP5TypeTestCase.py [utf8] Tue Sep 14 13:27:31 2010
@@ -1230,6 +1230,24 @@ class ZEOServerTestCase(ERP5TypeTestCase
self.zeo_server.close_server()
+class lazy_func_prop(object):
+ """Descriptor to delay the compilations of Python Scripts
+ until some of their attributes are accessed.
+ """
+ default_dict = {}
+ def __init__(self, name, default):
+ self.name = name
+ self.default_dict[name] = default
+ def __get__(self, instance, owner):
+ if self.name not in instance.__dict__:
+ instance.__dict__.update(self.default_dict)
+ instance._orig_compile()
+ return instance.__dict__[self.name]
+ def __set__(self, instance, value):
+ instance.__dict__[self.name] = value
+ def __delete__(self, instance):
+ del instance.__dict__[self.name]
+
@onsetup
def optimize():
'''Significantly reduces portal creation time.'''
@@ -1241,26 +1259,44 @@ def optimize():
# Delay the compilations of Python Scripts until they are really executed.
from Products.PythonScripts.PythonScript import PythonScript
- PythonScript_compile = PythonScript._compile
+ # In the future, Python Scripts will be exported without those 2 attributes:
+ PythonScript.func_code = lazy_func_prop('func_code', None)
+ PythonScript.func_defaults = lazy_func_prop('func_defaults', None)
+
+ PythonScript._orig_compile = PythonScript._compile
def _compile(self):
- self._lazy_compilation = 1
+ # mark the script as being not compiled
+ for name in lazy_func_prop.default_dict:
+ self.__dict__.pop(name, None)
PythonScript._compile = _compile
PythonScript_exec = PythonScript._exec
def _exec(self, *args):
- if getattr(self, '_lazy_compilation', 0):
- self._lazy_compilation = 0
- PythonScript_compile(self)
+ self.func_code # trigger compilation if needed
return PythonScript_exec(self, *args)
PythonScript._exec = _exec
from Acquisition import aq_parent
def _makeFunction(self, dummy=0): # CMFCore.FSPythonScript uses dummy arg.
self.ZCacheable_invalidate()
- PythonScript_compile(self)
+ self.__dict__.update(lazy_func_prop.default_dict)
+ self._orig_compile()
if not (aq_parent(self) is None or hasattr(self, '_filepath')):
# It needs a _filepath, and has an acquisition wrapper.
self._filepath = self.get_filepath()
PythonScript._makeFunction = _makeFunction
+ # XXX Previous implementation of this 'optimize' function requires that
+ # Python Scripts always contain up-to-date data for 'func_code' and
+ # 'func_defaults' properties, so make sure we always export them.
+ # This compatibility code is not required for normal ERP5 instances
+ # because scripts are compiled at BT installation.
+ from Products.ERP5Type.Document.BusinessTemplate import BaseTemplateItem
+ BaseTemplateItem_removeProperties = BaseTemplateItem.removeProperties
+ def removeProperties(self, obj, export):
+ if export and isinstance(obj, PythonScript):
+ obj.func_code # trigger compilation if needed
+ return BaseTemplateItem_removeProperties(self, obj, export)
+ BaseTemplateItem.removeProperties = removeProperties
+
# Do not reindex portal types sub objects by default
# We will probably disable reindexing for other types later
full_indexing_set = set(os.environ.get('enable_full_indexing', '').split(','))
More information about the Erp5-report
mailing list