[Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication - PublicationTraverse.py:1.1.2.18 Traversers.py:1.1.2.18 zopepublication.zcml:1.1.2.5

Jim Fulton jim@zope.com
Thu, 23 May 2002 14:01:50 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication
In directory cvs.zope.org:/tmp/cvs-serv26429/lib/python/Zope/App/ZopePublication

Modified Files:
      Tag: Zope-3x-branch
	PublicationTraverse.py Traversers.py zopepublication.zcml 
Log Message:
This all started with wanting to be able to use url;view in a ZPT path. :)

That lead me to:

- Massive traversal refactoring.

  Namespace handling is now centralized in Zope.App.Traversing. 

- ZPT refactoring, including some renaming that touches pretty much everything. :)

  - The application specific ZPT support was moved into
    Zope.App.PageTemplate. 

  - To get page template files (for use in views):

    from Zope.App.PageTemplate import ViewPageTemplateFile

  - Fixed up security so that ZPT expressions only have access to 
    safe builtins and so that modules namespace does imports safely.

  - Got ZPTPage working!

- renaming url to absolute_url and got absolute_url to work in paths.

- Cleaned up the (as yet unused) RestrictedInterpreter module in
  Zope.Security. In particular, changed to use a separate
  RestrictedBuiltins module.



=== Zope3/lib/python/Zope/App/ZopePublication/PublicationTraverse.py 1.1.2.17 => 1.1.2.18 ===
      import ApplicationController
 from Zope.Proxy.ProxyIntrospection import removeAllProxies
-from Zope.ComponentArchitecture.Exceptions import ComponentLookupError
+from Zope.App.Traversing.Namespaces import namespaceLookup
+from Zope.App.Traversing.ParameterParsing import parameterizedNameParse
 
 class DuplicateNamespaces(Exception):
     """More than one namespace was specified in a request"""
@@ -34,9 +35,6 @@
 class UnknownNamespace(Exception):
     """A parameter specified an unknown namespace"""
 
-class ExcessiveWrapping(NotFound):
-    """Too many levels of acquisition wrapping. We don't believe them."""
-
 class PublicationTraverse:
 
     def traverseName(self, request, ob, name):
@@ -44,48 +42,32 @@
         nm = name # the name to look up the object with
 
         if name.find(';') >= 0:
-            # Process URI segment parameters. It makes sense to centralize
-            # this here. Later it may be abstracted and distributed again,
-            # but, if so it will be distributed to various path
-            # traversers, rather than to traversal adapters/views.
-            ns = ''
-            parts = name.split(';')
-            nm = parts[:1]
-            for param in parts[1:]:
-                l = param.find('=')
-                if l >= 0:
-                    pname = param[:l]
-                    pval = param[l+1:]
-                    if pname == 'ns':
-                        if ns:
-                            raise DuplicateNamespaces(name)
-                        ns = pval
-                    else:
-                        pset = getattr(self, "_parameterSet%s" % pname,
-                                       self # marker
-                                       )
-                        if pset is self:
-                            # We don't know about this one, so leave it in the
-                            # name
-                            nm.append(param)
-                        else:
-                            pset(pname, pval, request)
+            # Process URI segment parameters. 
+            ns, nm, parms = parameterizedNameParse(name)
+
+            unknown_parms = ()
+            for pname, pval in parms:
+                pset = getattr(self, "_parameterSet%s" % pname,
+                               self # marker
+                               )
+                if pset is self:
+                    # We don't know about this one
+                    unknown_parms += ((pname, pval),)
                 else:
-                    if ns:
-                        raise DuplicateNamespaces(name)
-                    ns = param
+                    pset(pname, pval, request)
 
-            nm = ';'.join(nm)
             if ns:
-                traverse = getattr(self, "_traverse%s" % ns,
-                                   self # marker
-                                   )
-                if traverse is self:
-                    raise UnknownNamespace(ns, name)
-
-                ob2 = traverse(request, ob, nm)
-                return self._wrap(ob2, ob, name, nm)
-            elif not nm:
+                ob2 = namespaceLookup(name, ns, nm, unknown_parms, ob, request)
+                return ContextWrapper(ob2, ob, name=name)
+
+            if unknown_parms:
+                nm = "%s;%s" % (
+                    nm,
+                    ';'.join(["%s=%s" % (parm[0], parm[1])
+                              for parm in unknown_parms])
+                    )
+                
+            if not nm:
                 # Just set params, so skip
                 return ob
 
@@ -103,81 +85,7 @@
             else:
                 raise NotFound(ob, name, request)
 
-        return self._wrap(ob2, ob, name, nm)
-
-    def _wrap(self, ob, parent, name, nm):
-        wrapped = ContextWrapper(ob, parent, name=name)
-        return wrapped
-
-    def _traverseview(self, request, ob, name):
-        # use self as marker
-        r = getRequestView(ob, name, request, self)
-        if r is self: 
-            raise NotFound(ob, name, request)
-        return r
-
-    def _traverseetc(self, request, ob, name):
-        # XXX
-        
-        # This is here now to allow us to get service managers from a
-        # separate namespace from the content. We add and etc
-        # namespace to allow us to handle misc objects.  We'll apply
-        # YAGNI for now and hard code this. We'll want something more
-        # general later. We were thinking of just calling "get"
-        # methods, but this is probably too magic. In particular, we
-        # will treat returned objects as sub-objects wrt security and
-        # not all get methods may satisfy this assumption. It might be
-        # best to introduce some sort of etc registry.
-
-        if name == 'ApplicationController' and ob is None:
-            return self.__etcApplicationController()
-
-        if name != 'Services':
-            raise NotFound(ob, name, request)
-        
-        try:
-            return ob.getServiceManager()
-        except AttributeError, ComponentLookupError:
-            raise NotFound(ob, name, request)
-
-    def __etcApplicationController(self):
-        return ApplicationController
-
-    def _traverseacquire(self, request, ob, name):
-        """acquires content objects from higher in tree"""
-        i = 0
-        origOb=ob
-        while i < 200:
-            i = i + 1
-            #r = getattr(ob, name, self) # no...
-            # what we actually want to do is traverse ob, then parents, yes?
-            # this is a cut and paste of the pertinent traverseName code;
-            # clean to your pleasure, if desired.
-            try:
-                if request.getViewType().isImplementedBy(ob):
-                    ob2 = ob.publishTraverse(request, name)
-                else:
-                    adapter = getRequestView(ob, '_traverse', request, self # marker
-                                             ) 
-
-                    if adapter is not self:
-                        ob2 =  adapter.publishTraverse(request, name)
-                    else:
-                        raise NotFound(ob, name, request)
-                return ob2
-                
-            except NotFound:
-                ob = getWrapperContext(ob)
-                if ob is None:
-                    raise NotFound(origOb, name, request)
-        raise ExcessiveWrapping(origOb, name, request)
-    
-    def _traversecreate(self, request, ob, name): 
-        for addable in getService(ob,'AddableContent').getAddables(ob):
-            if addable.id == name:
-                return addable
-        raise NotFound(ob, name, request)
-        
+        return ContextWrapper(ob2, ob, name=name)
 
 class PublicationTraverser(PublicationTraverse):    
 


=== Zope3/lib/python/Zope/App/ZopePublication/Traversers.py 1.1.2.17 => 1.1.2.18 ===
 from Zope.ComponentArchitecture \
      import getRequestView, getRequestDefaultViewName
+from Zope.ComponentArchitecture.Exceptions import ComponentLookupError
 
-class DefaultTraverser:
-    """
+class SimpleComponentTraverser:
+    """Browser traverser for simple components that can only traverse to views
     """
     __implements__ = IBrowserPublisher
 
@@ -25,27 +26,70 @@
         self.target = target
 
     def browserDefault(self, request):
-        #XXX: (hack), we really need this to be component
-        # specific. 
         ob = self.target
+        
+        view_name = getRequestDefaultViewName(ob, request)
+
+        return ob, (view_name,)
+
+    def publishTraverse(self, request, name):
+        ob = self.target
+        try:
+            return getRequestView(ob, name, request)
+        except ComponentLookupError:
+            raise NotFound(ob, name)
+
 
-        # if ob is not a component return 
-        if not hasattr(ob, '__implements__'):
-            return ob,()
+
+class HTMLContentTraverser(SimpleComponentTraverser):
+    """Browser traverser for HTML content.
+
+    HTML content is content that authors expect to be used like simple
+    HTML pages. In particular, for the default view, URLs should be
+    relative to the container containing the content. 
+    """
+
+    def browserDefault(self, request):
+        ob = self.target
         
         view_name = getRequestDefaultViewName(ob, request)
+        view = self.publishTraverse(request, view_name)
+        if hasattr(view, 'browserDefault'):
+            view, path = view.browserDefault(request)
+            if len(path) == 1:
+                view = view.publishTraverse(request, path[0])
+                path = ()
+        else:
+            path = ()
+                
+        return view, path
 
-        view_uri = "%s;view" % view_name
-        return ob, (view_uri,)
+class TestTraverser:
+    "Bobo-style traverser, mostly useful for testing" 
+
+    __implements__ = IBrowserPublisher
+
+    def __init__(self, target):
+        self.target = target
+
+    def browserDefault(self, request):
+        ob = self.target
+
+        if hasattr(ob, '__implements__'):
+        
+            view_name = getRequestDefaultViewName(ob, request)
+
+            return ob, (("%s;view" % view_name),)
+        
+        return ob, ()
 
     def publishTraverse(self, request, name):
-        """ """
-        # TODO:  Look for default view
         ob = self.target
-        if name.startswith('_'):
-            raise Unauthorized("Name %s begins with an underscore" % `name`)
         if name.endswith(';view'):
             return getRequestView( ob, name[:-5], request)
+            
+        if name.startswith('_'):
+            raise Unauthorized("Name %s begins with an underscore" % `name`)
 
         subob = getattr(ob, name, self) # self is marker here
         if subob is self:
@@ -57,4 +101,3 @@
                 raise NotFound(ob, name, request)
 
         return subob
-


=== Zope3/lib/python/Zope/App/ZopePublication/zopepublication.zcml 1.1.2.4 => 1.1.2.5 ===
 
 <browser:view name="_traverse" 
- factory="Zope.App.ZopePublication.Traversers.DefaultTraverser." />
+ for="Interface.Interface"
+ factory="Zope.App.ZopePublication.Traversers.SimpleComponentTraverser" />
+
+<browser:view name="_traverse" 
+ for="Zope.App.OFS.Content.IHTMLContent."
+ factory="Zope.App.ZopePublication.Traversers.HTMLContentTraverser" />
 
   <xmlrpc:view name="_traverse" 
-   factory=".Traversers.DefaultTraverser." />
+   for="Interface.Interface"
+   factory=".Traversers.SimpleComponentTraverser." />
 
 <include package=".AbsoluteURL" file="config.zcml" />