summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Alexander <steve@z3u.com>2002-06-15 20:38:19 +0000
committerSteve Alexander <steve@z3u.com>2002-06-15 20:38:19 +0000
commitcb676e38461ca2f420e9284056e02a3d9f7698d4 (patch)
tree7224b57f937887f987fb9e6f85b5cf72925ade07
parentbaa7e23fcf0f0466277216aa167d7ede613de67a (diff)
downloadzope-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.py65
-rw-r--r--__init__.py72
-rw-r--r--tests/testConvenienceFunctions.py155
-rw-r--r--tests/testObjectName.py69
-rw-r--r--tests/testTraverser.py11
-rw-r--r--traversing.zcml13
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>