From 0f5d8befb0f7a77c3b1ac96e43f9924f512d7fb7 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Tue, 4 Aug 2009 17:02:47 +0000 Subject: - 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. --- CHANGES.txt | 7 +++++++ repoze/bfg/tests/test_traversal.py | 22 +++++++++++++++++++++- repoze/bfg/traversal.py | 18 +++++++++++++----- 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): -- cgit v1.2.3