[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