diff --git a/Lib/inspect.py b/Lib/inspect.py index c2a1ed4148e749..a982fc724ba13d 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -347,7 +347,10 @@ def getmembers(object, predicate=None): # like calling their __get__ (see bug #1785), so fall back to # looking in the __dict__. try: - value = getattr(object, key) + if isinstance(getattr_static(object, key), property): + value = getattr_static(object, key) + else: + value = getattr(object, key) # handle the duplicate key if key in processed: raise AttributeError diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 9d28d5ad570d11..350fb30227ad3b 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1191,6 +1191,27 @@ def f(self): self.assertIn(('f', b.f), inspect.getmembers(b)) self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod)) + def test_getmembers_static(self): + class Foo: + def __init__(self, bar): + self._bar = bar + + @property + def bar(self): + # This property should not be called by getmembers + raise NotImplementedError + + foobar = Foo(42) + try: + members = inspect.getmembers(foobar) + property_member = ('bar', inspect.getattr_static(foobar, 'bar')) + self.assertIn(property_member, members) + class_members = inspect.getmembers(Foo) + property_class_member = ('bar', inspect.getattr_static(Foo, 'bar')) + self.assertIn(property_member, class_members) + except NotImplementedError: + self.fail('getmembers() called property!') + def test_getmembers_VirtualAttribute(self): class M(type): def __getattr__(cls, name): diff --git a/Misc/NEWS.d/next/Library/2019-10-01-12-23-37.bpo-38337.QmLSXW.rst b/Misc/NEWS.d/next/Library/2019-10-01-12-23-37.bpo-38337.QmLSXW.rst new file mode 100644 index 00000000000000..17ab1751ea39e1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-10-01-12-23-37.bpo-38337.QmLSXW.rst @@ -0,0 +1 @@ +Prevent :func:`inspect.getmembers` from calling descriptors.