summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-08-04 17:02:47 +0000
committerChris McDonough <chrism@agendaless.com>2009-08-04 17:02:47 +0000
commit0f5d8befb0f7a77c3b1ac96e43f9924f512d7fb7 (patch)
tree00f4d7cab03cf86cc192906dacc0a8079eebae9b
parentff65a5a7b6177759191071be8790d02bd4c0ce8e (diff)
downloadpyramid-0f5d8befb0f7a77c3b1ac96e43f9924f512d7fb7.tar.gz
pyramid-0f5d8befb0f7a77c3b1ac96e43f9924f512d7fb7.tar.bz2
pyramid-0f5d8befb0f7a77c3b1ac96e43f9924f512d7fb7.zip
- Allow ``repoze.bfg.traversal.find_interface`` API to use a class
object as the argument to compare against the ``model`` passed in. This means you can now do ``find_interface(model, SomeClass)`` and the first object which is found in the lineage which has ``SomeClass`` as its class (or the first object found which has ``SomeClass`` as any of its superclasses) will be returned.
-rw-r--r--CHANGES.txt7
-rw-r--r--repoze/bfg/tests/test_traversal.py22
-rw-r--r--repoze/bfg/traversal.py18
3 files changed, 41 insertions, 6 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 8b0a3cbcb..173204a9c 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,13 @@
Next release
============
+- Allow ``repoze.bfg.traversal.find_interface`` API to use a class
+ object as the argument to compare against the ``model`` passed in.
+ This means you can now do ``find_interface(model, SomeClass)`` and
+ the first object which is found in the lineage which has
+ ``SomeClass`` as its class (or the first object found which has
+ ``SomeClass`` as any of its superclasses) will be returned.
+
- Fixed documentation bugs related to forget and remember in security API
docs.
diff --git a/repoze/bfg/tests/test_traversal.py b/repoze/bfg/tests/test_traversal.py
index 4a4080aab..3041a271c 100644
--- a/repoze/bfg/tests/test_traversal.py
+++ b/repoze/bfg/tests/test_traversal.py
@@ -327,7 +327,7 @@ class FindInterfaceTests(unittest.TestCase):
from repoze.bfg.traversal import find_interface
return find_interface(context, iface)
- def test_it(self):
+ def test_it_interface(self):
baz = DummyContext()
bar = DummyContext(baz)
foo = DummyContext(bar)
@@ -349,6 +349,26 @@ class FindInterfaceTests(unittest.TestCase):
result = self._callFUT(baz, IFoo)
self.assertEqual(result.__name__, 'root')
+ def test_it_class(self):
+ class DummyRoot(object):
+ def __init__(self, child):
+ self.child = child
+ baz = DummyContext()
+ bar = DummyContext(baz)
+ foo = DummyContext(bar)
+ root = DummyRoot(foo)
+ root.__parent__ = None
+ root.__name__ = 'root'
+ foo.__parent__ = root
+ foo.__name__ = 'foo'
+ bar.__parent__ = foo
+ bar.__name__ = 'bar'
+ baz.__parent__ = bar
+ baz.__name__ = 'baz'
+ request = DummyRequest()
+ result = self._callFUT(baz, DummyRoot)
+ self.assertEqual(result.__name__, 'root')
+
class FindRootTests(unittest.TestCase):
def _callFUT(self, context):
from repoze.bfg.traversal import find_root
diff --git a/repoze/bfg/traversal.py b/repoze/bfg/traversal.py
index 374804df0..7f6b87ea1 100644
--- a/repoze/bfg/traversal.py
+++ b/repoze/bfg/traversal.py
@@ -5,6 +5,7 @@ from zope.component import getMultiAdapter
from zope.interface import classProvides
from zope.interface import implements
+from zope.interface.interfaces import IInterface
from repoze.lru import lru_cache
@@ -77,15 +78,22 @@ def find_model(model, path):
raise KeyError('%r has no subelement %s' % (context, view_name))
return context
-def find_interface(model, interface):
+def find_interface(model, class_or_interface):
"""
Return the first object found in the parent chain of ``model``
- which provides the interface ``interface``. Return ``None`` if no
- object providing ``interface`` can be found in the parent chain.
- The ``model`` passed in *must* be :term:`location`-aware.
+ which, a) if ``interface_or_class`` is a Python class object, is
+ an instance of the class or any subclass of that class or b) if
+ ``interface_or_class`` is a Zope interface, provides the specified
+ interface. Return ``None`` if no object providing
+ ``interface_or_class`` can be found in the parent chain. The
+ ``model`` passed in *must* be :term:`location`-aware.
"""
+ if IInterface.providedBy(class_or_interface):
+ test = class_or_interface.providedBy
+ else:
+ test = lambda arg: isinstance(arg, class_or_interface)
for location in lineage(model):
- if interface.providedBy(location):
+ if test(location):
return location
def model_path(model, *elements):