[Zope-Checkins] SVN: Zope/branches/publication-refactor/lib/python/ Refactor some of the Zope2 traversal. This includes using

Michael Kerrin michael.kerrin at openapp.biz
Fri Apr 21 10:20:06 EDT 2006


Log message for revision 67219:
  Refactor some of the Zope2 traversal. This includes using
  IPublishTraverse to do the traversal, and using Zope3 to
  find the views.
  

Changed:
  U   Zope/branches/publication-refactor/lib/python/Products/Five/configure.zcml
  U   Zope/branches/publication-refactor/lib/python/ZPublisher/BaseRequest.py
  U   Zope/branches/publication-refactor/lib/python/ZPublisher/Publication.py
  U   Zope/branches/publication-refactor/lib/python/ZPublisher/Publish.py
  U   Zope/branches/publication-refactor/lib/python/ZPublisher/Test.py

-=-
Modified: Zope/branches/publication-refactor/lib/python/Products/Five/configure.zcml
===================================================================
--- Zope/branches/publication-refactor/lib/python/Products/Five/configure.zcml	2006-04-21 14:18:10 UTC (rev 67218)
+++ Zope/branches/publication-refactor/lib/python/Products/Five/configure.zcml	2006-04-21 14:20:05 UTC (rev 67219)
@@ -60,4 +60,11 @@
        provides="zope.publisher.interfaces.ITraversingRequest"
        />
 
+  <adapter
+     for="*
+          .interfaces.IZope2Request"
+     provides="zope.publisher.interfaces.IPublishTraverse"
+     factory="ZPublisher.Publication.Zope2PublishTraverseAdapter"
+     />
+
 </configure>

Modified: Zope/branches/publication-refactor/lib/python/ZPublisher/BaseRequest.py
===================================================================
--- Zope/branches/publication-refactor/lib/python/ZPublisher/BaseRequest.py	2006-04-21 14:18:10 UTC (rev 67218)
+++ Zope/branches/publication-refactor/lib/python/ZPublisher/BaseRequest.py	2006-04-21 14:20:05 UTC (rev 67219)
@@ -230,16 +230,9 @@
 
         if method=='GET' or method=='POST' and not isinstance(response,
                                                               xmlrpc.Response):
-            # Probably a browser
-            no_acquire_flag=0
             # index_html is still the default method, only any object can
             # override it by implementing its own __browser_default__ method
             method = 'index_html'
-        elif self.maybe_webdav_client:
-            # Probably a WebDAV client.
-            no_acquire_flag=1
-        else:
-            no_acquire_flag=0
 
         URL=request['URL']
         parents = request['PARENTS']
@@ -315,7 +308,7 @@
 
                 try:
                     subobject = self.publication.traverseName(
-                        self, object, entry_name, no_acquire_flag)
+                        self, object, entry_name)
                 except NotFound:
                     if debug_mode:
                         return response.debugError(
@@ -323,30 +316,6 @@
                     else:
                         return response.notFoundError(URL)
 
-                # Ensure that the object has a docstring, or that the parent
-                # object has a pseudo-docstring for the object. Objects that
-                # have an empty or missing docstring are not published.
-                doc = getattr(subobject, '__doc__', None)
-                if doc is None:
-                    doc = getattr(object, '%s__doc__' % entry_name, None)
-                if not doc:
-                    return response.debugError(
-                        "The object at %s has an empty or missing " \
-                        "docstring. Objects must have a docstring to be " \
-                        "published." % URL
-                        )
-
-                # Hack for security: in Python 2.2.2, most built-in types
-                # gained docstrings that they didn't have before. That caused
-                # certain mutable types (dicts, lists) to become publishable
-                # when they shouldn't be. The following check makes sure that
-                # the right thing happens in both 2.2.2+ and earlier versions.
-
-                if not typeCheck(subobject):
-                    return response.debugError(
-                        "The object at %s is not publishable." % URL
-                        )
-
                 roles = getRoles(
                     object, (not got) and entry_name or None, subobject,
                     roles)

Modified: Zope/branches/publication-refactor/lib/python/ZPublisher/Publication.py
===================================================================
--- Zope/branches/publication-refactor/lib/python/ZPublisher/Publication.py	2006-04-21 14:18:10 UTC (rev 67218)
+++ Zope/branches/publication-refactor/lib/python/ZPublisher/Publication.py	2006-04-21 14:20:05 UTC (rev 67219)
@@ -16,9 +16,10 @@
 import sys
 import transaction
 import types
+import xmlrpc
 
 from zope.event import notify
-from zope.component import queryUtility
+from zope.component import queryUtility, queryMultiAdapter
 from zope.interface import implements
 from zope.publisher.interfaces import IRequest, IPublication
 from zope.publisher.interfaces import NotFound, IPublicationRequest
@@ -30,12 +31,16 @@
 from zope.app.publication.interfaces import BeforeTraverseEvent
 from zope.app.publication.interfaces import IBrowserRequestFactory
 from zope.app.publication.interfaces import IRequestPublicationFactory
+from zope.app.traversing.namespace import nsParse
+from zope.app.traversing.namespace import namespaceLookup
+from zope.app.traversing.interfaces import TraversalError
 
 from ZPublisher.Publish import Retry
 from ZPublisher.Publish import get_module_info, call_object
 from ZPublisher.Publish import missing_name, dont_publish_class
 from ZPublisher.mapply import mapply
 from ZPublisher.BaseRequest import RequestContainer
+from ZPublisher.BaseRequest import typeCheck
 
 from ZPublisher.HTTPRequest import HTTPRequest
 from ZPublisher.HTTPResponse import HTTPResponse
@@ -234,7 +239,76 @@
         # request supports retry. It's not clear how this will be
         # handled by Zope 3.
 
-    def traverseName(self, request, ob, name, acquire=True):
+    def traverseName(self, request, ob, name):
+        nm = name # the name to look up the object with
+
+        if name and name[:1] in '@+':
+            # Process URI segment parameters.
+            ns, nm = nsParse(name)
+            if ns:
+                try:
+                    ob2 = namespaceLookup(ns, nm, ob, request)
+                except TraversalError:
+                    raise NotFound(ob, name)
+
+                return ob2
+
+        if nm == '.':
+            return ob
+
+        if zope.publisher.interfaces.IPublishTraverse.providedBy(ob):
+            ob2 = ob.publishTraverse(request, nm)
+        else:
+            # self is marker
+            adapter = queryMultiAdapter((ob, request),
+                                     zope.publisher.interfaces.IPublishTraverse,
+                                     default = self)
+            if adapter is self:
+                ## Zope2 doesn't set up its own adapters in a lot of cases
+                ## so we will just use a default adapter.
+                adapter = Zope2PublishTraverseAdapter(ob, request)
+
+            ob2 = adapter.publishTraverse(request, nm)
+
+        return ob2
+
+    def getDefaultTraversal(self, request, ob):
+        if hasattr(ob, '__browser_default__'):
+            return object.__browser_default__(request)
+        if getattr(ob, 'index_html', None):
+            return ob, ['index_html']
+        return ob, []
+
+_publications = {}
+def get_publication(module_name=None):
+    if module_name is None:
+        module_name = "Zope2"
+    if not _publications.has_key(module_name):
+        _publications[module_name] = ZopePublication(db=None,
+                                                     module_name=module_name)
+    return _publications[module_name]
+
+
+class Zope2PublishTraverseAdapter(object):
+    implements(zope.publisher.interfaces.IPublishTraverse)
+
+    def __init__(self, context, request):
+        self.context = context
+
+    def subObject(self, request, ob, name):
+        # How did this request come in? (HTTP GET, PUT, POST, etc.)
+        method = request.get('REQUEST_METHOD', 'GET').upper()
+
+        if method == 'GET' or method == 'POST' and \
+               not isinstance(request.response, xmlrpc.Response):
+            # Probably a browser
+            no_acquire_flag=0
+        elif request.maybe_webdav_client:
+            # Probably a WebDAV client.
+            no_acquire_flag=1
+        else:
+            no_acquire_flag=0
+        
         if hasattr(ob, '__bobo_traverse__'):
             try:
                 subob = ob.__bobo_traverse__(request, name)
@@ -264,7 +338,7 @@
             # an object 'test' existed above it in the
             # heirarchy -- you'd always get the
             # existing object :(
-            if (acquire and hasattr(ob, 'aq_base')):
+            if (no_acquire_flag and hasattr(ob, 'aq_base')):
                 if hasattr(ob.aq_base, name):
                     return getattr(ob, name)
                 else:
@@ -272,30 +346,41 @@
             else:
                 return getattr(ob, name)
         except AttributeError:
-            got = 1
             try:
                 return ob[name]
             except (KeyError, IndexError,
                     TypeError, AttributeError):
                 raise NotFound(ob, name)
+        
+    def publishTraverse(self, request, name):
+        subobject = self.subObject(request, self.context, name)
 
-    def getDefaultTraversal(self, request, ob):
-        if hasattr(ob, '__browser_default__'):
-            return object.__browser_default__(request)
-        if getattr(ob, 'index_html', None):
-            return ob, ['index_html']
-        return ob, []
+        # Ensure that the object has a docstring, or that the parent
+        # object has a pseudo-docstring for the object. Objects that
+        # have an empty or missing docstring are not published.
+        doc = getattr(subobject, '__doc__', None)
+        if doc is None:
+            doc = getattr(object, '%s__doc__' % entry_name, None)
+        if not doc:
+            return request.response.debugError(
+                "The object at %s has an empty or missing " \
+                "docstring. Objects must have a docstring to be " \
+                "published." % URL
+                )
 
-_publications = {}
-def get_publication(module_name=None):
-    if module_name is None:
-        module_name = "Zope2"
-    if not _publications.has_key(module_name):
-        _publications[module_name] = ZopePublication(db=None,
-                                                     module_name=module_name)
-    return _publications[module_name]
+        # Hack for security: in Python 2.2.2, most built-in types
+        # gained docstrings that they didn't have before. That caused
+        # certain mutable types (dicts, lists) to become publishable
+        # when they shouldn't be. The following check makes sure that
+        # the right thing happens in both 2.2.2+ and earlier versions.
 
+        if not typeCheck(subobject):
+            return request.response.debugError(
+                "The object at %s is not publishable." % URL
+                )
 
+        return subobject
+
 class Zope2HTTPResponse(HTTPResponse):
     
     def setResult(self, result):

Modified: Zope/branches/publication-refactor/lib/python/ZPublisher/Publish.py
===================================================================
--- Zope/branches/publication-refactor/lib/python/ZPublisher/Publish.py	2006-04-21 14:18:10 UTC (rev 67218)
+++ Zope/branches/publication-refactor/lib/python/ZPublisher/Publish.py	2006-04-21 14:20:05 UTC (rev 67219)
@@ -21,6 +21,7 @@
 from maybe_lock import allocate_lock
 from mapply import mapply
 from zExceptions import Redirect
+from zope.app.publication.browser import setDefaultSkin
 
 class Retry(Exception):
     """Raise this to retry a request
@@ -179,6 +180,11 @@
         publication = get_publication(module_name)
         request.setPublication(publication)
 
+        # make sure that the request we hand over has the
+        # default layer/skin set on it; subsequent code that
+        # wants to look up views will likely depend on it
+        setDefaultSkin(request)
+
         from zope.publisher.publish import publish as publish3
         publish3(request)
     except SystemExit, v:

Modified: Zope/branches/publication-refactor/lib/python/ZPublisher/Test.py
===================================================================
--- Zope/branches/publication-refactor/lib/python/ZPublisher/Test.py	2006-04-21 14:18:10 UTC (rev 67218)
+++ Zope/branches/publication-refactor/lib/python/ZPublisher/Test.py	2006-04-21 14:20:05 UTC (rev 67219)
@@ -190,6 +190,11 @@
             stdout=response.stdout
         if request is None:
             request=Request(stdin, environ, response)
+        # make sure that the request we hand over has the
+        # default layer/skin set on it; subsequent code that
+        # wants to look up views will likely depend on it
+        from zope.app.publication.browser import setDefaultSkin
+        setDefaultSkin(request)
         request.setPublication(get_publication())
         for k, v in extra.items(): request[k]=v
         response = request.response



More information about the Zope-Checkins mailing list