diff --git a/Lib/inspect.py b/Lib/inspect.py index 950bdb221798d6..590843d183da99 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -340,7 +340,9 @@ def getmembers(object, predicate=None): for k, v in base.__dict__.items(): if isinstance(v, types.DynamicClassAttribute): names.append(k) - except AttributeError: + except Exception: + # Deliberately catch all exceptions for properties that raise + # exceptions (e.g. NotImplementedError). See bug #35108 pass for key in names: # First try to get the value via getattr. Some descriptors don't @@ -360,6 +362,11 @@ def getmembers(object, predicate=None): # could be a (currently) missing slot member, or a buggy # __dir__; discard and move on continue + except Exception: + # See bug #25108 + # Attempt to get the value with getattr_static but skip if + # even that fails. + value = getattr_static(object, key) if not predicate or predicate(value): results.append((key, value)) processed.add(key) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 8a2efc879323fb..f2f37bb76913f3 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1213,6 +1213,17 @@ class C(metaclass=M): attrs = [a[0] for a in inspect.getmembers(C)] self.assertNotIn('missing', attrs) + def test_getmembers_property_raises_exception(self): + # bpo-35108 + class A: + @property + def f(self): + raise NotImplementedError + + self.assertIn(("f", A.f), inspect.getmembers(A())) + + + class TestIsDataDescriptor(unittest.TestCase): def test_custom_descriptors(self): diff --git a/Misc/NEWS.d/next/Library/2020-02-03-09-21-13.bpo-35108.7iPRPL.rst b/Misc/NEWS.d/next/Library/2020-02-03-09-21-13.bpo-35108.7iPRPL.rst new file mode 100644 index 00000000000000..0748ebfbcda22c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-02-03-09-21-13.bpo-35108.7iPRPL.rst @@ -0,0 +1 @@ +Handle proprties raising exceptions in :meth:`inspect.getmembers`.