[Zope3-checkins] CVS: Zope3/src/zope/app/traversing - configure.zcml:1.13 namespace.py:1.29 meta.zcml:NONE metaconfigure.py:NONE metadirectives.py:NONE

Jim Fulton jim at zope.com
Sun Apr 18 12:01:07 EDT 2004


Update of /cvs-repository/Zope3/src/zope/app/traversing
In directory cvs.zope.org:/tmp/cvs-serv12900/src/zope/app/traversing

Modified Files:
	configure.zcml namespace.py 
Removed Files:
	meta.zcml metaconfigure.py metadirectives.py 
Log Message:
Changed way namespace handlers (handlers for traversing names of the
form "++namespace++name") are registered.  Now the are registered as
views and adapters.  When traversing a namespace-qualified view, a
request is sometimes provided.  When a request is provided, a view
will be used to traverse the name. Otherwise, an adapter is used.
handlers that don't care about the request are registered as both an
adapter and a view.

With this change, it's not possible to have content-specific
namespace-specific traversers.  Content objects can now define
specialized namespaces.


=== Zope3/src/zope/app/traversing/configure.zcml 1.12 => 1.13 ===
--- Zope3/src/zope/app/traversing/configure.zcml:1.12	Sat Mar 13 16:03:23 2004
+++ Zope3/src/zope/app/traversing/configure.zcml	Sun Apr 18 12:00:33 2004
@@ -15,40 +15,92 @@
     for="zope.app.traversing.interfaces.IContainmentRoot"
     factory="zope.app.traversing.adapters.RootPhysicallyLocatable" />
 
-<traversalNamespace
+<adapter
     name="etc"
-    handler="zope.app.traversing.namespace.etc" />
-
-<traversalNamespace
-    name="view"
-    handler="zope.app.traversing.namespace.view" />
-
-<traversalNamespace
-    name="resource"
-    handler="zope.app.traversing.namespace.resource" />
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.etc" 
+    />
+<view
+    name="etc"
+    type="zope.interface.Interface"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.etc" 
+    />
 
-<traversalNamespace
+<adapter
     name="attribute"
-    handler="zope.app.traversing.namespace.attr" />
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.attr" 
+    />
+<view
+    name="attribute"
+    type="zope.interface.Interface"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.attr" 
+    />
 
-<traversalNamespace
+<adapter
+    name="item"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.item" 
+    />
+<view
     name="item"
-    handler="zope.app.traversing.namespace.item" />
+    type="zope.interface.Interface"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.item" 
+    />
 
-<traversalNamespace
+<adapter
     name="acquire"
-    handler="zope.app.traversing.namespace.acquire" />
-
-<traversalNamespace
-    name="skin"
-    handler="zope.app.traversing.namespace.skin" />
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.acquire" 
+    />
+<view
+    name="acquire"
+    type="zope.interface.Interface"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.acquire" 
+    />
 
-<traversalNamespace
+<adapter
+    name="help"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.help" 
+    />
+<view
     name="help"
-    handler="zope.app.traversing.namespace.help" />
+    type="zope.interface.Interface"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.help" 
+    />
+
+<view
+    name="view"
+    type="zope.interface.Interface"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.view" 
+    />
+
+<view
+    name="resource"
+    type="zope.interface.Interface"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.resource" 
+    />
+
+<view
+    name="skin"
+    type="zope.interface.Interface"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.skin" 
+    />
 
-<traversalNamespace
+<view
     name="vh"
-    handler="zope.app.traversing.namespace.vh" />
+    type="zope.interface.Interface"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.vh" 
+    />
 
 </configure>


=== Zope3/src/zope/app/traversing/namespace.py 1.28 => 1.29 ===
--- Zope3/src/zope/app/traversing/namespace.py:1.28	Sat Apr 17 13:15:34 2004
+++ Zope3/src/zope/app/traversing/namespace.py	Sun Apr 18 12:00:33 2004
@@ -16,6 +16,7 @@
 $Id$
 """
 import re
+import zope.interface
 from zope.app import zapi
 from zope.exceptions import NotFoundError
 from zope.app.traversing.interfaces import ITraversable
@@ -27,33 +28,80 @@
 class ExcessiveWrapping(NotFoundError):
     "Too many levels of acquisition wrapping. We don't believe them."
 
-class NoRequest(NotFoundError):
-    "Attempt to access a presentation component outside of a request context."
+def namespaceLookup(ns, name, object, request=None):
+    """Lookup a value from a namespace
 
+       We look up a value using a view or an adapter, depending on
+       whether a request is passed.
 
-_namespace_handlers = {}
+       Let's start with adapter-based transersal. We're going to use the
+       component architecture, so we'll need to initialize it:
 
-def provideNamespaceHandler(ns, handler):
-    _namespace_handlers[ns] = handler
+         >>> from zope.app.tests.placelesssetup import setUp, tearDown
+         >>> setUp()
 
-def namespaceLookup(ns, qname, object, request=None):
-    """Lookup a value from a namespace
+         >>> class I(zope.interface.Interface):
+         ...     'Test interface'
+         >>> class C:
+         ...     zope.interface.implements(I)
 
-    name -- the original name
-    ns -- The namespace
-    qname -- The name without the namespace
+       We'll register a simple testing adapter:
 
-    The resulting object is returned in the context of the original.
-    This means that the caller should *not* wrap the result.
-    """
+         >>> class Adapter:
+         ...     def __init__(self, context):
+         ...         self.context = context
+         ...     def traverse(self, name, remaining):
+         ...         return name+'42'
+
+         >>> from zope.app.tests import ztapi
+         >>> ztapi.provideAdapter(I, ITraversable, Adapter, 'foo')
+
+       Then given an object, we can traverse it with a
+       namespace-qualified name:
+
+         >>> namespaceLookup('foo', 'bar', C())
+         'bar42'
+
+       If we give an invalid namespace, we'll get a not found error:
+
+         >>> namespaceLookup('fiz', 'bar', C())
+         Traceback (most recent call last):
+         ...
+         NotFoundError: ++fiz++bar
+
+       We'll get the same thing if we provide a request:
+
+         >>> from zope.publisher.browser import TestRequest
+         >>> request = TestRequest()
+         >>> namespaceLookup('foo', 'bar', C(), request)
+         Traceback (most recent call last):
+         ...
+         NotFoundError: ++foo++bar
+
+       We need to provide a view:
 
-    handler = _namespace_handlers.get(ns)
-    if handler is None:
-        raise NotFoundError(name)
+         >>> class View:
+         ...     def __init__(self, context, request):
+         ...         pass
+         ...     def traverse(self, name, remaining):
+         ...         return name+'fromview'
+         >>> ztapi.browserView(I, 'foo', View, providing=ITraversable)
 
-    new = handler(qname, object, request)
+         >>> namespaceLookup('foo', 'bar', C(), request)
+         'barfromview'
 
-    return new
+         >>> tearDown()
+       """
+
+    if request is not None:
+        traverser = zapi.queryView(object, ns, request, providing=ITraversable)
+    else:
+        traverser = zapi.queryNamedAdapter(object, ITraversable, ns)
+
+    if traverser is None:
+        raise NotFoundError("++%s++%s" % (ns, name))
+
+    return traverser.traverse(name, ())
 
 
 namespace_pattern = re.compile('[+][+]([a-zA-Z0-9_]+)[+][+]')
@@ -125,122 +173,222 @@
 
 # ---- namespace processors below ----
 
-def acquire(name, ob, request):
-    i = 0
-    origOb = ob
-    while i < 200:
-        i += 1
-        traversable = ITraversable(ob, None)
-        if traversable is not None:
+class SimpleHandler(object):
 
-            try:
-                # XXX what do we do if the path gets bigger?
-                path = []
-                next = traversable.traverse(name, path)
-                if path:
-                    continue
-            except NotFoundError:
-                pass
-            else:
-                return next
-
-        ob = getattr(ob, '__parent__', None)
-        if ob is None:
-            raise NotFoundError(origOb, name)
+    zope.interface.implements(ITraversable)
+    
+    def __init__(self, context, request=None):
+        """Simple hadlers can be usd as adapters or views
 
-    raise ExcessiveWrapping(origOb, name)
+           The ignore their second constructor arg and store the first
+           one in their context attr:
 
-def attr(name, ob, request):
-    return getattr(ob, name)
+              >>> SimpleHandler(42).context
+              42
+              
+              >>> SimpleHandler(42, 43).context
+              42
+           """
+        self.context = context
 
-def item(name, ob, request):
-    return ob[name]
+class acquire(SimpleHandler):
+    """Traversal adapter for the acquire namespace
+    """
+
+    def traverse(self, name, remaining):
+        """Acquire a name
+
+           Let's set up some example data:
+
+             >>> class testcontent:
+             ...     zope.interface.implements(ITraversable)
+             ...     def traverse(self, name, remaining):
+             ...         v = getattr(self, name, None)
+             ...         if v is None:
+             ...             raise NotFoundError(name)
+             ...         return v
+             ...     def __repr__(self):
+             ...         return 'splat'
+
+             >>> ob = testcontent()
+             >>> ob.a = 1
+             >>> ob.__parent__ = testcontent()
+             >>> ob.__parent__.b = 2
+             >>> ob.__parent__.__parent__ = testcontent()
+             >>> ob.__parent__.__parent__.c = 3
+
+           And acquire some names:
+
+             >>> adapter = acquire(ob)
+
+             >>> adapter.traverse('a', ())
+             1
+
+             >>> adapter.traverse('b', ())
+             2
+
+             >>> adapter.traverse('c', ())
+             3
+
+             >>> adapter.traverse('d', ())
+             Traceback (most recent call last):
+             ...
+             NotFoundError: (splat, 'd')
+           """
+        i = 0
+        ob = self.context
+        while i < 200:
+            i += 1
+            traversable = ITraversable(ob, None)
+            if traversable is not None:
+                try:
+                    # XXX what do we do if the path gets bigger?
+                    path = []
+                    next = traversable.traverse(name, path)
+                    if path:
+                        continue
+                except NotFoundError:
+                    pass
+                else:
+                    return next
+
+            ob = getattr(ob, '__parent__', None)
+            if ob is None:
+                raise NotFoundError(self.context, name)
+
+        raise ExcessiveWrapping(self.context, name)
+
+class attr(SimpleHandler):
+
+    def traverse(self, name, ignored):
+        """Attribute traversal adapter
+
+           This adapter just provides traversal to attributes:
+
+              >>> ob = {'x': 1}
+              >>> adapter = attr(ob)
+              >>> adapter.traverse('keys', ())()
+              ['x']
+              
+           """
+        return getattr(self.context, name)
+
+class item(SimpleHandler):
+
+    def traverse(self, name, ignored):
+        """Item traversal adapter
+
+           This adapter just provides traversal to items:
+
+              >>> ob = {'x': 42}
+              >>> adapter = item(ob)
+              >>> adapter.traverse('x', ())
+              42
+           """
+        return self.context[name]
 
 from zope.app.applicationcontrol.applicationcontrol \
-    import applicationController
+     import applicationController
 from zope.app.traversing.interfaces import IContainmentRoot
-def etc(name, ob, request):
-    # 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 in ('process', 'ApplicationController')
-        and IContainmentRoot.providedBy(ob)):
-        return applicationController
-
-    if name not in ('site', 'Services'):
-        raise NotFoundError(ob, name, request)
-
-    method_name = "getSiteManager"
-    method = getattr(ob, method_name, None)
-    if method is None:
-        raise NotFoundError(ob, name, request)
-
-    return method()
-
-def help(name, ob, request):
-    """Used to traverse to an online help topic."""
-    return zapi.getService(ob, 'OnlineHelp')
-
-def view(name, ob, request):
-    if not request:
-        raise NoRequest(pname)
-    view = zapi.queryView(ob, name, request)
-    if view is None:
-        raise NotFoundError(ob, name)
+class etc(SimpleHandler):
+    
+    def traverse(self, name, ignored):
+        # XXX
 
-    return view
+        # 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.
 
-def resource(name, ob, request):
-    if not request:
-        raise NoRequest(pname)
+        ob = self.context
 
-    resource = queryResourceInContext(ob, name, request)
-    if resource is None:
-        raise NotFoundError(ob, name)
+        if (name in ('process', 'ApplicationController')
+            and IContainmentRoot.providedBy(ob)):
+            return applicationController
 
-    return resource
+        if name not in ('site', 'Services'):
+            raise NotFoundError(ob, name)
 
-def skin(name, ob, request):
-    if not request:
-        raise NoRequest(pname)
+        method_name = "getSiteManager"
+        method = getattr(ob, method_name, None)
+        if method is None:
+            raise NotFoundError(ob, name)
 
-    request.shiftNameToApplication()
-    request.setPresentationSkin(name)
+        return method()
 
-    return ob
+class help(SimpleHandler):
 
-def vh(name, ob, request):
+    def traverse(self, name, ignored):
+        """Used to traverse to an online help topic."""
+        return zapi.getService(self.context, 'OnlineHelp')
 
-    traversal_stack = request.getTraversalStack()
-    app_names = []
+class view(object):
 
-    if name:
-        try:
-            proto, host, port = name.split(":")
-        except ValueError:
-            raise ValueError("Vhost directive should have the form "
-                             "++vh++protocol:host:port")
+    zope.interface.implements(ITraversable)
+    
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+    
+    def traverse(self, name, ignored):
+        view = zapi.queryView(self.context, name, self.request)
+        if view is None:
+            raise NotFoundError(self.context, name)
+
+        return view
+
+class resource(view):
 
-        request.setApplicationServer(host, proto, port)
+    def traverse(self, name, ignored):
+        resource = queryResourceInContext(self.context, name, self.request)
+        if resource is None:
+            raise NotFoundError(self.context, name)
 
-    if '++' in traversal_stack:
-        segment = traversal_stack.pop()
-        while segment != '++':
-            app_names.append(segment)
+        return resource
+
+class skin(view):
+    
+    def traverse(self, name, ignored):
+        self.request.shiftNameToApplication()
+        self.request.setPresentationSkin(name)
+
+        return self.context
+
+class vh(view):
+    
+    def traverse(self, name, ignored):
+
+        request = self.request
+        
+        traversal_stack = request.getTraversalStack()
+        app_names = []
+
+        if name:
+            try:
+                proto, host, port = name.split(":")
+            except ValueError:
+                raise ValueError("Vhost directive should have the form "
+                                 "++vh++protocol:host:port")
+
+            request.setApplicationServer(host, proto, port)
+
+        if '++' in traversal_stack:
             segment = traversal_stack.pop()
-        request.setTraversalStack(traversal_stack)
-    else:
-        raise ValueError("Must have a path element '++' after a virtual host "
-                         "directive.")
+            while segment != '++':
+                app_names.append(segment)
+                segment = traversal_stack.pop()
+            request.setTraversalStack(traversal_stack)
+        else:
+            raise ValueError(
+                "Must have a path element '++' after a virtual host "
+                "directive.")
+
+        request.setVirtualHostRoot(app_names)
 
-    request.setVirtualHostRoot(app_names)
-    return ob
+        return self.context

=== Removed File Zope3/src/zope/app/traversing/meta.zcml ===

=== Removed File Zope3/src/zope/app/traversing/metaconfigure.py ===

=== Removed File Zope3/src/zope/app/traversing/metadirectives.py ===




More information about the Zope3-Checkins mailing list