[Erp5-report] r38691 jm - in /erp5/trunk/products: CMFActivity/ ERP5/ ERP5/Tool/ ERP5Type/ ...

nobody at svn.erp5.org nobody at svn.erp5.org
Mon Sep 27 23:16:07 CEST 2010


Author: jm
Date: Mon Sep 27 23:16:06 2010
New Revision: 38691

URL: http://svn.erp5.org?rev=38691&view=rev
Log:
Stop using zope.site.hooks and implement our own getSite using ERP5Site.__of__

zope.site.hooks.setSite is always called too late to be usable and it became
a nightmare to make getSite working early enough.

This fixes portal creation on Zope 2.12, which was broken since r38613.

Removed:
    erp5/trunk/products/ERP5Type/patches/getSite.py
Modified:
    erp5/trunk/products/CMFActivity/ActivityTool.py
    erp5/trunk/products/ERP5/ERP5Site.py
    erp5/trunk/products/ERP5/Tool/AlarmTool.py
    erp5/trunk/products/ERP5Type/Dynamic/portaltypeclass.py
    erp5/trunk/products/ERP5Type/ZopePatch.py
    erp5/trunk/products/ERP5Type/tests/ERP5TypeTestCase.py
    erp5/trunk/products/ERP5Type/tests/runUnitTest.py

Modified: erp5/trunk/products/CMFActivity/ActivityTool.py
URL: http://svn.erp5.org/erp5/trunk/products/CMFActivity/ActivityTool.py?rev=38691&r1=38690&r2=38691&view=diff
==============================================================================
--- erp5/trunk/products/CMFActivity/ActivityTool.py [utf8] (original)
+++ erp5/trunk/products/CMFActivity/ActivityTool.py [utf8] Mon Sep 27 23:16:06 2010
@@ -67,7 +67,6 @@ except ImportError:
 
 from ZODB.POSException import ConflictError
 from Products.MailHost.MailHost import MailHostError
-from zope.site.hooks import setSite
 
 from zLOG import LOG, INFO, WARNING, ERROR
 from warnings import warn
@@ -878,9 +877,6 @@ class ActivityTool (Folder, UniqueObject
         if not acquired:
           return
 
-        portal = self.getPortalObject()
-        setSite(portal)
-
         # make sure our skin is set-up. On CMF 1.5 it's setup by acquisition,
         # but on 2.2 it's by traversal, and our site probably wasn't traversed
         # by the timerserver request, which goes into the Zope Control_Panel

Modified: erp5/trunk/products/ERP5/ERP5Site.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/ERP5Site.py?rev=38691&r1=38690&r2=38691&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/ERP5Site.py [utf8] (original)
+++ erp5/trunk/products/ERP5/ERP5Site.py [utf8] Mon Sep 27 23:16:06 2010
@@ -15,6 +15,8 @@
   Portal class
 """
 
+import threading
+from weakref import ref as weakref
 from Products.ERP5Type import Globals
 from Products.ERP5Type.Globals import package_home
 
@@ -36,8 +38,7 @@ from Products.ERP5Type.Log import log as
 from Products.CMFActivity.Errors import ActivityPendingError
 import ERP5Defaults
 from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
-
-from zope.site.hooks import setSite
+from Products.ERP5Type.Dynamic.portaltypeclass import synchronizeDynamicModules
 
 from zLOG import LOG, INFO
 from string import join
@@ -178,6 +179,38 @@ class ReferCheckerBeforeTraverseHook:
             'request : "%s"' % http_url)
         response.unauthorized()
 
+
+class _site(threading.local):
+  """Class for getting and setting the site in the thread global namespace
+  """
+  site = ()
+
+  def __new__(cls):
+    self = threading.local.__new__(cls)
+    return self.__get, self.__set
+
+  def __get(self):
+    """Returns the currently processed site
+
+    XXX The returned site is not wrapped in a request.
+    """
+    app, site_id = self.site[-1]
+    app = app()
+    return CMFSite.__of__(app.__dict__[site_id], app)
+
+  def __set(self, site):
+    app = aq_base(site.aq_parent)
+    self.site = [x for x in self.site if x[0]() is not app]
+    # Use weak references for automatic cleanup. In practice, this is probably
+    # useless, because there is no reason a thread reopen the database.
+    self.site.append((weakref(app, self.__del), site.id))
+
+  def __del(self, app):
+    self.site = [x for x in self.site if x[0] is not app]
+
+getSite, setSite = _site()
+
+
 class ERP5Site(FolderMixIn, CMFSite, CacheCookieMixin):
   """
   The *only* function this class should have is to help in the setup
@@ -213,6 +246,17 @@ class ERP5Site(FolderMixIn, CMFSite, Cac
     """
     return self.index_html()
 
+  def __of__(self, parent):
+    self = CMFSite.__of__(self, parent)
+    # Use a transactional variable for performance reason,
+    # since ERP5Site.__of__ is called quite often.
+    tv = getTransactionalVariable()
+    if 'ERP5Site.__of__' not in tv:
+      tv['ERP5Site.__of__'] = None
+      setSite(self)
+      synchronizeDynamicModules(self)
+    return self
+
   def manage_beforeDelete(self, item, container):
     # On Zope 2.8, skin is setup during Acquisition (in the .__of__() method).
     # On Zope 2.12, skin is setup during __before_publishing_traverse__, which
@@ -359,14 +403,6 @@ class ERP5Site(FolderMixIn, CMFSite, Cac
     # and tries to load subobjects of the portal too early
     return []
 
-  security.declareProtected(Permissions.AccessContentsInformation, 'objectValues')
-  def objectValues(self, *args, **kw):
-    # When stepping in an ERP5Site from outside,
-    # (e.g. left hand tree frame in {zope root}/manage )
-    # we need to set up the site to load portal types inside each site
-    setSite(self)
-    return super(ERP5Site, self).objectValues(*args, **kw)
-
   security.declareProtected(Permissions.AccessContentsInformation, 'searchFolder')
   def searchFolder(self, **kw):
     """
@@ -375,7 +411,6 @@ class ERP5Site(FolderMixIn, CMFSite, Cac
     """
     if not kw.has_key('parent_uid'):
       kw['parent_uid'] = self.uid
-    setSite(self)
     return self.portal_catalog.searchResults(**kw)
 
   security.declareProtected(Permissions.AccessContentsInformation, 'countFolder')
@@ -386,7 +421,6 @@ class ERP5Site(FolderMixIn, CMFSite, Cac
     """
     if not kw.has_key('parent_uid'):
       kw['parent_uid'] = self.uid
-    setSite(self)
     return self.portal_catalog.countResults(**kw)
 
   # Proxy methods for security reasons
@@ -1484,23 +1518,6 @@ class ERP5Generator(PortalGenerator):
     # Return the fully wrapped object.
     p = parent.this()._getOb(id)
 
-    setSite(p)
-
-    try:
-      sm = p.getSiteManager()
-    except:
-      # Zope 2.8, ot site manager, no DefaultTraversable, dont care
-      pass
-    else:
-      import zope
-      # XXX hackish, required to setUpERP5Core while in tests,
-      # could probably be better
-      # (for some reason calling setSite here does not allow
-      # the newly created site to find the global DefaultTraversable
-      # object)
-      sm.registerAdapter(zope.traversing.adapters.DefaultTraversable,
-                         required=(zope.interface.Interface,))
-
     erp5_sql_deferred_connection_string = erp5_sql_connection_string
     p._setProperty('erp5_catalog_storage',
                    erp5_catalog_storage, 'string')

Modified: erp5/trunk/products/ERP5/Tool/AlarmTool.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Tool/AlarmTool.py?rev=38691&r1=38690&r2=38691&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Tool/AlarmTool.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Tool/AlarmTool.py [utf8] Mon Sep 27 23:16:06 2010
@@ -46,7 +46,6 @@ import re
 # minimal IP:Port regexp
 NODE_RE = re.compile('^\d+\.\d+\.\d+\.\d+:\d+$')
 
-from zope.site.hooks import setSite
 try:
   from Products.TimerService import getTimerService
 except ImportError:
@@ -211,10 +210,6 @@ class AlarmTool(BaseTool):
     if not acquired:
       return
     try:
-
-      portal = self.getPortalObject()
-      setSite(portal)
-
       # make sure our skin is set-up. On CMF 1.5 it's setup by acquisition,
       # but on 2.2 it's by traversal, and our site probably wasn't traversed
       # by the timerserver request, which goes into the Zope Control_Panel

Modified: erp5/trunk/products/ERP5Type/Dynamic/portaltypeclass.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Dynamic/portaltypeclass.py?rev=38691&r1=38690&r2=38691&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Dynamic/portaltypeclass.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Dynamic/portaltypeclass.py [utf8] Mon Sep 27 23:16:06 2010
@@ -6,7 +6,6 @@ import sys
 import inspect
 from types import ModuleType
 
-from zope.site.hooks import getSite
 from Products.ERP5Type.Globals import InitializeClass
 from Products.ERP5Type.Utils import setDefaultClassProperties
 
@@ -54,6 +53,7 @@ def portal_type_factory(portal_type_name
     # before creating any Base Type object
     type_class = "BusinessTemplate"
   else:
+    from Products.ERP5.ERP5Site import getSite
     site = getSite()
 
     type_tool = site.portal_types

Modified: erp5/trunk/products/ERP5Type/ZopePatch.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/ZopePatch.py?rev=38691&r1=38690&r2=38691&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/ZopePatch.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/ZopePatch.py [utf8] Mon Sep 27 23:16:06 2010
@@ -70,4 +70,3 @@ from Products.ERP5Type.patches import Zo
 from Products.ERP5Type.patches.PropertyManager import ERP5PropertyManager
 from Products.ERP5Type.patches.DCWorkflow import ValidationFailed, ERP5TransitionDefinition
 from Products.ERP5Type.patches.BTreeFolder2 import ERP5BTreeFolder2Base
-from Products.ERP5Type.patches.getSite import getSite

Removed: erp5/trunk/products/ERP5Type/patches/getSite.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/patches/getSite.py?rev=38690&view=auto
==============================================================================
--- erp5/trunk/products/ERP5Type/patches/getSite.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/patches/getSite.py (removed)
@@ -1,42 +0,0 @@
-from Products.ERP5Type import Globals
-module_name = 'zope.site.hooks'
-try:
-  hooks = __import__(module_name, {}, {}, module_name)
-  _getSite = hooks.getSite
-  _setSite = hooks.setSite
-except ImportError:
-  # backwards compatibility for Zope < 2.12
-  import imp, sys
-  import zope
-  try:
-    site = zope.site
-  except:
-    sys.modules['zope.site'] = zope.site = imp.new_module('zope.site')
-  sys.modules[module_name] = hooks = imp.new_module(module_name)
-
-  def _getSite():
-    return None
-  def _setSite(site=None):
-    request = Globals.get_request()
-    if not (None in (site, request) or site in request.get('PARENTS', ())):
-      request['PARENTS'] = [site]
-
-# patch getSite so that it works everywhere
-def getSite():
-  site = _getSite()
-  if site is None:
-    parents = Globals.get_request()['PARENTS']
-    for site in parents[::-1]:
-      if getattr(site, 'getPortalObject', None) is not None:
-        break
-    else:
-      raise AttributeError("getSite() can't retrieve the site")
-  return site
-hooks.getSite = getSite
-
-def setSite(site=None):
-  _setSite(site)
-  if site is not None:
-    from Products.ERP5Type.Dynamic.portaltypeclass import synchronizeDynamicModules
-    synchronizeDynamicModules(site)
-hooks.setSite = setSite

Modified: erp5/trunk/products/ERP5Type/tests/ERP5TypeTestCase.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/tests/ERP5TypeTestCase.py?rev=38691&r1=38690&r2=38691&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/tests/ERP5TypeTestCase.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/tests/ERP5TypeTestCase.py [utf8] Mon Sep 27 23:16:06 2010
@@ -50,6 +50,14 @@ Products.ERP5Type.Utils.get_request = ge
 Globals.get_request = get_request
 
 try:
+  from zope.site.hooks import setSite
+except ImportError:
+  # BACK: Zope 2.8. setSite is somewhere else, and we can't use it anyway
+  # since ERP5Site is not yet an ISite. Remove once we drop support for 2.8
+  def setSite(site=None):
+    pass
+
+try:
   import itools.zope
   itools.zope.get_context = get_context
 except ImportError:
@@ -221,8 +229,6 @@ failed_portal_installation = {}
 # this is a mapping 'list of business template -> boolean
 setup_done = {}
 
-from zope.site.hooks import setSite
-
 def _getConnectionStringDict():
   """Returns the connection strings used for this test.
   """

Modified: erp5/trunk/products/ERP5Type/tests/runUnitTest.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/tests/runUnitTest.py?rev=38691&r1=38690&r2=38691&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/tests/runUnitTest.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/tests/runUnitTest.py [utf8] Mon Sep 27 23:16:06 2010
@@ -536,6 +536,7 @@ def runUnitTestList(test_list, verbosity
       import transaction
       transaction.commit()
       ZopeTestCase.close(app)
+      del app
 
     if zeo_client_pid_list is None:
       result = suite()




More information about the Erp5-report mailing list