diff options
author | Steve Alexander <steve@z3u.com> | 2002-06-15 20:38:19 +0000 |
---|---|---|
committer | Steve Alexander <steve@z3u.com> | 2002-06-15 20:38:19 +0000 |
commit | cb676e38461ca2f420e9284056e02a3d9f7698d4 (patch) | |
tree | 7224b57f937887f987fb9e6f85b5cf72925ade07 | |
parent | baa7e23fcf0f0466277216aa167d7ede613de67a (diff) | |
download | zope-traversing-cb676e38461ca2f420e9284056e02a3d9f7698d4.tar.gz |
Added a set of convenience functions that you can import from
Zope.App.Traversing.
Fixed a few typos in the ContextWrapper docstrings, and also added
an isWrapper method to Zope/Proxy/IContextWrapper, mainly so that
I can raise nice errors if the convenience functions are passed
an unwrapped object, rather than returning objs or Nones or []s and
having programs fail at tenuously related other places.
-rw-r--r-- | ObjectName.py | 65 | ||||
-rw-r--r-- | __init__.py | 72 | ||||
-rw-r--r-- | tests/testConvenienceFunctions.py | 155 | ||||
-rw-r--r-- | tests/testObjectName.py | 69 | ||||
-rw-r--r-- | tests/testTraverser.py | 11 | ||||
-rw-r--r-- | traversing.zcml | 13 |
6 files changed, 380 insertions, 5 deletions
diff --git a/ObjectName.py b/ObjectName.py new file mode 100644 index 0000000..be245db --- /dev/null +++ b/ObjectName.py @@ -0,0 +1,65 @@ +############################################################################## +# +# 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: ObjectName.py,v 1.1 2002/06/15 20:38:17 stevea Exp $ +""" +from Zope.Proxy.ContextWrapper import getWrapperData + +from Interface import Interface + +class IObjectName(Interface): + + def __str__(): + """Get a human-readable string representation + """ + + def __repr__(): + """Get a string representation + """ + + def __call__(): + """Get a string representation + """ + +class ObjectName(object): + + __implements__ = IObjectName + + def __init__(self, context): + self.context = context + + def __str__(self): + dict = getWrapperData(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__ diff --git a/__init__.py b/__init__.py index 656c898..ff17ff4 100644 --- a/__init__.py +++ b/__init__.py @@ -14,5 +14,77 @@ """ Traversing the object tree. """ +# being careful not to pollute the namespace unnecessarily... +from Zope.ComponentArchitecture import getAdapter as _getAdapter +from ObjectName import IObjectName as _IObjectName +from ITraverser import ITraverser as _ITraverser +from Traverser import WrapperChain as _WrapperChain +from Zope.Proxy.ContextWrapper import getWrapperContext as _getWrapperContext +from Zope.Proxy.ContextWrapper import isWrapper as _isWrapper +_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' + + Raises NotFoundError if path cannot be found + Raises TypeError if place is not context wrapped + """ + if not _isWrapper(place): + raise TypeError, "Not enough context information to traverse" + traverser = _getAdapter(place, _ITraverser) + if default is _marker: + return traverser.traverse(path, request=request) + else: + return traverser.traverse(path, default=default, request=request) + +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 + given object. + + Raises TypeError if the given object is not context wrapped + """ + if not _isWrapper(obj): + raise TypeError, "Not enough context information to traverse" + + return _getAdapter(obj, _ITraverser).getPhysicalPath() + +def getPhysicalRoot(obj): + """Returns the root of the traversal for the given object. + Raises TypeError if the given object is not context wrapped + """ + if not _isWrapper(obj): + raise TypeError, "Not enough context information to traverse" + + return _getAdapter(obj, _ITraverser).getPhysicalRoot() diff --git a/tests/testConvenienceFunctions.py b/tests/testConvenienceFunctions.py new file mode 100644 index 0000000..af9a3b6 --- /dev/null +++ b/tests/testConvenienceFunctions.py @@ -0,0 +1,155 @@ +############################################################################## +# +# 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: testConvenienceFunctions.py,v 1.1 2002/06/15 20:38:18 stevea Exp $ +""" +from unittest import TestCase, TestSuite, main, makeSuite +from Zope.App.OFS.Services.ServiceManager.tests.PlacefulSetup \ + import PlacefulSetup +from Zope.Proxy.ContextWrapper import ContextWrapper +from Zope.App.Traversing.Traverser import Traverser +from Zope.ComponentArchitecture import getService +from Zope.App.Traversing.ITraverser import ITraverser +from Zope.App.Traversing.ITraversable import ITraversable +from Zope.App.Traversing.DefaultTraversable import DefaultTraversable +from Zope.App.Traversing.ObjectName import IObjectName, ObjectName + +class C: + def __init__(self, name): + self.name = name + +class Test(PlacefulSetup, TestCase): + + def setUp(self): + PlacefulSetup.setUp(self) + # Build up a wrapper chain + root = C('root') + folder = C('folder') + item = C('item') + + self.root = ContextWrapper(root, None, name='') + self.folder = ContextWrapper(folder, self.root, name='folder') + self.item = ContextWrapper(item, self.folder, name='item') + self.unwrapped_item = item + + root.folder = folder + folder.item = item + + self.tr = Traverser(root) + getService(None,"Adapters").provideAdapter( + None, ITraverser, Traverser) + getService(None,"Adapters").provideAdapter( + None, ITraversable, DefaultTraversable) + getService(None,"Adapters").provideAdapter( + None, IObjectName, ObjectName) + + + def testTraverse(self): + from Zope.App.Traversing import traverse + self.assertEqual( + traverse(self.item, '/folder/item'), + self.tr.traverse('/folder/item') + ) + + def testTraverseFromUnwrapped(self): + from Zope.App.Traversing import traverse + self.assertRaises( + TypeError, + traverse, + self.unwrapped_item, '/folder/item' + ) + + def testObjectName(self): + from Zope.App.Traversing import objectName + self.assertEqual( + objectName(self.item), + 'item' + ) + + def testObjectNameFromUnwrapped(self): + from Zope.App.Traversing import objectName + self.assertRaises( + TypeError, + objectName, + self.unwrapped_item + ) + + def testGetParent(self): + from Zope.App.Traversing import getParent + self.assertEqual( + getParent(self.item), + self.folder + ) + + def testGetParentFromUnwrapped(self): + from Zope.App.Traversing import getParent + self.assertRaises( + TypeError, + getParent, + self.unwrapped_item + ) + + def testGetParents(self): + from Zope.App.Traversing import getParents + self.assertEqual( + getParents(self.item), + [self.folder, self.root] + ) + + def testGetParentsFromUnwrapped(self): + from Zope.App.Traversing import getParents + self.assertRaises( + TypeError, + getParents, + self.unwrapped_item + ) + + def testGetPhysicalPath(self): + from Zope.App.Traversing import getPhysicalPath + self.assertEqual( + getPhysicalPath(self.item), + ('', 'folder', 'item') + ) + + def testGetPhysicalPathFromUnwrapped(self): + from Zope.App.Traversing import getPhysicalPath + self.assertRaises( + TypeError, + getPhysicalPath, + self.unwrapped_item + ) + + def testGetPhysicalRoot(self): + from Zope.App.Traversing import getPhysicalRoot + self.assertEqual( + getPhysicalRoot(self.item), + self.root + ) + + def testGetPhysicalRootFromUnwrapped(self): + from Zope.App.Traversing import getPhysicalRoot + self.assertRaises( + TypeError, + getPhysicalRoot, + self.unwrapped_item + ) + +def test_suite(): + return TestSuite(( + makeSuite(Test), + )) + +if __name__=='__main__': + main(defaultTest='test_suite') diff --git a/tests/testObjectName.py b/tests/testObjectName.py new file mode 100644 index 0000000..def40dd --- /dev/null +++ b/tests/testObjectName.py @@ -0,0 +1,69 @@ +############################################################################## +# +# 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. +# +############################################################################## +"""Test the ObjectName adapter + +Revision information: +$Id: testObjectName.py,v 1.1 2002/06/15 20:38:18 stevea Exp $ +""" +from unittest import TestCase, TestSuite, main, makeSuite +from Interface import Interface + +from Zope.ComponentArchitecture.tests.PlacelessSetup import PlacelessSetup +from Zope.ComponentArchitecture import getService, getAdapter + +from Zope.Proxy.ContextWrapper import ContextWrapper + +from Zope.App.Traversing.ObjectName \ + import IObjectName, ObjectName, SiteObjectName + +class IRoot(Interface): pass + +class Root: + __implements__ = IRoot + +class TrivialContent(object): + """Trivial content object, used because instances of object are rocks.""" + +class Test(PlacelessSetup, TestCase): + + def setUp(self): + PlacelessSetup.setUp(self) + + provideAdapter = getService(None, "Adapters").provideAdapter + provideAdapter(None, IObjectName, [ObjectName]) + provideAdapter(IRoot, IObjectName, [ObjectName]) + + def testAdapterBadObject(self): + adapter = getAdapter(None, IObjectName) + self.assertRaises(TypeError, adapter) + + def testAdapterNoContext(self): + adapter = getAdapter(Root(), IObjectName) + self.assertRaises(TypeError, adapter) + + def testAdapterBasicContext(self): + content = ContextWrapper(TrivialContent(), Root(), name='a') + content = ContextWrapper(TrivialContent(), content, name='b') + content = ContextWrapper(TrivialContent(), content, name='c') + adapter = getAdapter(content, IObjectName) + self.assertEqual(adapter(), 'c') + +def test_suite(): + return TestSuite(( + makeSuite(Test), + )) + +if __name__=='__main__': + main(defaultTest='test_suite') + diff --git a/tests/testTraverser.py b/tests/testTraverser.py index 0cfdf5e..c44aa33 100644 --- a/tests/testTraverser.py +++ b/tests/testTraverser.py @@ -13,7 +13,7 @@ ############################################################################## """ -$Id: testTraverser.py,v 1.2 2002/06/10 23:28:17 jim Exp $ +$Id: testTraverser.py,v 1.3 2002/06/15 20:38:18 stevea Exp $ """ import unittest @@ -24,14 +24,15 @@ from Zope.App.Traversing.DefaultTraversable import DefaultTraversable from Zope.Proxy.ContextWrapper import ContextWrapper from Zope.Exceptions import NotFoundError, Unauthorized from Zope.ComponentArchitecture import getService -from Zope.Security.SecurityManagement import setSecurityPolicy, \ - noSecurityManager +from Zope.Security.SecurityManagement \ + import setSecurityPolicy, noSecurityManager from Interface.Verify import verifyClass from Interface.Implements import instancesOfObjectImplements -from Zope.App.OFS.Services.ServiceManager.tests.PlacefulSetup import PlacefulSetup +from Zope.App.OFS.Services.ServiceManager.tests.PlacefulSetup \ + import PlacefulSetup from Zope.Security.Checker \ - import ProxyFactory, defineChecker, NamesChecker, CheckerPublic, Checker + import ProxyFactory, defineChecker, NamesChecker, CheckerPublic, Checker from Zope.Security.SecurityManagement import newSecurityManager class C: diff --git a/traversing.zcml b/traversing.zcml index 29b8d77..e1cc656 100644 --- a/traversing.zcml +++ b/traversing.zcml @@ -15,5 +15,18 @@ <adapter factory="Zope.App.Traversing.DefaultTraversable." provides="Zope.App.Traversing.ITraversable." /> +<adapter + factory=".ObjectName." + provides=".ObjectName.IObjectName" + permission='Zope.Public' +/> + +<adapter + factory=".ObjectName.SiteObjectName" + provides=".ObjectName.IObjectName" + for="Zope.App.OFS.Content.Folder.RootFolder.IRootFolder" + permission='Zope.Public' +/> + </zopeConfigure> |