[Zope3-checkins] CVS: Zope3/src/zope/app/traversing - __init__.py:1.2 acquirenamespace.py:1.2 attritemnamespaces.py:1.2 configure.zcml:1.2 defaulttraversable.py:1.2 etcnamespace.py:1.2 exceptions.py:1.2 getresource.py:1.2 meta.zcml:1.2 modulenamespace.py:1.2 namespaces.py:1.2 objectname.py:1.2 parameterparsing.py:1.2 physicallocationadapters.py:1.2 presentationnamespaces.py:1.2 skinnamespace.py:1.2 traverser.py:1.2

Jim Fulton jim@zope.com
Wed, 25 Dec 2002 09:13:59 -0500


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

Added Files:
	__init__.py acquirenamespace.py attritemnamespaces.py 
	configure.zcml defaulttraversable.py etcnamespace.py 
	exceptions.py getresource.py meta.zcml modulenamespace.py 
	namespaces.py objectname.py parameterparsing.py 
	physicallocationadapters.py presentationnamespaces.py 
	skinnamespace.py traverser.py 
Log Message:
Grand renaming:

- Renamed most files (especially python modules) to lower case.

- Moved views and interfaces into separate hierarchies within each
  project, where each top-level directory under the zope package
  is a separate project.

- Moved everything to src from lib/python.

  lib/python will eventually go away. I need access to the cvs
  repository to make this happen, however.

There are probably some bits that are broken. All tests pass
and zope runs, but I haven't tried everything. There are a number
of cleanups I'll work on tomorrow.



=== Zope3/src/zope/app/traversing/__init__.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:57 2002
+++ Zope3/src/zope/app/traversing/__init__.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,171 @@
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+Traversing the object tree.
+"""
+# being careful not to pollute the namespace unnecessarily...
+from zope.component import getAdapter as _getAdapter
+from objectname import IObjectName as _IObjectName
+from zope.app.interfaces.traversing.traverser import ITraverser as _ITraverser
+from zope.app.interfaces.traversing.physicallylocatable \
+     import IPhysicallyLocatable as _IPhysicallyLocatable
+from traverser import WrapperChain as _WrapperChain
+from traverser import Traverser as _Traverser
+from zope.proxy.context import getWrapperContext as _getWrapperContext
+from zope.proxy.context import isWrapper as _isWrapper
+from types import StringTypes
+_marker = object()
+
+# XXX: this probably shouldn't have "request" in its signature, nor
+#      in the arguments of the call to traverser.traverse
+def traverse(place, path, default=_marker, request=None):
+    """Traverse 'path' relative to 'place'
+
+    'path' can be a string with path segments separated by '/'
+    or a sequence of path segments.
+
+    Raises NotFoundError if path cannot be found
+    Raises TypeError if place is not context wrapped
+
+    Note: calling traverse with a path argument taken from an untrusted
+          source, such as an HTTP request form variable, is a bad idea.
+          It could allow a maliciously constructed request to call
+          code unexpectedly.
+          Consider using traverseName instead.
+    """
+    traverser = _Traverser(place)
+    if default is _marker:
+        return traverser.traverse(path, request=request)
+    else:
+        return traverser.traverse(path, default=default, request=request)
+
+# XXX This should have an additional optional argument where you
+#     can pass an ITraversable to use, otherwise it should get
+#     an adapter for ITraversable from the object and use that to
+#     traverse one step.
+def traverseName(obj, name, default=_marker):
+    """Traverse a single step 'name' relative to 'place'
+
+    'name' must be a string. 'name' will be treated as a single
+    path segment, no matter what characters it contains.
+
+    Raises NotFoundError if path cannot be found
+    Raises TypeError if place is not context wrapped
+    """
+    # by passing [name] to traverse (above), we ensure that name is
+    # treated as a single path segment, regardless of any '/' characters
+    return traverse(obj, [name], default=default)
+
+
+def objectName(obj):
+    """Get the name an object was traversed via
+
+    Raises TypeError if the object is not context-wrapped
+    """
+    return _getAdapter(obj, _IObjectName)()
+
+def getParent(obj):
+    """Returns the container the object was traversed via.
+
+    Raises TypeError if the given object is not context wrapped
+    """
+    if not _isWrapper(obj):
+        raise TypeError, "Not enough context information to traverse"
+    return _getWrapperContext(obj)
+
+def getParents(obj):
+    """Returns a list starting with the given object's parent followed by
+    each of its parents.
+
+    Raises TypeError if the given object is not context wrapped
+    """
+    if not _isWrapper(obj):
+        raise TypeError, "Not enough context information to traverse"
+    iterator = _WrapperChain(obj)
+    iterator.next()  # send head of chain (current object) to /dev/null
+    return [p for p in iterator]
+
+def getPhysicalPath(obj):
+    """Returns a tuple of names representing the physical path to the object.
+
+    Raises TypeError if the given object is not context wrapped
+    """
+    return _getAdapter(obj, _IPhysicallyLocatable).getPhysicalPath()
+
+def getPhysicalPathString(obj):
+    """Returns a string representing the physical path to the object.
+
+    Raises TypeError if the given object is not context wrapped
+    """
+    path = _getAdapter(obj, _IPhysicallyLocatable).getPhysicalPath()
+    return locationAsUnicode(path)
+
+
+def getPhysicalRoot(obj):
+    """Returns the root of the traversal for the given object.
+
+    Raises TypeError if the given object is not context wrapped
+    """
+    return _getAdapter(obj, _IPhysicallyLocatable).getPhysicalRoot()
+
+def locationAsTuple(location):
+    """Given a location as a unicode or ascii string or as a tuple of
+    unicode or ascii strings, returns the location as a tuple of
+    unicode strings.
+
+    Raises a ValueError if a poorly formed location is given.
+    """
+    if not location:
+        raise ValueError, "location must be non-empty: %s" % repr(location)
+    if isinstance(location, StringTypes):
+        if location == u'/':  # matches '/' or u'/'
+            return (u'',)
+        t = tuple(location.split(u'/'))
+    elif location.__class__ == tuple:
+        # isinstance doesn't work when tuple is security-wrapped
+        t = tuple(map(unicode, location))
+    else:
+        raise ValueError, \
+            "location %s must be a string or a tuple of strings." % (location,)
+
+    if len(t) > 1 and t[-1] == u'':  # matches '' or u''
+        raise ValueError, \
+            "location tuple %s must not end with empty string." % (t,)
+    # don't usually need this, so just an assertion rather than a value error
+    assert '' not in t[1:]
+    return t
+
+def locationAsUnicode(location):
+    """Given a location as a unicode or ascii string or as a tuple of
+    unicode or ascii strings, returns the location as a slash-separated
+    unicode string.
+
+    Raises ValueError if a poorly formed location is given.
+    """
+    if not location:
+        raise ValueError, "location must be non-empty."
+    if isinstance(location, StringTypes):
+        u = unicode(location)
+    elif location.__class__ == tuple:
+        # isinstance doesn't work when tuple is security-wrapped
+        u = u'/'.join(location)
+        if not u:  # special case for u''
+            return u'/'
+    else:
+        raise ValueError, \
+            "location %s must be a string or a tuple of strings." % (location,)
+    if u != '/' and u[-1] == u'/':
+        raise ValueError, "location %s must not end with a slash." % u
+    # don't usually need this, so just an assertion rather than a value error
+    assert u.find(u'//') == -1
+    return u


=== Zope3/src/zope/app/traversing/acquirenamespace.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:57 2002
+++ Zope3/src/zope/app/traversing/acquirenamespace.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,54 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.app.traversing.namespaces import provideNamespaceHandler
+from zope.app.traversing.exceptions import UnexpectedParameters
+from zope.exceptions import NotFoundError
+from zope.component import queryAdapter
+from zope.proxy.context import ContextWrapper, getWrapperContext
+from zope.app.interfaces.traversing.traversable import ITraversable
+
+class ExcessiveWrapping(NotFoundError):
+    """Too many levels of acquisition wrapping. We don't believe them."""
+
+def acquire(name, parameters, pname, ob, request):
+    if parameters:
+        raise UnexpectedParameters(parameters)
+
+    i = 0
+    origOb = ob
+    while i < 200:
+        i += 1
+        traversable = queryAdapter(ob, ITraversable, None)
+        if traversable is not None:
+
+            try:
+                # XXX what do we do if the path gets bigger?
+                path = []
+                next = traversable.traverse(name, parameters, pname, path)
+                if path: continue
+            except NotFoundError:
+                pass
+            else:
+                return ContextWrapper(next, ob, name=name)
+
+        ob = getWrapperContext(ob)
+        if ob is None:
+            raise NotFoundError(origOb, pname)
+
+    raise ExcessiveWrapping(origOb, pname)


=== Zope3/src/zope/app/traversing/attritemnamespaces.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:57 2002
+++ Zope3/src/zope/app/traversing/attritemnamespaces.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,30 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.app.traversing.namespaces import provideNamespaceHandler
+from zope.app.traversing.exceptions import UnexpectedParameters
+
+def attr(name, parameters, pname, ob, request):
+    if parameters:
+        raise UnexpectedParameters(parameters)
+    return getattr(ob, name)
+
+def item(name, parameters, pname, ob, request):
+    if parameters:
+        raise UnexpectedParameters(parameters)
+    return ob[name]


=== Zope3/src/zope/app/traversing/configure.zcml 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:57 2002
+++ Zope3/src/zope/app/traversing/configure.zcml	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,49 @@
+<zopeConfigure
+   xmlns='http://namespaces.zope.org/zope'
+   xmlns:browser='http://namespaces.zope.org/browser'
+>
+
+<adapter factory="zope.app.traversing.traverser.Traverser"
+         provides="zope.app.interfaces.traversing.traverser.ITraverser"
+         />
+    <!-- Ultimately, this should be registered only for IWrapper, but that
+         won't work like that just now.
+         for="zope.proxy.interfaces.context.IWrapper" /> -->
+
+<adapter factory="zope.app.traversing.defaulttraversable.DefaultTraversable"
+         provides="zope.app.interfaces.traversing.traversable.ITraversable" />
+
+<adapter
+    factory="zope.app.traversing.objectname.ObjectName"
+    provides="zope.app.traversing.objectname.IObjectName"
+    permission='zope.Public'
+    />
+
+<adapter
+    factory="zope.app.traversing.objectname.SiteObjectName"
+    provides="zope.app.traversing.objectname.IObjectName"
+    for="zope.app.interfaces.content.folder.IRootFolder"
+    permission='zope.Public'
+    />
+
+<adapter 
+    provides="zope.app.interfaces.traversing.physicallylocatable.IPhysicallyLocatable"
+    factory="zope.app.traversing.physicallocationadapters.WrapperPhysicallyLocatable" 
+    />
+
+<adapter 
+    provides="zope.app.interfaces.traversing.physicallylocatable.IPhysicallyLocatable"
+    for="zope.app.interfaces.traversing.containmentroot.IContainmentRoot"
+    factory="zope.app.traversing.physicallocationadapters.RootPhysicallyLocatable" 
+    />
+
+<traversalNamespace name="etc" handler="zope.app.traversing.etcnamespace.etc" />
+<traversalNamespace name="view" handler="zope.app.traversing.presentationnamespaces.view" />
+<traversalNamespace name="resource"
+                    handler="zope.app.traversing.presentationnamespaces.resource" />
+<traversalNamespace name="attribute" handler="zope.app.traversing.attritemnamespaces.attr" />
+<traversalNamespace name="item" handler="zope.app.traversing.attritemnamespaces.item" />
+<traversalNamespace name="acquire" handler="zope.app.traversing.acquirenamespace.acquire" />
+<traversalNamespace name="skin" handler="zope.app.traversing.skinnamespace.skin" />
+<traversalNamespace name="module" handler="zope.app.traversing.modulenamespace.module" />
+</zopeConfigure>


=== Zope3/src/zope/app/traversing/defaulttraversable.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:58 2002
+++ Zope3/src/zope/app/traversing/defaulttraversable.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,39 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+from zope.app.interfaces.traversing.traversable import ITraversable
+from zope.exceptions import NotFoundError
+from zope.app.traversing.exceptions import UnexpectedParameters
+
+_marker = object()  # opaque marker that doesn't get security proxied
+class DefaultTraversable:
+    """Traverses objects via attribute and item lookup"""
+
+    __implements__ = ITraversable
+
+    def __init__(self, subject):
+        self._subject = subject
+
+    def traverse(self, name, parameters, pname, furtherPath):
+        if parameters:
+            raise UnexpectedParameters(parameters)
+        subject = self._subject
+        r = getattr(subject, name, _marker)
+        if r is not _marker:
+            return r
+
+        if hasattr(subject, '__getitem__'):
+            # Let exceptions propagate.
+            return self._subject[name]
+        else:
+            raise NotFoundError(self._subject, name)


=== Zope3/src/zope/app/traversing/etcnamespace.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:58 2002
+++ Zope3/src/zope/app/traversing/etcnamespace.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,54 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+from zope.app.applicationcontrol.applicationcontrol \
+     import applicationController
+from zope.app.traversing.namespaces import provideNamespaceHandler
+from zope.app.traversing.exceptions import UnexpectedParameters
+from zope.exceptions import NotFoundError
+
+from zope.app.content.folder import RootFolder
+
+def etc(name, parameters, pname, 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 parameters:
+        raise UnexpectedParameters(parameters)
+
+    if name == 'ApplicationController' and ob.__class__ == RootFolder:
+        return applicationController
+
+    if name != 'Services':
+
+        raise NotFoundError(ob, pname, request)
+
+    method_name = "getServiceManager"
+    method = getattr(ob, method_name, None)
+    if method is None:
+        raise NotFoundError(ob, pname, request)
+
+    return method()


=== Zope3/src/zope/app/traversing/exceptions.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:58 2002
+++ Zope3/src/zope/app/traversing/exceptions.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,22 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+from zope.exceptions import NotFoundError
+
+class UnexpectedParameters(NotFoundError):
+    """Unexpected namespace parameters were provided.
+    """


=== Zope3/src/zope/app/traversing/getresource.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:58 2002
+++ Zope3/src/zope/app/traversing/getresource.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,34 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.component import getService
+from zope.exceptions import NotFoundError
+from zope.proxy.context import ContextWrapper
+
+def getResource(ob, name, request):
+    resource = queryResource(ob, name, request)
+    if resource is None:
+        raise NotFoundError(ob, name)
+    return resource
+
+def queryResource(ob, name, request, default=None):
+    resource_service = getService(ob, 'Resources')
+    resource = resource_service.queryResource(ob, name, request)
+    if resource is None:
+        return default
+    return ContextWrapper(resource, resource_service, name=name)


=== Zope3/src/zope/app/traversing/meta.zcml 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:58 2002
+++ Zope3/src/zope/app/traversing/meta.zcml	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,10 @@
+<zopeConfigure xmlns='http://namespaces.zope.org/zope'>
+
+  <directives namespace="http://namespaces.zope.org/zope">
+
+    <directive name="traversalNamespace" attributes="name handler"
+       handler="zope.app.traversing.namespaces.directive" />
+
+  </directives>
+
+</zopeConfigure>


=== Zope3/src/zope/app/traversing/modulenamespace.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:58 2002
+++ Zope3/src/zope/app/traversing/modulenamespace.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,33 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.app.interfaces.services.service import INameResolver
+from zope.component import getServiceManager, getAdapter
+from zope.component import queryDefaultViewName
+from zope.interface import Interface
+
+
+def module(name, parameters, pname, ob, request):
+    """Used to traverse to a module (in dot notation)"""
+    servicemanager = getServiceManager(ob)
+    adapter = getAdapter(servicemanager, INameResolver)
+    if adapter is not None:
+        ob = adapter.resolve(name)
+    if queryDefaultViewName(ob, request) is None:
+        return Interface
+    return ob


=== Zope3/src/zope/app/traversing/namespaces.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:58 2002
+++ Zope3/src/zope/app/traversing/namespaces.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,74 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.exceptions import NotFoundError
+from zope.proxy.context import ContextWrapper, getWrapperObject
+from zope.configuration.action import Action
+
+_namespace_handlers = {}
+
+def provideNamespaceHandler(ns, handler):
+    _namespace_handlers[ns] = handler
+
+def directive(_context, name, handler):
+    handler = _context.resolve(handler)
+    return [Action(
+               discriminator=("traversalNamespace", name),
+               callable=provideNamespaceHandler,
+               args=(name, handler),
+               )]
+
+def namespaceLookup(name, ns, qname, parameters, object, request=None):
+    """Lookup a value from a namespace
+
+    name -- the original name
+    ns -- The namespace
+    qname -- The name without any parameters
+
+    The resulting object is returned in the context of the original.
+    This means that the caller should *not* wrap the result.
+    """
+
+    handler = _namespace_handlers.get(ns)
+    if handler is None:
+        raise NotFoundError(name)
+
+    new = handler(qname, parameters, name, object, request)
+    if new is object:
+        # The handler had a side effect only and didn't look up a
+        # different object.  We want to retain the side-effect name
+        # for things like URLs.
+
+        # But wait, there's more. The object may be wrapped. If the
+        # object is already wrapped and we return the object in the
+        # context of itself, the containment context will be wrong,
+        # because the inner wrapper will be the original object, so
+        # our added layer with the name we want to preserve will be
+        # ignored when searching containment.
+
+        # For this reason, we'll remove a layer of wrapping from new
+        # before we put it in context.
+
+        new = getWrapperObject(new)
+
+        new = ContextWrapper(new, object, name='.', side_effect_name=name)
+
+    else:
+        new = ContextWrapper(new, object, name=name)
+
+    return new


=== Zope3/src/zope/app/traversing/objectname.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:58 2002
+++ Zope3/src/zope/app/traversing/objectname.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,50 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+from zope.proxy.context import getInnerWrapperData
+from zope.app.interfaces.traversing.objectname import IObjectName
+
+class ObjectName(object):
+
+    __implements__ = IObjectName
+
+    def __init__(self, context):
+        self.context = context
+
+    def __str__(self):
+        dict = getInnerWrapperData(self.context)
+        name = dict and dict.get('name') or None
+        if name is None:
+            raise TypeError, \
+                  'Not enough context information to get an object name'
+        return name
+
+    __call__ = __str__
+
+
+class SiteObjectName(object):
+
+    __implements__ = IObjectName
+
+    def __init__(self, context):
+        pass
+
+    def __str__(self):
+        return ''
+
+    __call__ = __str__


=== Zope3/src/zope/app/traversing/parameterparsing.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:58 2002
+++ Zope3/src/zope/app/traversing/parameterparsing.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,46 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+import re
+
+namespace_pattern = re.compile('[+][+]([a-zA-Z0-9_]+)[+][+]')
+
+def parameterizedNameParse(name):
+    """Parse a name with parameters, including namespace parameters.
+
+    Return:
+
+    - namespace, or None if there isn't one.
+
+    - unparameterized name.
+
+    - sequence of parameters, as name-value pairs.
+    """
+
+    ns = ''
+    if name.startswith('@@'):
+        ns = 'view'
+        name = name[2:]
+    else:
+        match = namespace_pattern.match(name)
+        if match:
+            prefix, ns = match.group(0, 1)
+            name = name[len(prefix):]
+
+    return ns, name, ()


=== Zope3/src/zope/app/traversing/physicallocationadapters.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:58 2002
+++ Zope3/src/zope/app/traversing/physicallocationadapters.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""XXX short summary goes here.
+
+XXX longer description goes here.
+
+$Id$
+"""
+__metaclass__ = type
+
+from zope.app.interfaces.traversing.physicallylocatable import IPhysicallyLocatable
+from zope.app.interfaces.traversing.containmentroot import IContainmentRoot
+from zope.component import getAdapter
+from zope.proxy.context import getInnerWrapperData, getWrapperContainer
+
+class WrapperPhysicallyLocatable:
+    __doc__ = IPhysicallyLocatable.__doc__
+
+    __implements__ =  IPhysicallyLocatable
+
+    def __init__(self, context):
+        self.context = context
+
+    def getPhysicalRoot(self):
+        "See IPhysicallyLocatable"
+        container = getWrapperContainer(self.context)
+        if container is None:
+            raise TypeError("Not enough context to determine location root")
+        return getAdapter(container, IPhysicallyLocatable).getPhysicalRoot()
+
+    def getPhysicalPath(self):
+        "See IPhysicallyLocatable"
+        context = self.context
+        container = getWrapperContainer(context)
+        if container is None:
+            raise TypeError("Not enough context to determine location")
+        name = getInnerWrapperData(context)['name']
+
+        container = getAdapter(container, IPhysicallyLocatable)
+        container_path = container.getPhysicalPath()
+
+        if name == '.':
+            # skip
+            return container_path
+
+        return container_path + (name, )
+
+
+class RootPhysicallyLocatable:
+    __doc__ = IPhysicallyLocatable.__doc__
+
+    __implements__ =  IPhysicallyLocatable
+
+    __used_for__ = IContainmentRoot
+
+    def __init__(self, context):
+        self.context = context
+
+    def getPhysicalPath(self):
+        "See IPhysicallyLocatable"
+        return ('', )
+
+    def getPhysicalRoot(self):
+        "See IPhysicallyLocatable"
+        return self.context


=== Zope3/src/zope/app/traversing/presentationnamespaces.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:58 2002
+++ Zope3/src/zope/app/traversing/presentationnamespaces.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,47 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.component import getView
+from zope.app.traversing.namespaces import provideNamespaceHandler
+from zope.app.traversing.exceptions import UnexpectedParameters
+from zope.exceptions import NotFoundError
+from zope.proxy.context import ContextWrapper
+from zope.app.traversing.getresource import queryResource
+
+class NoRequest(NotFoundError):
+    """Atempt to access a presentation component outside of a request context
+    """
+
+def view(name, parameters, pname, ob, request):
+    if parameters:
+        raise UnexpectedParameters(parameters)
+    if not request:
+        raise NoRequest(pname)
+    return getView(ob, name, request)
+
+def resource(name, parameters, pname, ob, request):
+    if parameters:
+        raise UnexpectedParameters(parameters)
+    if not request:
+        raise NoRequest(pname)
+
+    resource = queryResource(ob, name, request)
+    if resource is None:
+        raise NotFoundError(ob, pname)
+
+    return resource


=== Zope3/src/zope/app/traversing/skinnamespace.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:58 2002
+++ Zope3/src/zope/app/traversing/skinnamespace.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,37 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from zope.app.traversing.namespaces import provideNamespaceHandler
+from zope.app.traversing.exceptions import UnexpectedParameters
+from zope.exceptions import NotFoundError
+
+class NoRequest(NotFoundError):
+    """Atempt to access a presentation component outside of a request context
+    """
+
+def skin(name, parameters, pname, ob, request):
+
+    if parameters:
+        raise UnexpectedParameters(parameters)
+
+    if not request:
+        raise NoRequest(pname)
+
+    request.setViewSkin(name)
+
+    return ob


=== Zope3/src/zope/app/traversing/traverser.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:59 2002
+++ Zope3/src/zope/app/traversing/traverser.py	Wed Dec 25 09:13:26 2002
@@ -0,0 +1,109 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Default implementation of ITraverser.
+
+$Id$
+"""
+
+from zope.component import getAdapter
+from zope.proxy.context import getWrapperContainer
+from zope.proxy.context import ContextWrapper
+from zope.component import queryAdapter
+from zope.exceptions import NotFoundError
+from zope.app.traversing.namespaces import namespaceLookup
+from zope.app.traversing.parameterparsing import parameterizedNameParse
+
+from zope.app.interfaces.traversing.physicallylocatable import IPhysicallyLocatable
+from zope.app.interfaces.traversing.traverser import ITraverser
+from zope.app.interfaces.traversing.traversable import ITraversable
+
+from types import StringTypes
+
+from __future__ import generators
+
+# A chain generator; let's us walk the wrapper chain down to the root
+def WrapperChain(w):
+    while w is not None:
+        yield w
+        w = getWrapperContainer(w)
+
+_marker = object()
+
+class Traverser:
+    """Provide traverse features"""
+
+    __implements__ = ITraverser
+
+    # This adapter can be used for any object.
+
+    def __init__(self, wrapper):
+        self.context = wrapper
+
+    def traverse(self, path, default=_marker, request=None):
+        if not path:
+            return self.context
+
+        if isinstance(path, StringTypes):
+            path = path.split('/')
+            if len(path) > 1 and not path[-1]:
+                # Remove trailing slash
+                path.pop()
+        else:
+            path = list(path)
+
+        path.reverse()
+        pop = path.pop
+
+        curr = self.context
+        if not path[-1]:
+            # Start at the root
+            pop()
+            curr = getAdapter(self.context, IPhysicallyLocatable
+                              ).getPhysicalRoot()
+        try:
+            while path:
+                name = pop()
+
+                if name == '.':
+                    continue
+
+                if name == '..':
+                    # XXX This doesn't look right. Why fall back to curr?
+                    curr = getWrapperContainer(curr) or curr
+                    continue
+
+
+                if name and name[:1] in '@+':
+                    ns, nm, parms = parameterizedNameParse(name)
+                    if ns:
+                        curr = namespaceLookup(name, ns, nm, parms,
+                                               curr, request)
+                        continue
+                else:
+                    parms = ()
+                    nm = name
+
+                traversable = queryAdapter(curr, ITraversable, None)
+                if traversable is None:
+                    raise NotFoundError(
+                        'No traversable adapter found', curr)
+
+                next = traversable.traverse(nm, parms, name, path)
+                curr = ContextWrapper(next, curr, name=name)
+
+            return curr
+        except NotFoundError:
+            if default == _marker:
+                raise
+            return default