[Erp5-report] r42902 nicolas.dumazet - in /erp5/trunk/products: CMFActivity/ ERP5/ ERP5/Doc...
nobody at svn.erp5.org
nobody at svn.erp5.org
Tue Feb 1 17:55:14 CET 2011
Author: nicolas.dumazet
Date: Tue Feb 1 17:55:13 2011
New Revision: 42902
URL: http://svn.erp5.org?rev=42902&view=rev
Log:
Last chunk of portal type classes / zodb property sheets.
After this, all ERP5 objects become instances of portal type classes
Preferences:
* all the trickery for preferences is gone and is handled by a specific
accessor holder holding all preference methods
Property holders
* our Base.aq_portal_type property holders are not used anymore:
the "property holder" becomes the portal type class itself and the
set of accessor_holder classes in the mro of the portal type class:
portal-type-specific methods are on the portal type class, while
portal-type-independant method are put on the accessor holder ancestors
* the portal type meta class now also inherits from "PropertyHolder" to
provide the same introspection interface and methods.
(In the future this class / interface will need to be refined)
Bootstrap/migration:
* bootstrapping/migration from older instances: provide with code able to
import XML from ERP5/bootstrap/ to load necessary tools from almost any
instance state
* migrate in BusinessTemplate installation code all non-portal type classes
objects to portal type classes
* Change the way Tools are installed when creating a site, so that we create
directly portal type classes objects instead of Documents
Accessors:
* add a generatePortalTypeAccessors method on the portal type class to generate
portal-type-specific accessors
* associate BaseAccessorHolder to all portal type classes to contain
all common category related accessors
* change the way workflow methods are generated to bind them directly on
the portal type class
* disable Base._aq_dynamic (while still keeping its code for debugging and
reference, this can be cleanup up later)
Modified:
erp5/trunk/products/CMFActivity/ActivityTool.py
erp5/trunk/products/ERP5/Document/BusinessTemplate.py
erp5/trunk/products/ERP5/ERP5Site.py
erp5/trunk/products/ERP5Form/Document/Preference.py
erp5/trunk/products/ERP5Form/PreferenceTool.py
erp5/trunk/products/ERP5Type/Base.py
erp5/trunk/products/ERP5Type/ERP5Type.py
erp5/trunk/products/ERP5Type/TranslationProviderBase.py
erp5/trunk/products/ERP5Type/Utils.py
erp5/trunk/products/ERP5Type/dynamic/lazy_class.py
erp5/trunk/products/ERP5Type/dynamic/portal_type_class.py
Modified: erp5/trunk/products/CMFActivity/ActivityTool.py
URL: http://svn.erp5.org/erp5/trunk/products/CMFActivity/ActivityTool.py?rev=42902&r1=42901&r2=42902&view=diff
==============================================================================
--- erp5/trunk/products/CMFActivity/ActivityTool.py [utf8] (original)
+++ erp5/trunk/products/CMFActivity/ActivityTool.py [utf8] Tue Feb 1 17:55:13 2011
@@ -502,6 +502,8 @@ class ActivityTool (Folder, UniqueObject
allowed_types = ( 'CMF Active Process', )
security = ClassSecurityInfo()
+ isIndexable = False
+
manage_options = tuple(
[ { 'label' : 'Overview', 'action' : 'manage_overview' }
, { 'label' : 'Activities', 'action' : 'manageActivities' }
Modified: erp5/trunk/products/ERP5/Document/BusinessTemplate.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/BusinessTemplate.py?rev=42902&r1=42901&r2=42902&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/BusinessTemplate.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/BusinessTemplate.py [utf8] Tue Feb 1 17:55:13 2011
@@ -816,11 +816,18 @@ class ObjectTemplateItem(BaseTemplateIte
if context.getTemplateFormatVersion() == 1:
upgrade_list = []
type_name = self.__class__.__name__.split('TemplateItem')[-2]
- for path in self._objects:
+ for path, obj in self._objects.iteritems():
if installed_item._objects.has_key(path):
upgrade_list.append((path, installed_item._objects[path]))
else: # new object
modified_object_list[path] = 'New', type_name
+
+ # if that's an old style class, use a portal type class instead
+ migrateme = getattr(obj, '_migrateToPortalTypeClass', None)
+ if migrateme is not None:
+ migrateme()
+ self._objects[path] = obj
+
# update _p_jar property of objects cleaned by removeProperties
transaction.savepoint(optimistic=True)
for path, old_object in upgrade_list:
@@ -1006,7 +1013,7 @@ class ObjectTemplateItem(BaseTemplateIte
workflow_history = None
old_obj = container._getOb(object_id, None)
object_existed = old_obj is not None
- if old_obj is not None:
+ if object_existed:
# Object already exists
recurse(saveHook, old_obj)
if getattr(aq_base(old_obj), 'groups', None) is not None:
@@ -1920,10 +1927,24 @@ class PortalTypeTemplateItem(ObjectTempl
PersistentMigrationMixin._no_migration -= 1
return object_key_list
- # XXX : this method is kept temporarily, but can be removed once all bt5 are
- # re-exported with separated workflow-chain information
def install(self, context, trashbin, **kw):
+ if context.getTemplateFormatVersion() == 1:
+ object_list = self._objects
+ else:
+ object_list = self._archive
+
+ for path, obj in object_list.iteritems():
+ # if that's an old style class, use a portal type class instead
+ # XXX PortalTypeTemplateItem-specific
+ migrateme = getattr(obj, '_migrateToPortalTypeClass', None)
+ if migrateme is not None:
+ migrateme()
+ object_list[path] = obj
+
ObjectTemplateItem.install(self, context, trashbin, **kw)
+
+ # XXX : following be removed once all bt5 are
+ # re-exported with separated workflow-chain information
update_dict = kw.get('object_to_update')
force = kw.get('force')
# We now need to setup the list of workflows corresponding to
@@ -1933,10 +1954,6 @@ class PortalTypeTemplateItem(ObjectTempl
# best solution, by default it is 'default_workflow', which is
# not very usefull
default_chain = ''
- if context.getTemplateFormatVersion() == 1:
- object_list = self._objects
- else:
- object_list = self._archive
for path in object_list.keys():
if update_dict.has_key(path) or force:
if not force:
@@ -3478,7 +3495,7 @@ class PropertySheetTemplateItem(Document
# If set to False, then the migration of Property Sheets will never
# be performed, required until the code of ZODB Property Sheets is
# stable and completely documented
- _perform_migration = False
+ _perform_migration = True
# Only meaningful for filesystem Property Sheets
local_file_reader_name = staticmethod(readLocalPropertySheet)
@@ -4336,6 +4353,7 @@ Business Template is a set of definition
, 'icon' : 'file_icon.gif'
, 'product' : 'ERP5Type'
, 'factory' : 'addBusinessTemplate'
+ , 'type_class' : 'BusinessTemplate'
, 'immediate_view' : 'BusinessTemplate_view'
, 'allow_discussion' : 1
, 'allowed_content_types': (
Modified: erp5/trunk/products/ERP5/ERP5Site.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/ERP5Site.py?rev=42902&r1=42901&r2=42902&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/ERP5Site.py [utf8] (original)
+++ erp5/trunk/products/ERP5/ERP5Site.py [utf8] Tue Feb 1 17:55:13 2011
@@ -139,6 +139,14 @@ def getCatalogStorageList(*args, **kw):
result.append((item, title))
return result
+def addERP5Tool(portal, id, portal_type):
+ if portal.hasObject(id):
+ return
+ import erp5.portal_type
+ klass = getattr(erp5.portal_type, portal_type)
+ obj = klass()
+ portal._setObject(id, obj)
+
class ReferCheckerBeforeTraverseHook:
"""This before traverse hook checks the HTTP_REFERER argument in the request
and refuses access to anything else that portal_url.
@@ -313,6 +321,7 @@ class ERP5Site(FolderMixIn, CMFSite, Cac
return CMFSite.manage_renameObject(self, id=id, new_id=new_id,
REQUEST=REQUEST)
+
def _getAcquireLocalRoles(self):
"""
Prevent local roles from being acquired outside of Portal object.
@@ -1287,7 +1296,7 @@ class ERP5Site(FolderMixIn, CMFSite, Cac
module_id = expected_module_id
# then look for module where the type is allowed
else:
- for expected_module_id in portal_object.objectIds(spec=('ERP5 Folder',)):
+ for expected_module_id in portal_object.objectIds(('ERP5 Folder',)):
module = portal_object._getOb(expected_module_id, None)
if module is not None:
if portal_type in self.portal_types[module.getPortalType()].\
@@ -1465,7 +1474,6 @@ class PortalGenerator:
addCMFCoreTool('CMF Catalog', None)
addCMFCoreTool('CMF Member Data Tool', None)
addCMFCoreTool('CMF Skins Tool', None)
- addCMFCoreTool('CMF Types Tool', None)
addCMFCoreTool('CMF Undo Tool', None)
addCMFCoreTool('CMF URL Tool', None)
addCMFCoreTool('CMF Workflow Tool', None)
@@ -1610,23 +1618,17 @@ class ERP5Generator(PortalGenerator):
# Add several other tools, only at the end in order
# to make sure that they will be reindexed
- addTool = p.manage_addProduct['ERP5'].manage_addTool
- if not p.hasObject('portal_rules'):
- addTool('ERP5 Rule Tool', None)
- if not p.hasObject('portal_simulation'):
- addTool('ERP5 Simulation Tool', None)
- if not p.hasObject('portal_deliveries'):
- addTool('ERP5 Delivery Tool', None)
- if not p.hasObject('portal_orders'):
- addTool('ERP5 Order Tool', None)
+ addERP5Tool(p, 'portal_rules', 'Rule Tool')
+ addERP5Tool(p, 'portal_simulation', 'Simulation Tool')
+ addERP5Tool(p, 'portal_deliveries', 'Delivery Tool')
+ addERP5Tool(p, 'portal_orders', 'Order Tool')
def setupTemplateTool(self, p, **kw):
"""
Setup the Template Tool. Security must be set strictly.
"""
- addTool = p.manage_addProduct['ERP5'].manage_addTool
- addTool('ERP5 Template Tool', None)
+ addERP5Tool(p, 'portal_templates', 'Template Tool')
context = p.portal_templates
permission_list = context.possible_permissions()
for permission in permission_list:
@@ -1638,7 +1640,6 @@ class ERP5Generator(PortalGenerator):
"""
if not 'portal_actions' in p.objectIds():
PortalGenerator.setupTools(self, p)
- p._delObject('portal_types')
# It is better to remove portal_catalog
# which is ZCatalog as soon as possible,
@@ -1660,51 +1661,31 @@ class ERP5Generator(PortalGenerator):
pass
# Add ERP5 Tools
- addTool = p.manage_addProduct['ERP5'].manage_addTool
- if not p.hasObject('portal_categories'):
- addTool('ERP5 Categories', None)
- if not p.hasObject('portal_ids'):
- addTool('ERP5 Id Tool', None)
+ addERP5Tool(p, 'portal_categories', 'Category Tool')
+ addERP5Tool(p, 'portal_ids', 'Id Tool')
if not p.hasObject('portal_templates'):
self.setupTemplateTool(p)
- if not p.hasObject('portal_trash'):
- addTool('ERP5 Trash Tool', None)
- if not p.hasObject('portal_alarms'):
- addTool('ERP5 Alarm Tool', None)
- if not p.hasObject('portal_domains'):
- addTool('ERP5 Domain Tool', None)
- if not p.hasObject('portal_tests'):
- addTool('ERP5 Test Tool', None)
- if not p.hasObject('portal_password'):
- addTool('ERP5 Password Tool', None)
- if not p.hasObject('portal_acknowledgements'):
- addTool('ERP5 Acknowledgement Tool', None)
+ addERP5Tool(p, 'portal_trash', 'Trash Tool')
+ addERP5Tool(p, 'portal_alarms', 'Alarm Tool')
+ addERP5Tool(p, 'portal_domains', 'Domain Tool')
+ addERP5Tool(p, 'portal_tests', 'Test Tool')
+ addERP5Tool(p, 'portal_password', 'Password Tool')
+ addERP5Tool(p, 'portal_acknowledgements', 'Acknowledgement Tool')
# Add ERP5Type Tool
- addTool = p.manage_addProduct['ERP5Type'].manage_addTool
- if not p.hasObject('portal_caches'):
- addTool('ERP5 Cache Tool', None)
- if not p.hasObject('portal_memcached'):
- addTool('ERP5 Memcached Tool', None)
- if not p.hasObject('portal_types'):
- addTool('ERP5 Types Tool', None)
- if not p.hasObject('portal_property_sheets'):
- addTool('ERP5 Property Sheet Tool', None)
+ addERP5Tool(p, 'portal_caches', 'Cache Tool')
+ addERP5Tool(p, 'portal_memcached', 'Memcached Tool')
try:
- addTool = p.manage_addProduct['ERP5Subversion'].manage_addTool
- if not p.hasObject('portal_subversion'):
- addTool('ERP5 Subversion Tool', None)
+ addERP5Tool(p, 'portal_subversion', 'Subversion Tool')
except AttributeError:
pass
# Add ERP5Type Tools
- addTool = p.manage_addProduct['ERP5Type'].manage_addTool
- if not p.hasObject('portal_classes'):
- if allowClassTool():
- addTool('ERP5 Class Tool', None)
- else:
- addTool('ERP5 Dummy Class Tool', None)
+ if allowClassTool():
+ addERP5Tool(p, 'portal_classes', 'Class Tool')
+ else:
+ addERP5Tool(p, 'portal_classes', 'Dummy Class Tool')
# Add ERP5 SQL Catalog Tool
addTool = p.manage_addProduct['ERP5Catalog'].manage_addTool
@@ -1758,17 +1739,12 @@ class ERP5Generator(PortalGenerator):
pass
# Add ERP5Form Tools
- addTool = p.manage_addProduct['ERP5Form'].manage_addTool
- if not p.hasObject('portal_selections'):
- addTool('ERP5 Selections', None)
- if not p.hasObject('portal_preferences'):
- addTool('ERP5 Preference Tool', None)
+ addERP5Tool(p, 'portal_selections', 'Selection Tool')
+ addERP5Tool(p, 'portal_preferences', 'Preference Tool')
try:
# Add ERP5SyncML Tools
- addTool = p.manage_addProduct['ERP5SyncML'].manage_addTool
- if not p.hasObject('portal_synchronizations'):
- addTool('ERP5 Synchronizations', None)
+ addERP5Tool(p, 'portal_synchronizations', 'Synchronization Tool')
except AttributeError:
pass
@@ -2032,10 +2008,6 @@ class ERP5Generator(PortalGenerator):
self.setupPermissions(p)
self.setupDefaultSkins(p)
- # ERP5 Design Choice is that all content should be user defined
- # Content is disseminated through business templates
- self.setupPortalTypes(p)
-
if not p.hasObject('content_type_registry'):
self.setupMimetypes(p)
if not update:
@@ -2054,18 +2026,6 @@ class ERP5Generator(PortalGenerator):
if not update:
self.setupIndex(p, **kw)
- def setupPortalTypes(self, p):
- """
- Install the portal_type of Business Template
- """
- tool = getToolByName(p, 'portal_types', None)
- if tool is None:
- return
- for t in (BusinessTemplate, ):
- t = t.factory_type_information
- if not tool.hasObject(t['id']):
- tool._setObject(t['id'], ERP5TypeInformation(uid=None, **t))
-
def setupERP5Core(self,p,**kw):
"""
Install the core part of ERP5
Modified: erp5/trunk/products/ERP5Form/Document/Preference.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Form/Document/Preference.py?rev=42902&r1=42901&r2=42902&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Form/Document/Preference.py [utf8] (original)
+++ erp5/trunk/products/ERP5Form/Document/Preference.py [utf8] Tue Feb 1 17:55:13 2011
@@ -93,11 +93,3 @@ class Preference( Folder ):
def disable(self):
"""Workflow method"""
self._clearCache()
-
- def _aq_dynamic(self, id):
- """ force _aq_dynamic on preference tool, because list of property sheet of
- preferences depends on the code of PreferenceTool._aq_dynamic"""
- if not PreferenceTool.aq_preference_generated:
- portal = self.getPortalObject()
- portal.portal_preferences._aq_dynamic('dummy')
- return Preference.inheritedAttribute('_aq_dynamic')(self, id)
Modified: erp5/trunk/products/ERP5Form/PreferenceTool.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Form/PreferenceTool.py?rev=42902&r1=42901&r2=42902&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Form/PreferenceTool.py [utf8] (original)
+++ erp5/trunk/products/ERP5Form/PreferenceTool.py [utf8] Tue Feb 1 17:55:13 2011
@@ -30,17 +30,15 @@
from AccessControl import ClassSecurityInfo
from AccessControl.SecurityManagement import getSecurityManager,\
setSecurityManager, newSecurityManager
-from AccessControl.PermissionRole import PermissionRole
from MethodObject import Method
from Products.ERP5Type.Globals import InitializeClass, DTMLFile
from zLOG import LOG, PROBLEM
from Products.CMFCore.utils import getToolByName
from Products.ERP5Type.Tool.BaseTool import BaseTool
-from Products.ERP5Type import Permissions, PropertySheet
+from Products.ERP5Type import Permissions
from Products.ERP5Type.Cache import CachingMethod
from Products.ERP5Type.Utils import convertToUpperCase
-from Products.ERP5Type.Accessor.TypeDefinition import list_types
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5Form import _dtmldir
@@ -52,76 +50,6 @@ class Priority:
GROUP = 2
USER = 3
-def updatePreferenceClassPropertySheetList():
- # XXX obsolete, and now handled in dynamic.portal_type_class
-
- from Products.ERP5Form.Document.Preference import Preference
- # 'Static' property sheets defined on the class
- class_property_sheet_list = Preference.property_sheets
- # Time to lookup for preferences defined on other modules
- property_sheets = list(class_property_sheet_list)
- for id in dir(PropertySheet):
- if id.endswith('Preference'):
- ps = getattr(PropertySheet, id)
- if not isinstance(ps, basestring) and ps not in property_sheets:
- property_sheets.append(ps)
- class_property_sheet_list = tuple(property_sheets)
- Preference.property_sheets = class_property_sheet_list
-
-
-def createPreferenceToolAccessorList(portal) :
- """
- Initialize all Preference methods on the preference tool.
- This method must be called on startup.
-
- This tool is capable of updating the list of Preference
- property sheets by looking at all registered property sheets
- and considering those which name ends with 'Preference'
- """
- property_list = []
-
- # 'Static' property sheets defined on the class
- # The Preference class should be imported from the common location
- # in ERP5Type since it could be overloaded in another product
- from Products.ERP5Type.Document.Preference import Preference
- for property_sheet in Preference.property_sheets:
- if not isinstance(property_sheet, basestring):
- property_list += property_sheet._properties
-
- if not len(property_list):
- return
-
- # 'Dynamic' property sheets added by portal_type
- pref_portal_type = portal.portal_types.getTypeInfo('Preference')
- if pref_portal_type is None:
- LOG('ERP5Form.PreferenceTool', PROBLEM,
- 'Preference type information is not installed.')
- else:
- pref_portal_type.updatePropertySheetDefinitionDict(
- {'_properties': property_list})
-
-
- # Generate common method names
- for prop in property_list:
- if prop.get('preference'):
- # XXX read_permission and write_permissions defined at
- # property sheet are not respected by this.
- # only properties marked as preference are used
- attribute = prop['id']
- attr_list = [ 'get%s' % convertToUpperCase(attribute)]
- if prop['type'] == 'boolean':
- attr_list.append('is%s' % convertToUpperCase(attribute))
- if prop['type'] in list_types :
- attr_list.append('get%sList' % convertToUpperCase(attribute))
- for attribute_name in attr_list:
- method = PreferenceMethod(attribute_name, prop.get('default'))
- setattr(PreferenceTool, attribute_name, method)
- read_permission = prop.get('read_permission')
- if read_permission:
- setattr(PreferenceTool, attribute_name + '__roles__',
- PermissionRole(read_permission))
-
-
class func_code: pass
class PreferenceMethod(Method):
@@ -207,23 +135,6 @@ class PreferenceTool(BaseTool):
return method(default)
return default
- def _aq_dynamic(self, id):
- # XXX as soon as zodb property sheets are put everywhere, this can
- # be safely deleted
- base_value = PreferenceTool.inheritedAttribute('_aq_dynamic')(self, id)
- if not PreferenceTool.aq_preference_generated:
- updatePreferenceClassPropertySheetList()
-
- portal = self.getPortalObject()
- while portal.portal_type != 'ERP5 Site':
- portal = portal.aq_parent.aq_inner.getPortalObject()
- createPreferenceToolAccessorList(portal)
-
- PreferenceTool.aq_preference_generated = True
- if base_value is None:
- return getattr(self, id)
- return base_value
-
security.declareProtected(Permissions.ModifyPortalContent, "setPreference")
def setPreference(self, pref_name, value) :
""" set the preference on the active Preference object"""
Modified: erp5/trunk/products/ERP5Type/Base.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Base.py?rev=42902&r1=42901&r2=42902&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Base.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Base.py [utf8] Tue Feb 1 17:55:13 2011
@@ -339,7 +339,9 @@ class PropertyHolder(object):
Invokes appropriate factory and create an accessor
"""
fake_accessor = getattr(self, id)
- ptype = self._portal_type
+ ptype = getattr(self, '_portal_type', None)
+ if ptype is None:
+ ptype = self.portal_type
if fake_accessor is PropertyHolder.WORKFLOW_METHOD_MARKER:
# Case 1 : a workflow method only
accessor = Base._doNothing
@@ -416,6 +418,7 @@ class PropertyHolder(object):
self.workflow_method_registry[id] = signature_list + (signature,)
if getattr(self, id, None) is None:
setattr(self, id, PropertyHolder.WORKFLOW_METHOD_MARKER)
+ self.createAccessor(id)
def declareProtected(self, permission, accessor_name):
"""
@@ -476,10 +479,8 @@ class PropertyHolder(object):
"""
result = {}
if inherited:
- base_list = list(klass.__bases__)
- base_list.reverse()
- for klass in base_list:
- result.update(self._getClassDict(klass, inherited=1, local=1))
+ for parent in reversed(klass.mro()):
+ result.update(parent.__dict__)
if local:
result.update(klass.__dict__)
return result
@@ -495,7 +496,7 @@ class PropertyHolder(object):
Return a list of tuple (id, method, module) for every class method
"""
return [x for x in self._getClassItemList(klass, inherited=inherited,
- local=local) if callable(x[1]) and not isinstance(x[1], Method)]
+ local=local) if callable(x[1])]
def getClassMethodIdList(self, klass, inherited=1, local=1):
"""
@@ -542,6 +543,8 @@ def initializeClassDynamicProperties(sel
Base.aq_method_generated.add(klass)
def initializePortalTypeDynamicProperties(self, klass, ptype, aq_key, portal):
+ raise ValueError("No reason to go through this no more with portal type classes")
+
## Init CachingMethod which implements caching for ERP5
from Products.ERP5Type.Cache import initializePortalCachingProperties
initializePortalCachingProperties(portal)
@@ -615,8 +618,7 @@ def initializePortalTypeDynamicPropertie
#klass.__ac_permissions__ = prop_holder.__ac_permissions__
Base.aq_portal_type[aq_key] = prop_holder
-def initializePortalTypeDynamicWorkflowMethods(self, klass, ptype, prop_holder,
- portal):
+def initializePortalTypeDynamicWorkflowMethods(ptype_klass, portal_workflow):
"""We should now make sure workflow methods are defined
and also make sure simulation state is defined."""
# aq_inner is required to prevent extra name lookups from happening
@@ -624,12 +626,13 @@ def initializePortalTypeDynamicWorkflowM
# wrapper contains an object with _aq_dynamic defined, the workflow id
# is looked up with _aq_dynamic, thus causes infinite recursions.
- portal_workflow = aq_inner(getToolByName(portal, 'portal_workflow'))
+ portal_workflow = aq_inner(portal_workflow)
+ portal_type = ptype_klass.__name__
dc_workflow_dict = dict()
interaction_workflow_dict = dict()
- for wf in portal_workflow.getWorkflowsFor(self):
+ for wf in portal_workflow.getWorkflowsFor(portal_type):
wf_id = wf.id
wf_type = wf.__class__.__name__
if wf_type == "DCWorkflowDefinition":
@@ -643,11 +646,11 @@ def initializePortalTypeDynamicWorkflowM
WorkflowState.TranslatedGetter),
('getTranslated%sTitle' % UpperCase(state_var),
WorkflowState.TranslatedTitleGetter)):
- if not hasattr(prop_holder, method_id):
+ if not hasattr(ptype_klass, method_id):
method = getter(method_id, wf_id)
# Attach to portal_type
- setattr(prop_holder, method_id, method)
- prop_holder.security.declareProtected(
+ setattr(ptype_klass, method_id, method)
+ ptype_klass.security.declareProtected(
Permissions.AccessContentsInformation,
method_id )
@@ -673,40 +676,38 @@ def initializePortalTypeDynamicWorkflowM
transition_id_set, trigger_dict = v
for tr_id, tdef in trigger_dict.iteritems():
method_id = convertToMixedCase(tr_id)
- method = getattr(klass, method_id, _MARKER)
+ method = getattr(ptype_klass, method_id, _MARKER)
if method is _MARKER:
- prop_holder.security.declareProtected(Permissions.AccessContentsInformation,
+ ptype_klass.security.declareProtected(Permissions.AccessContentsInformation,
method_id)
- prop_holder.registerWorkflowMethod(method_id, wf_id, tr_id)
+ ptype_klass.registerWorkflowMethod(method_id, wf_id, tr_id)
continue
# Wrap method
if not callable(method):
LOG('initializePortalTypeDynamicWorkflowMethods', 100,
'WARNING! Can not initialize %s on %s' % \
- (method_id, str(klass)))
+ (method_id, portal_type))
continue
if not isinstance(method, WorkflowMethod):
method = WorkflowMethod(method)
- setattr(klass, method_id, method)
+ setattr(ptype_klass, method_id, method)
else:
# We must be sure that we
# are going to register class defined
# workflow methods to the appropriate transition
transition_id = method.getTransitionId()
if transition_id in transition_id_set:
- method.registerTransitionAlways(ptype, wf_id, transition_id)
- method.registerTransitionAlways(ptype, wf_id, tr_id)
+ method.registerTransitionAlways(portal_type, wf_id, transition_id)
+ method.registerTransitionAlways(portal_type, wf_id, tr_id)
if not interaction_workflow_dict:
return
- class_method_list = prop_holder.getClassMethodIdList(klass)
- # only compute once this (somehow) costly list
- all_method_id_list = prop_holder.getAccessorMethodIdList() + \
- prop_holder.getWorkflowMethodIdList() + \
- class_method_list
+ # all methods in mro of portal type class: that contains all
+ # workflow methods and accessors you could possibly ever need
+ class_method_id_list = ptype_klass.getClassMethodIdList(ptype_klass)
interaction_queue = []
# XXX This part is (more or less...) a copy and paste
@@ -714,7 +715,7 @@ def initializePortalTypeDynamicWorkflowM
transition_id_set, trigger_dict = v
for tr_id, tdef in trigger_dict.iteritems():
if (tdef.portal_type_filter is not None and \
- ptype not in tdef.portal_type_filter):
+ portal_type not in tdef.portal_type_filter):
continue
for imethod_id in tdef.method_id:
if wildcard_interaction_method_id_match(imethod_id):
@@ -730,21 +731,21 @@ def initializePortalTypeDynamicWorkflowM
method_id_matcher))
# XXX - class stuff is missing here
- method_id_list = filter(method_id_matcher, all_method_id_list)
+ method_id_list = filter(method_id_matcher, class_method_id_list)
else:
# Single method
# XXX What if the method does not exist ?
# It's not consistent with regexp based filters.
method_id_list = [imethod_id]
for method_id in method_id_list:
- method = getattr(klass, method_id, _MARKER)
+ method = getattr(ptype_klass, method_id, _MARKER)
if method is _MARKER:
# set a default security, if this method is not already
# protected.
- if method_id not in prop_holder.security.names:
- prop_holder.security.declareProtected(
+ if method_id not in ptype_klass.security.names:
+ ptype_klass.security.declareProtected(
Permissions.AccessContentsInformation, method_id)
- prop_holder.registerWorkflowMethod(method_id, wf_id, tr_id,
+ ptype_klass.registerWorkflowMethod(method_id, wf_id, tr_id,
tdef.once_per_transaction)
continue
@@ -752,42 +753,46 @@ def initializePortalTypeDynamicWorkflowM
if not callable(method):
LOG('initializePortalTypeDynamicWorkflowMethods', 100,
'WARNING! Can not initialize %s on %s' % \
- (method_id, str(klass)))
+ (method_id, portal_type))
continue
if not isinstance(method, WorkflowMethod):
method = WorkflowMethod(method)
- setattr(klass, method_id, method)
+ setattr(ptype_klass, method_id, method)
else:
# We must be sure that we
# are going to register class defined
# workflow methods to the appropriate transition
transition_id = method.getTransitionId()
if transition_id in transition_id_set:
- method.registerTransitionAlways(ptype, wf_id, transition_id)
+ method.registerTransitionAlways(portal_type, wf_id, transition_id)
if tdef.once_per_transaction:
- method.registerTransitionOncePerTransaction(ptype, wf_id, tr_id)
+ method.registerTransitionOncePerTransaction(portal_type, wf_id, tr_id)
else:
- method.registerTransitionAlways(ptype, wf_id, tr_id)
+ method.registerTransitionAlways(portal_type, wf_id, tr_id)
if not interaction_queue:
return
- new_method_set = set(prop_holder.getClassMethodIdList(klass))
- added_method_set = new_method_set.difference(class_method_list)
+ # the only methods that could have appeared since last check are
+ # workflow methods
+ # TODO we could just queue the ids of methods that are attached to the
+ # portal type class in the previous loop, to improve performance
+ new_method_set = set(ptype_klass.getWorkflowMethodIdList())
+ added_method_set = new_method_set.difference(class_method_id_list)
# We need to run this part twice in order to handle interactions of interactions
# ex. an interaction workflow creates a workflow method which matches
# the regexp of another interaction workflow
for wf_id, tr_id, transition_id_set, once, method_id_matcher in interaction_queue:
for method_id in filter(method_id_matcher, added_method_set):
# method must already exist and be a workflow method
- method = getattr(klass, method_id)
+ method = getattr(ptype_klass, method_id)
transition_id = method.getTransitionId()
if transition_id in transition_id_set:
- method.registerTransitionAlways(ptype, wf_id, transition_id)
+ method.registerTransitionAlways(portal_type, wf_id, transition_id)
if once:
- method.registerTransitionOncePerTransaction(ptype, wf_id, tr_id)
+ method.registerTransitionOncePerTransaction(portal_type, wf_id, tr_id)
else:
- method.registerTransitionAlways(ptype, wf_id, tr_id)
+ method.registerTransitionAlways(portal_type, wf_id, tr_id)
class Base( CopyContainer,
PortalContent,
@@ -906,23 +911,15 @@ class Base( CopyContainer,
def _propertyMap(self):
""" Method overload - properties are now defined on the ptype """
- # Get all the accessor holders for ZODB Property Sheets
- if hasattr(self.__class__, 'getAccessorHolderPropertyList'):
- accessor_holder_property_list = \
- tuple(self.__class__.getAccessorHolderPropertyList())
- # Temporary portal type (such as 'TempBase' meaningful to display
- # the objects being created/updated/removed on SVN update) does
- # not inherit from any class of erp5.portal_type
- else:
- accessor_holder_property_list = ()
+ klass = self.__class__
+ property_list = []
+ # Get all the accessor holders for this portal type
+ if hasattr(klass, 'getAccessorHolderPropertyList'):
+ property_list += \
+ self.__class__.getAccessorHolderPropertyList()
- self._aq_dynamic('id') # Make sure aq_dynamic has been called once
- property_holder = Base.aq_portal_type.get(self._aq_key())
- if property_holder is None:
- return ERP5PropertyManager._propertyMap(self)
- return (tuple(getattr(property_holder, '_properties', ())) +
- tuple(getattr(self, '_local_properties', ())) +
- accessor_holder_property_list)
+ property_list += getattr(self, '_local_properties', [])
+ return tuple(property_list)
def manage_historyCompare(self, rev1, rev2, REQUEST,
historyComparisonResults=''):
@@ -945,6 +942,9 @@ class Base( CopyContainer,
createPreferenceToolAccessorList(self.getPortalObject())
def _aq_dynamic(self, id):
+ # ahah! disabled, thanks to portal type classes
+ return None
+
# _aq_dynamic has been created so that callable objects
# and default properties can be associated per portal type
# and per class. Other uses are possible (ex. WebSection).
@@ -1432,28 +1432,12 @@ class Base( CopyContainer,
except TypeError:
pass
return method(**kw)
- # Try to get a portal_type property (Implementation Dependent)
- aq_key = self._aq_key()
- aq_portal_type = Base.aq_portal_type
- if aq_key not in aq_portal_type:
- try:
- self._aq_dynamic(accessor_name)
- except AttributeError:
- pass
- if hasattr(aq_portal_type[aq_key], accessor_name):
- method = getattr(self, accessor_name)
- if d is not _MARKER:
- try:
- return method(d, **kw)
- except TypeError:
- pass
- return method(**kw)
# Try a mono valued accessor if it is available
# and return it as a list
if accessor_name.endswith('List'):
mono_valued_accessor_name = accessor_name[:-4]
- if hasattr(aq_portal_type[aq_key], mono_valued_accessor_name):
- method = getattr(self, mono_valued_accessor_name)
+ method = getattr(self, mono_valued_accessor_name, None)
+ if method is not None:
# We have a monovalued property
if d is _MARKER:
result = method(**kw)
@@ -1519,27 +1503,15 @@ class Base( CopyContainer,
if getattr(aq_self, public_accessor_name, None) is not None:
method = getattr(self, public_accessor_name)
return method(value, **kw)
- # Try to get a portal_type property (Implementation Dependent)
- aq_key = self._aq_key()
- aq_portal_type = Base.aq_portal_type
- if not aq_portal_type.has_key(aq_key):
- self._aq_dynamic('id') # Make sure _aq_dynamic has been called once
- if getattr(aq_portal_type[aq_key], accessor_name, None) is not None:
- method = getattr(self, accessor_name)
- # LOG("Base.py", 0, "method = %s, name = %s" %(method, accessor_name))
- return method(value, **kw)
- if getattr(aq_portal_type[aq_key], public_accessor_name, None) is not None:
- method = getattr(self, public_accessor_name)
- return method(value, **kw)
# Try a mono valued setter if it is available
# and call it
if accessor_name.endswith('List'):
mono_valued_accessor_name = accessor_name[:-4]
mono_valued_public_accessor_name = public_accessor_name[:-4]
method = None
- if hasattr(aq_portal_type[aq_key], mono_valued_accessor_name):
+ if hasattr(self, mono_valued_accessor_name):
method = getattr(self, mono_valued_accessor_name)
- elif hasattr(aq_portal_type[aq_key], mono_valued_public_accessor_name):
+ elif hasattr(self, mono_valued_public_accessor_name):
method = getattr(self, mono_valued_public_accessor_name)
if method is not None:
if isinstance(value, (list, tuple)):
@@ -1584,18 +1556,6 @@ class Base( CopyContainer,
method = getattr(self, public_accessor_name)
method(value, **kw)
return
- # Try to get a portal_type property (Implementation Dependent)
- aq_key = self._aq_key()
- if not Base.aq_portal_type.has_key(aq_key):
- self._aq_dynamic('id') # Make sure _aq_dynamic has been called once
- if hasattr(Base.aq_portal_type[aq_key], accessor_name):
- method = getattr(self, accessor_name)
- method(value, **kw)
- return
- if hasattr(Base.aq_portal_type[aq_key], public_accessor_name):
- method = getattr(self, public_accessor_name)
- method(value, **kw)
- return
# Finaly use standard PropertyManager
#LOG("Changing attr: ",0, key)
#try:
@@ -1692,20 +1652,16 @@ class Base( CopyContainer,
unordered_key_list = [k for k in key_list if k not in edit_order]
ordered_key_list = [k for k in edit_order if k in key_list]
restricted_method_set = set()
+ default_permission_set = set(('Access contents information',
+ 'Modify portal content'))
if restricted:
# retrieve list of accessors which doesn't use default permissions
- aq_key = self._aq_key()
- aq_portal_type = Base.aq_portal_type
- if aq_key not in aq_portal_type:
- try:
- self._aq_dynamic("")
- except AttributeError:
- pass
- prop_holder = aq_portal_type[aq_key]
- for permissions in prop_holder.__ac_permissions__:
- if permissions[0] not in ('Access contents information', 'Modify portal content'):
- for method in permissions[1]:
- restricted_method_set.add(method)
+ for ancestor in self.__class__.mro():
+ for permissions in getattr(ancestor, '__ac_permissions__', ()):
+ if permissions[0] not in default_permission_set:
+ for method in permissions[1]:
+ if method.startswith('set'):
+ restricted_method_set.add(method)
getProperty = self.getProperty
hasProperty = self.hasProperty
Modified: erp5/trunk/products/ERP5Type/ERP5Type.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/ERP5Type.py?rev=42902&r1=42901&r2=42902&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/ERP5Type.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/ERP5Type.py [utf8] Tue Feb 1 17:55:13 2011
@@ -396,9 +396,8 @@ class ERP5TypeInformation(XMLObject,
return ob
def _getPropertyHolder(self):
- ob = self.constructTempInstance(self, self.getId())
- ob._aq_dynamic('id')
- return ob.aq_portal_type[ob._aq_key()]
+ import erp5.portal_type as module
+ return getattr(module, self.getId())
security.declarePrivate('updatePropertySheetDefinitionDict')
def updatePropertySheetDefinitionDict(self, definition_dict):
@@ -499,7 +498,7 @@ class ERP5TypeInformation(XMLObject,
"""
Returns the list of properties which are specific to the portal type.
"""
- return self.constructTempInstance(self, self.getId()).propertyMap()
+ return self.__class__.propertyMap()
security.declareProtected(Permissions.AccessContentsInformation,
'PrincipiaSearchSource')
Modified: erp5/trunk/products/ERP5Type/TranslationProviderBase.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/TranslationProviderBase.py?rev=42902&r1=42901&r2=42902&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/TranslationProviderBase.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/TranslationProviderBase.py [utf8] Tue Feb 1 17:55:13 2011
@@ -62,7 +62,7 @@ class TranslationProviderBase(object):
"""
property_domain_dict = {}
- for prop in self._getPropertyHolder()._properties:
+ for prop in self._getPropertyHolder().getAccessorHolderPropertyList():
prop_id = prop['id']
if prop.get('translatable') and prop_id not in property_domain_dict:
domain_name = prop.get('translation_domain')
Modified: erp5/trunk/products/ERP5Type/Utils.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Utils.py?rev=42902&r1=42901&r2=42902&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Utils.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Utils.py [utf8] Tue Feb 1 17:55:13 2011
@@ -1301,7 +1301,8 @@ def getExistingBaseCategoryList(portal,
category_tool = getattr(portal, 'portal_categories', None)
if category_tool is None:
# most likely, accessor generation when bootstrapping a site
- warnings.warn("Category Tool is missing. Accessors can not be generated.")
+ if not getattr(portal, '_v_bootstrapping', False):
+ warnings.warn("Category Tool is missing. Accessors can not be generated.")
return ()
new_base_cat_list = []
@@ -1577,13 +1578,6 @@ def setDefaultProperties(property_holder
portal=portal)
# Create Category Accessors
createAllCategoryAccessors(portal, property_holder, cat_list, econtext)
- if object is not None and property_holder.__name__ == "Base":
- # XXX use if possible is and real class
- if portal is not None:
- portal_categories = getattr(portal, 'portal_categories', None)
- else:
- portal_categories = None
- createRelatedAccessors(portal_categories, property_holder, econtext)
property_holder.constraints = []
for constraint in constraint_list:
@@ -1642,29 +1636,6 @@ def setDefaultProperties(property_holder
# # setattr(property_holder, prop['id'], defaults[prop['type']])
# pass
- # Create for every portal type group an accessor (like isPortalDeliveryType)
- # In the future, this should probably use categories
- if portal is not None and object is not None: # we can not do anything without portal
- # import lately in order to avoid circular dependency
- from Products.ERP5Type.ERP5Type import ERP5TypeInformation
- portal_type = object.portal_type
- for group in ERP5TypeInformation.defined_group_list:
- value = portal_type in portal._getPortalGroupedTypeSet(group)
- prop = {
- 'id' : group,
- 'description' : "accessor to know the membership of portal group %s" \
- % group,
- 'type' : 'group_type',
- 'default' : value,
- 'group_type' : group,
- }
- createDefaultAccessors(
- property_holder,
- prop['id'],
- prop=prop,
- read_permission=Permissions.AccessContentsInformation,
- portal=portal)
-
#####################################################
# Accessor initialization
#####################################################
@@ -2767,6 +2738,7 @@ def createGroupTypeAccessors(property_ho
Generate accessors that allows to know if we belongs to a particular
group of portal types
"""
+ raise ValueError("This method is not used. Remove it?")
# Getter
group = prop['group_type']
accessor_name = 'is' + UpperCase(group) + 'Type'
@@ -2933,7 +2905,8 @@ def createTranslationLanguageAccessors(p
localizer = getattr(portal, 'Localizer', None)
if localizer is None:
- warnings.warn("Localizer is missing. Accessors can not be generated.")
+ if not getattr(portal, '_v_bootstrapping', False):
+ warnings.warn("Localizer is missing. Accessors can not be generated.")
return
for language in localizer.get_languages():
Modified: erp5/trunk/products/ERP5Type/dynamic/lazy_class.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/dynamic/lazy_class.py?rev=42902&r1=42901&r2=42902&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/dynamic/lazy_class.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/dynamic/lazy_class.py [utf8] Tue Feb 1 17:55:13 2011
@@ -2,12 +2,17 @@
import sys
+from Products.ERP5Type import Permissions
+from Products.ERP5Type.Accessor.Constant import Getter as ConstantGetter
from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type.Base import Base as ERP5Base
+from Products.ERP5Type.Base import PropertyHolder, initializePortalTypeDynamicWorkflowMethods
+from Products.ERP5Type.Utils import createAllCategoryAccessors, createExpressionContext, UpperCase
from ExtensionClass import ExtensionClass, pmc_init_of
from zope.interface import classImplements
from ZODB.broken import Broken, PersistentBroken
+from AccessControl import ClassSecurityInfo
from zLOG import LOG, WARNING, BLATHER
from portal_type_class import generatePortalTypeClass
@@ -87,7 +92,7 @@ class GhostBaseMetaClass(ExtensionClass,
InitGhostBase = GhostBaseMetaClass('InitGhostBase', (ERP5Base,), {})
-class PortalTypeMetaClass(GhostBaseMetaClass):
+class PortalTypeMetaClass(GhostBaseMetaClass, PropertyHolder):
"""
Meta class that is used by portal type classes
@@ -114,6 +119,9 @@ class PortalTypeMetaClass(GhostBaseMetaC
if issubclass(type(parent), PortalTypeMetaClass):
PortalTypeMetaClass.subclass_register.setdefault(parent, []).append(cls)
+ cls.security = ClassSecurityInfo()
+ cls.workflow_method_registry = {}
+
cls.__isghost__ = True
super(GhostBaseMetaClass, cls).__init__(name, bases, dictionary)
@@ -166,11 +174,14 @@ class PortalTypeMetaClass(GhostBaseMetaC
for attr in cls.__dict__.keys():
if attr not in ('__module__',
'__doc__',
+ 'security',
+ 'workflow_method_registry',
'__isghost__',
'portal_type'):
delattr(cls, attr)
# generate a ghostbase that derives from all previous bases
ghostbase = GhostBaseMetaClass('GhostBase', cls.__bases__, {})
+ cls.workflow_method_registry.clear()
cls.__bases__ = (ghostbase,)
cls.__isghost__ = True
cls.resetAcquisitionAndSecurity()
@@ -191,6 +202,69 @@ class PortalTypeMetaClass(GhostBaseMetaC
raise AttributeError
+ def generatePortalTypeAccessors(cls, site):
+ createAllCategoryAccessors(site,
+ cls,
+ cls._categories,
+ createExpressionContext(site, site))
+ # make sure that category accessors from the portal type definition
+ # are generated, no matter what
+ # XXX this code is duplicated here, in PropertySheetTool, and in Base
+ # and anyway is ugly, as tuple-like registration does not help
+ for id, fake_accessor in cls._getPropertyHolderItemList():
+ if not isinstance(fake_accessor, tuple):
+ continue
+
+ if fake_accessor is PropertyHolder.WORKFLOW_METHOD_MARKER:
+ # Case 1 : a workflow method only
+ accessor = ERP5Base._doNothing
+ else:
+ # Case 2 : a workflow method over an accessor
+ (accessor_class, accessor_args, key) = fake_accessor
+ accessor = accessor_class(id, key, *accessor_args)
+
+ # Add the accessor to the accessor holder
+ setattr(cls, id, accessor)
+
+ portal_workflow = getattr(site, 'portal_workflow', None)
+ if portal_workflow is None:
+ if not getattr(site, '_v_bootstrapping', False):
+ LOG("ERP5Type.Dynamic", WARNING,
+ "Could not generate workflow methods for %s"
+ % cls.__name__)
+ else:
+ initializePortalTypeDynamicWorkflowMethods(cls, portal_workflow)
+
+ # portal type group methods, isNodeType, isResourceType...
+ from Products.ERP5Type.ERP5Type import ERP5TypeInformation
+ # XXX possible optimization:
+ # generate all methods on Base accessor holder, with all methods
+ # returning False, and redefine on portal types only those returning True,
+ # aka only those for the group they belong to
+ for group in ERP5TypeInformation.defined_group_list:
+ value = cls.__name__ in site._getPortalGroupedTypeSet(group)
+ accessor_name = 'is' + UpperCase(group) + 'Type'
+ setattr(cls, accessor_name, ConstantGetter(accessor_name, group, value))
+ cls.declareProtected(Permissions.AccessContentsInformation,
+ accessor_name)
+
+ from Products.ERP5Type.Cache import initializePortalCachingProperties
+ initializePortalCachingProperties(site)
+
+ # TODO in reality much optimization can be done for all
+ # PropertyHolder methods:
+ # - workflow methods are only on the MetaType erp5.portal_type method
+ # Iterating over the complete MRO is nonsense and inefficient
+ def _getPropertyHolderItemList(cls):
+ cls.loadClass()
+ result = PropertyHolder._getPropertyHolderItemList(cls)
+ for parent in cls.mro():
+ if parent.__module__ == 'erp5.accessor_holder':
+ for x in parent.__dict__.items():
+ if x[0] not in PropertyHolder.RESERVED_PROPERTY_SET:
+ result.append(x)
+ return result
+
def loadClass(cls):
"""
- mro before load:
@@ -218,6 +292,7 @@ class PortalTypeMetaClass(GhostBaseMetaC
site = getSite()
try:
try:
+
class_definition = generatePortalTypeClass(site, portal_type)
except AttributeError:
LOG("ERP5Type.Dynamic", WARNING,
@@ -238,11 +313,14 @@ class PortalTypeMetaClass(GhostBaseMetaC
for key, value in attribute_dict.iteritems():
setattr(klass, key, value)
- # XXX disabled
- #klass._categories = base_category_list
+ klass._categories = base_category_list
for interface in interface_list:
classImplements(klass, interface)
+
+ klass.generatePortalTypeAccessors(site)
+ except:
+ import traceback; traceback.print_exc()
finally:
ERP5Base.aq_method_lock.release()
Modified: erp5/trunk/products/ERP5Type/dynamic/portal_type_class.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/dynamic/portal_type_class.py?rev=42902&r1=42901&r2=42902&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/dynamic/portal_type_class.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/dynamic/portal_type_class.py [utf8] Tue Feb 1 17:55:13 2011
@@ -28,6 +28,7 @@
##############################################################################
import sys
+import os
import inspect
from types import ModuleType
@@ -291,6 +292,16 @@ def generatePortalTypeClass(site, portal
erp5.accessor_holder,
property_sheet_tool)
+ if "Base" in property_sheet_set:
+ accessor_holder = None
+ # useless if Base Category is not yet here
+ if hasattr(erp5.accessor_holder, "Base Category"):
+ accessor_holder = _generateBaseAccessorHolder(
+ site,
+ erp5.accessor_holder)
+ if accessor_holder is not None:
+ accessor_holder_list.append(accessor_holder)
+
# XXX a hook to add per-portal type accessor holders maybe?
if portal_type_name == "Preference Tool":
accessor_holder = _generatePreferenceToolAccessorHolder(
@@ -397,6 +408,8 @@ def initializeDynamicModules():
erp5.temp_portal_type = registerDynamicModule('erp5.temp_portal_type',
loadTempPortalTypeClass)
+required_tool_list = [('portal_types', 'Base Type'),
+ ('portal_property_sheets', 'BaseType')]
last_sync = -1
def synchronizeDynamicModules(context, force=False):
"""
@@ -423,12 +436,63 @@ def synchronizeDynamicModules(context, f
return
last_sync = cookie
- LOG("ERP5Type.dynamic", 0, "Resetting dynamic classes")
import erp5
Base.aq_method_lock.acquire()
try:
+
+ migrated = False
+ for tool_id, line_id in required_tool_list:
+ # if the instance has no property sheet tool, or incomplete
+ # property sheets, we need to import some data to bootstrap
+ # (only likely to happen on the first run ever)
+ tool = getattr(portal, tool_id, None)
+ if tool is not None:
+ if getattr(tool, line_id, None) is None:
+ # tool exists, but is incomplete
+ portal._delObject(tool_id)
+ else:
+ # tool exists, Base Type is represented; probably OK
+ continue
+
+ if not migrated:
+ # XXX: if some portal types are missing, for instance
+ # if some Tools have no portal types, this is likely to fail with an
+ # error. On the other hand, we can't proceed without this change,
+ # and if we dont import the xml, the instance wont start.
+ portal.migrateToPortalTypeClass()
+ migrated = True
+
+ LOG('ERP5Site', INFO, 'importing transitional %s tool'
+ ' from Products.ERP5.bootstrap to be able to load'
+ ' core items...' % tool_id)
+
+ from Products.ERP5.ERP5Site import getBootstrapDirectory
+ bundle_path = os.path.join(getBootstrapDirectory(),
+ '%s.xml' % tool_id)
+ assert os.path.exists(bundle_path), 'Please update ERP5 product'
+
+ try:
+ tool = portal._importObjectFromFile(
+ bundle_path,
+ id=tool_id,
+ verify=False,
+ set_owner=False,
+ suppress_events=True)
+ from Products.ERP5.Document.BusinessTemplate import _recursiveRemoveUid
+ _recursiveRemoveUid(tool)
+ portal._setOb(tool_id, tool)
+ except:
+ import traceback; traceback.print_exc()
+ raise
+
+ if not getattr(portal, '_v_bootstrapping', False):
+ LOG('ERP5Site', INFO, 'Transition successful, please update your'
+ ' business templates')
+
+
+ LOG("ERP5Type.dynamic", 0, "Resetting dynamic classes")
for class_name, klass in inspect.getmembers(erp5.portal_type,
inspect.isclass):
klass.restoreGhostState()
More information about the Erp5-report
mailing list