[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