[Checkins] SVN: zope.traversing/trunk/src/zope/traversing/ Moved the publicationtraverse module from zope.app.publication and added tests.
Shane Hathaway
shane at hathawaymix.org
Fri May 22 20:35:47 EDT 2009
Log message for revision 100262:
Moved the publicationtraverse module from zope.app.publication and added tests.
Changed:
A zope.traversing/trunk/src/zope/traversing/publicationtraverse.py
A zope.traversing/trunk/src/zope/traversing/tests/test_publicationtraverse.py
-=-
Added: zope.traversing/trunk/src/zope/traversing/publicationtraverse.py
===================================================================
--- zope.traversing/trunk/src/zope/traversing/publicationtraverse.py (rev 0)
+++ zope.traversing/trunk/src/zope/traversing/publicationtraverse.py 2009-05-23 00:35:46 UTC (rev 100262)
@@ -0,0 +1,129 @@
+##############################################################################
+#
+# 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.1 (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.
+#
+##############################################################################
+"""Publication Traverser
+
+$Id: publicationtraverse.py 67630 2006-04-27 00:54:03Z jim $
+"""
+__docformat__ = 'restructuredtext'
+from types import StringTypes
+
+from zope.component import queryMultiAdapter
+from zope.publisher.interfaces import NotFound
+from zope.security.checker import ProxyFactory
+from zope.traversing.namespace import namespaceLookup
+from zope.traversing.namespace import nsParse
+from zope.traversing.interfaces import TraversalError
+from zope.publisher.interfaces import IPublishTraverse
+from zope.publisher.interfaces.browser import IBrowserPublisher
+
+class DuplicateNamespaces(Exception):
+ """More than one namespace was specified in a request"""
+
+class UnknownNamespace(Exception):
+ """A parameter specified an unknown namespace"""
+
+class PublicationTraverser(object):
+ """Traversal used for publication.
+
+ The significant differences from
+ zope.traversing.adapters.traversePathElement() are:
+
+ - Instead of adapting each traversed object to ITraversable, this
+ version multi-adapts (ob, request) to IPublishTraverse.
+
+ - This version wraps a security proxy around each traversed object.
+
+ - This version raises NotFound rather than LocationError.
+
+ - This version has a method, traverseRelativeURL(), that
+ supports "browserDefault" traversal.
+ """
+
+ def traverseName(self, request, ob, name):
+ nm = name # the name to look up the object with
+
+ if name and name[:1] in '@+':
+ # Process URI segment parameters.
+ ns, nm = nsParse(name)
+ if ns:
+ try:
+ ob2 = namespaceLookup(ns, nm, ob, request)
+ except TraversalError:
+ raise NotFound(ob, name)
+
+ return ProxyFactory(ob2)
+
+ if nm == '.':
+ return ob
+
+ if IPublishTraverse.providedBy(ob):
+ ob2 = ob.publishTraverse(request, nm)
+ else:
+ # self is marker
+ adapter = queryMultiAdapter((ob, request), IPublishTraverse,
+ default=self)
+ if adapter is not self:
+ ob2 = adapter.publishTraverse(request, nm)
+ else:
+ raise NotFound(ob, name, request)
+
+ return ProxyFactory(ob2)
+
+ def traversePath(self, request, ob, path):
+
+ if isinstance(path, StringTypes):
+ path = path.split('/')
+ if len(path) > 1 and not path[-1]:
+ # Remove trailing slash
+ path.pop()
+ else:
+ path = list(path)
+
+ # Remove single dots
+ path = [x for x in path if x != '.']
+
+ path.reverse()
+
+ # Remove double dots
+ while '..' in path:
+ l = path.index('..')
+ if l < 0 or l+2 > len(path):
+ break
+ del path[l:l+2]
+
+ pop = path.pop
+
+ while path:
+ name = pop()
+ ob = self.traverseName(request, ob, name)
+
+ return ob
+
+ def traverseRelativeURL(self, request, ob, path):
+ """Path traversal that includes browserDefault paths"""
+ ob = self.traversePath(request, ob, path)
+
+ while True:
+ adapter = IBrowserPublisher(ob, None)
+ if adapter is None:
+ return ob
+ ob, path = adapter.browserDefault(request)
+ ob = ProxyFactory(ob)
+ if not path:
+ return ob
+
+ ob = self.traversePath(request, ob, path)
+
+# alternate spelling
+PublicationTraverse = PublicationTraverser
Added: zope.traversing/trunk/src/zope/traversing/tests/test_publicationtraverse.py
===================================================================
--- zope.traversing/trunk/src/zope/traversing/tests/test_publicationtraverse.py (rev 0)
+++ zope.traversing/trunk/src/zope/traversing/tests/test_publicationtraverse.py 2009-05-23 00:35:46 UTC (rev 100262)
@@ -0,0 +1,183 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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.
+#
+##############################################################################
+"""Tests of PublicationTraverser
+
+$Id: test_vh.py 82003 2007-11-28 08:49:12Z jukart $
+"""
+from unittest import TestCase, main, makeSuite
+from zope.testing.cleanup import CleanUp
+from zope.component import provideAdapter
+from zope.interface import Interface, implements
+from zope.publisher.browser import TestRequest
+from zope.publisher.interfaces import IPublishTraverse
+from zope.publisher.interfaces import NotFound
+from zope.publisher.interfaces.browser import IBrowserPublisher
+from zope.security.proxy import removeSecurityProxy
+from zope.traversing.interfaces import ITraversable
+
+class TestPublicationTraverser(CleanUp, TestCase):
+
+ def testViewNotFound(self):
+ ob = Content()
+ from zope.traversing.publicationtraverse import PublicationTraverser
+ t = PublicationTraverser()
+ request = TestRequest()
+ self.assertRaises(NotFound, t.traverseName, request, ob, '@@foo')
+
+ def testViewFound(self):
+ provideAdapter(DummyViewTraverser, (Interface, Interface),
+ ITraversable, name='view')
+ ob = Content()
+ from zope.traversing.publicationtraverse import PublicationTraverser
+ t = PublicationTraverser()
+ request = TestRequest()
+ proxy = t.traverseName(request, ob, '@@foo')
+ view = removeSecurityProxy(proxy)
+ self.assertTrue(proxy is not view)
+ self.assertEqual(view.__class__, View)
+ self.assertEqual(view.name, 'foo')
+
+ def testDot(self):
+ ob = Content()
+ from zope.traversing.publicationtraverse import PublicationTraverser
+ t = PublicationTraverser()
+ request = TestRequest()
+ self.assertEqual(ob, t.traverseName(request, ob, '.'))
+
+ def testNameNotFound(self):
+ ob = Content()
+ from zope.traversing.publicationtraverse import PublicationTraverser
+ t = PublicationTraverser()
+ request = TestRequest()
+ self.assertRaises(NotFound, t.traverseName, request, ob, 'foo')
+
+ def testNameFound(self):
+ provideAdapter(DummyPublishTraverse, (Interface, Interface),
+ IPublishTraverse)
+ ob = Content()
+ from zope.traversing.publicationtraverse import PublicationTraverser
+ t = PublicationTraverser()
+ request = TestRequest()
+ proxy = t.traverseName(request, ob, 'foo')
+ view = removeSecurityProxy(proxy)
+ self.assertTrue(proxy is not view)
+ self.assertEqual(view.__class__, View)
+ self.assertEqual(view.name, 'foo')
+
+ def testDirectTraversal(self):
+ request = TestRequest()
+ ob = DummyPublishTraverse(Content(), request)
+ from zope.traversing.publicationtraverse import PublicationTraverser
+ t = PublicationTraverser()
+ proxy = t.traverseName(request, ob, 'foo')
+ view = removeSecurityProxy(proxy)
+ self.assertTrue(proxy is not view)
+ self.assertEqual(view.__class__, View)
+ self.assertEqual(view.name, 'foo')
+
+ def testPathNotFound(self):
+ ob = Content()
+ from zope.traversing.publicationtraverse import PublicationTraverser
+ t = PublicationTraverser()
+ request = TestRequest()
+ self.assertRaises(NotFound, t.traversePath, request, ob, 'foo/bar')
+
+ def testPathFound(self):
+ provideAdapter(DummyPublishTraverse, (Interface, Interface),
+ IPublishTraverse)
+ ob = Content()
+ from zope.traversing.publicationtraverse import PublicationTraverser
+ t = PublicationTraverser()
+ request = TestRequest()
+ proxy = t.traversePath(request, ob, 'foo/bar')
+ view = removeSecurityProxy(proxy)
+ self.assertTrue(proxy is not view)
+ self.assertEqual(view.__class__, View)
+ self.assertEqual(view.name, 'bar')
+
+ def testComplexPath(self):
+ provideAdapter(DummyPublishTraverse, (Interface, Interface),
+ IPublishTraverse)
+ ob = Content()
+ from zope.traversing.publicationtraverse import PublicationTraverser
+ t = PublicationTraverser()
+ request = TestRequest()
+ proxy = t.traversePath(request, ob, 'foo/../alpha//beta/./bar')
+ view = removeSecurityProxy(proxy)
+ self.assertTrue(proxy is not view)
+ self.assertEqual(view.__class__, View)
+ self.assertEqual(view.name, 'bar')
+
+ def testTraverseRelativeURL(self):
+ provideAdapter(DummyPublishTraverse, (Interface, Interface),
+ IPublishTraverse)
+ provideAdapter(DummyBrowserPublisher, (Interface,),
+ IBrowserPublisher)
+ ob = Content()
+ from zope.traversing.publicationtraverse import PublicationTraverser
+ t = PublicationTraverser()
+ request = TestRequest()
+ proxy = t.traverseRelativeURL(request, ob, 'foo/bar')
+ view = removeSecurityProxy(proxy)
+ self.assertTrue(proxy is not view)
+ self.assertEqual(view.__class__, View)
+ self.assertEqual(view.name, 'more')
+
+
+class IContent(Interface):
+ pass
+
+class Content(object):
+ implements(IContent)
+
+class View(object):
+ def __init__(self, name):
+ self.name = name
+
+class DummyViewTraverser(object):
+ implements(ITraversable)
+
+ def __init__(self, content, request):
+ self.content = content
+
+ def traverse(self, name, furtherPath):
+ return View(name)
+
+class DummyPublishTraverse(object):
+ implements(IPublishTraverse)
+
+ def __init__(self, context, request):
+ pass
+
+ def publishTraverse(self, request, name):
+ return View(name)
+
+class DummyBrowserPublisher(object):
+ implements(IBrowserPublisher)
+
+ def __init__(self, context):
+ self.context = removeSecurityProxy(context)
+
+ def browserDefault(self, request):
+ if self.context.name != 'more':
+ return self.context, ['more']
+ else:
+ return self.context, ()
+
+
+def test_suite():
+ return makeSuite(TestPublicationTraverser)
+
+if __name__ == '__main__':
+ unittest.main()
More information about the Checkins
mailing list