summaryrefslogtreecommitdiff
path: root/repoze
diff options
context:
space:
mode:
Diffstat (limited to 'repoze')
-rw-r--r--repoze/bfg/tests/test_zcml.py42
-rw-r--r--repoze/bfg/zcml.py25
2 files changed, 65 insertions, 2 deletions
diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py
index 282c27472..d6eb80c44 100644
--- a/repoze/bfg/tests/test_zcml.py
+++ b/repoze/bfg/tests/test_zcml.py
@@ -2544,6 +2544,48 @@ class TestExcludeFunction(unittest.TestCase):
self.assertEqual(self._callFUT('.foo'), True)
self.assertEqual(self._callFUT('foo'), False)
+class TestGetMembersFunction(unittest.TestCase):
+ def _callFUT(self, object, predicate=None):
+ from repoze.bfg.zcml import getmembers
+ return getmembers(object, predicate)
+
+ def test_with_attribute_error(self):
+ class Dummy:
+ @property
+ def raises(self):
+ raise AttributeError('raises')
+ ob = Dummy()
+ result = self._callFUT(ob, None)
+ result.sort()
+ self.assertEqual(result,
+ [('__doc__', None),
+ ('__module__', 'repoze.bfg.tests.test_zcml')]
+ )
+
+ def test_without_attribute_error(self):
+ class Dummy:
+ def doesntraise(self):
+ pass
+ ob = Dummy()
+ result = self._callFUT(ob, None)
+ result.sort()
+ self.assertEqual(result,
+ [('__doc__', None),
+ ('__module__', 'repoze.bfg.tests.test_zcml'),
+ ('doesntraise', ob.doesntraise)]
+ )
+
+ def test_predicate(self):
+ class Dummy:
+ def doesntraise(self):
+ pass
+ ob = Dummy()
+ def predicate(testing):
+ return getattr(testing, '__name__', None) == 'doesntraise'
+ result = self._callFUT(ob, predicate)
+ result.sort()
+ self.assertEqual(result,[('doesntraise', ob.doesntraise)])
+
class DummyModule:
__path__ = "foo"
__name__ = "dummy"
diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py
index d08a61303..6bf180b3a 100644
--- a/repoze/bfg/zcml.py
+++ b/repoze/bfg/zcml.py
@@ -707,8 +707,13 @@ class BFGClassGrokker(object):
found = BFGViewGrokker().grok(name, class_, **kw)
# grok any decorations attached to the class' method (direct
- # methods only, not methods of any base class)
- methods = inspect.getmembers(class_, inspect.ismethod)
+ # methods only, not methods of any base class); we can't use
+ # inspect.getmembers here because it doesn't deal with a
+ # corner case where objects that inherit from Persistent
+ # advertises a '__provides__' as per dir(ob) but getattr(ob,
+ # '__provides__') raises an AttributeError. Unknown why this
+ # happens, but it doesn't matter: need to deal with it.
+ methods = getmembers(class_, inspect.ismethod)
classmethods = class_.__dict__.keys()
for method_name, method in methods:
if method_name in classmethods:
@@ -739,3 +744,19 @@ class Uncacheable(object):
this class only exists for backwards compatibility (<0.8.1)"""
file_configure = zcml_configure # backwards compat (>0.8.1)
+
+def getmembers(object, predicate=None):
+ """Return all members of an object as (name, value) pairs sorted
+ by name. Optionally, only return members that satisfy a given
+ predicate. Differs from inspect.getmembers inasmuch as it ignores
+ AttributeErrors."""
+ results = []
+ for key in dir(object):
+ try:
+ value = getattr(object, key)
+ except AttributeError:
+ continue
+ if not predicate or predicate(value):
+ results.append((key, value))
+ results.sort()
+ return results