diff options
author | Jim Fulton <jim@zope.com> | 2002-07-13 14:18:37 +0000 |
---|---|---|
committer | Jim Fulton <jim@zope.com> | 2002-07-13 14:18:37 +0000 |
commit | 33cc9b96bc66a62ff8120b3ad6091d658ead52dd (patch) | |
tree | 819e7f437cf53528ad8037a142d7d44df1a246cb | |
parent | 15dd1d76d172b8c7782ba4c350e0892370d80881 (diff) | |
download | zope-traversing-33cc9b96bc66a62ff8120b3ad6091d658ead52dd.tar.gz |
Fixed bug in context management when uri segments that produce only
side effects (e.g. ++skin++ZopeTop) are used.
Fixed up absolute url bread crumbs to not show side-effect steps in
bread crumbs, while retaining them in the breadcrumb urls.
Refactored side-effect handling slightly (changed context data names)
in absolute url and physical path code.
Added tests for side effect handling for absolute url, physical path,
and namespace handling code.
-rw-r--r-- | Namespaces.py | 33 | ||||
-rw-r--r-- | SkinNamespace.py | 9 | ||||
-rw-r--r-- | Traverser.py | 3 | ||||
-rw-r--r-- | tests/testNamespaceTrversal.py | 22 | ||||
-rw-r--r-- | tests/testPhysicalLocationAdapters.py | 45 |
5 files changed, 104 insertions, 8 deletions
diff --git a/Namespaces.py b/Namespaces.py index 166e82b..ea831c8 100644 --- a/Namespaces.py +++ b/Namespaces.py @@ -13,11 +13,11 @@ ############################################################################## """ -$Id: Namespaces.py,v 1.4 2002/07/12 19:28:32 jim Exp $ +$Id: Namespaces.py,v 1.5 2002/07/13 14:18:36 jim Exp $ """ from Zope.Exceptions import NotFoundError -from Zope.Proxy.ContextWrapper import ContextWrapper +from Zope.Proxy.ContextWrapper import ContextWrapper, getWrapperObject from Zope.Configuration.Action import Action _namespace_handlers = {} @@ -39,11 +39,36 @@ def namespaceLookup(name, ns, qname, parameters, object, request=None): 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 = ContextWrapper(handler(qname, parameters, name, object, request), - object, name=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 diff --git a/SkinNamespace.py b/SkinNamespace.py index d23cb08..64b29c6 100644 --- a/SkinNamespace.py +++ b/SkinNamespace.py @@ -13,7 +13,7 @@ ############################################################################## """ -$Id: SkinNamespace.py,v 1.1 2002/07/12 19:28:32 jim Exp $ +$Id: SkinNamespace.py,v 1.2 2002/07/13 14:18:36 jim Exp $ """ from Zope.App.OFS.ApplicationControl.ApplicationControl \ @@ -22,11 +22,18 @@ from Namespaces import provideNamespaceHandler from 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 diff --git a/Traverser.py b/Traverser.py index 0d584e0..592f97b 100644 --- a/Traverser.py +++ b/Traverser.py @@ -13,7 +13,7 @@ ############################################################################## """Default implementation of ITraverser. -$Id: Traverser.py,v 1.3 2002/07/11 18:21:34 jim Exp $ +$Id: Traverser.py,v 1.4 2002/07/13 14:18:36 jim Exp $ """ from Zope.ComponentArchitecture import getAdapter @@ -81,6 +81,7 @@ class Traverser: continue if name == '..': + # XXX This doesn't look right. Why fall back to curr? curr = getWrapperContainer(curr) or curr continue diff --git a/tests/testNamespaceTrversal.py b/tests/testNamespaceTrversal.py index f490d2e..2380bf8 100644 --- a/tests/testNamespaceTrversal.py +++ b/tests/testNamespaceTrversal.py @@ -14,7 +14,7 @@ """ Revision information: -$Id: testNamespaceTrversal.py,v 1.3 2002/07/12 19:28:33 jim Exp $ +$Id: testNamespaceTrversal.py,v 1.4 2002/07/13 14:18:36 jim Exp $ """ from unittest import TestCase, TestSuite, main, makeSuite @@ -32,8 +32,10 @@ class Test(CleanUp, TestCase): def setUp(self): from Zope.App.Traversing.Namespaces import provideNamespaceHandler from Zope.App.Traversing.AttrItemNamespaces import attr, item + from Zope.App.Traversing.SkinNamespace import skin provideNamespaceHandler('attribute', attr) provideNamespaceHandler('item', item) + provideNamespaceHandler('skin', skin) def testAttr(self): @@ -47,6 +49,24 @@ class Test(CleanUp, TestCase): traverser = Traverser(c) v = traverser.traverse('++item++a') self.assertEqual(v, 'avalue') + + def testSideEffectsContextDetail(self): + """Check to make sure that when we traverse something in context, + that we get the right context for the result.""" + from Zope.Proxy.ContextWrapper \ + import ContextWrapper, getWrapperContainer + from Zope.App.Traversing.Traverser import Traverser + from Zope.Publisher.Browser.BrowserRequest import TestRequest + + c1 = C() + c2 = C() + c2c1 = ContextWrapper(c2, c1) + + traverser = Traverser(c2c1) + v = traverser.traverse('++skin++ZopeTop', request=TestRequest()) + self.assertEqual(v, c2) + self.failUnless(getWrapperContainer(v) is c2c1) + diff --git a/tests/testPhysicalLocationAdapters.py b/tests/testPhysicalLocationAdapters.py index c0e55c6..5242d76 100644 --- a/tests/testPhysicalLocationAdapters.py +++ b/tests/testPhysicalLocationAdapters.py @@ -12,7 +12,7 @@ # ############################################################################## """ -$Id: testPhysicalLocationAdapters.py,v 1.1 2002/07/11 18:21:34 jim Exp $ +$Id: testPhysicalLocationAdapters.py,v 1.2 2002/07/13 14:18:36 jim Exp $ """ from unittest import TestCase, TestSuite, main, makeSuite @@ -50,6 +50,49 @@ class Test(PlacelessSetup, TestCase): self.assertRaises(TypeError, adapter.getPhysicalPath) self.assertRaises(TypeError, adapter.getPhysicalRoot) + def testWSideEffectDataInFront(self): + provideAdapter(None, IPhysicallyLocatable, WrapperPhysicallyLocatable) + provideAdapter(IContainmentRoot, IPhysicallyLocatable, + RootPhysicallyLocatable) + + root = Root() + root = ContextWrapper(root, root, name='.', + side_effect_name="++skin++ZopeTop") + f1 = ContextWrapper(C(), root, name='f1') + f2 = ContextWrapper(C(), f1, name='f2') + f3 = ContextWrapper(C(), f2, name='f3') + + adapter = getAdapter(f3, IPhysicallyLocatable) + + self.assertEqual(adapter.getPhysicalPath(), ('', 'f1', 'f2', 'f3')) + self.assertEqual(adapter.getPhysicalRoot(), root) + + adapter = getAdapter(C(), IPhysicallyLocatable) + self.assertRaises(TypeError, adapter.getPhysicalPath) + self.assertRaises(TypeError, adapter.getPhysicalRoot) + + def testWSideEffectDataInMiddle(self): + provideAdapter(None, IPhysicallyLocatable, WrapperPhysicallyLocatable) + provideAdapter(IContainmentRoot, IPhysicallyLocatable, + RootPhysicallyLocatable) + + root = Root() + c = C() + f1 = ContextWrapper(c, root, name='f1') + f1 = ContextWrapper(c, f1, name='.', + side_effect_name="++skin++ZopeTop") + f2 = ContextWrapper(C(), f1, name='f2') + f3 = ContextWrapper(C(), f2, name='f3') + + adapter = getAdapter(f3, IPhysicallyLocatable) + + self.assertEqual(adapter.getPhysicalPath(), ('', 'f1', 'f2', 'f3')) + self.assertEqual(adapter.getPhysicalRoot(), root) + + adapter = getAdapter(C(), IPhysicallyLocatable) + self.assertRaises(TypeError, adapter.getPhysicalPath) + self.assertRaises(TypeError, adapter.getPhysicalRoot) + def test_suite(): return TestSuite(( makeSuite(Test), |