From ba746bc197a8e040f70b0163e467d89e4b70ffe4 Mon Sep 17 00:00:00 2001 From: Jonas Drotleff Date: Tue, 1 Oct 2019 14:02:58 +0200 Subject: [PATCH 1/8] Change getattr to inspect.getattr_static --- Lib/inspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/inspect.py b/Lib/inspect.py index c2a1ed4148e749..9ef03ade6b41e4 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -347,7 +347,7 @@ 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) + value = getattr_static(object, key) # handle the duplicate key if key in processed: raise AttributeError From 80fcfb4671db82078419ff1a4f4712d7ba8a7127 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2019 12:23:38 +0000 Subject: [PATCH 2/8] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NEWS.d/next/Library/2019-10-01-12-23-37.bpo-38337.QmLSXW.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2019-10-01-12-23-37.bpo-38337.QmLSXW.rst 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..9898ad7f4ae41d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-10-01-12-23-37.bpo-38337.QmLSXW.rst @@ -0,0 +1 @@ +Prevent ``inspect.getmembers`` to call properties. Used ``inspect.getattr_static`` instead. \ No newline at end of file From 434a3e6a5b3cbece5156d16dfe67ebbede27989e Mon Sep 17 00:00:00 2001 From: Jonas Drotleff Date: Tue, 1 Oct 2019 19:36:22 +0200 Subject: [PATCH 3/8] Update NEWS entry As suggested by @brandtbucher Co-Authored-By: Brandt Bucher --- .../next/Library/2019-10-01-12-23-37.bpo-38337.QmLSXW.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 9898ad7f4ae41d..17ab1751ea39e1 100644 --- 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 @@ -1 +1 @@ -Prevent ``inspect.getmembers`` to call properties. Used ``inspect.getattr_static`` instead. \ No newline at end of file +Prevent :func:`inspect.getmembers` from calling descriptors. From db038c591ca02ee4b30816d332277b07012dca10 Mon Sep 17 00:00:00 2001 From: Jonas Drotleff Date: Tue, 1 Oct 2019 23:42:52 +0200 Subject: [PATCH 4/8] Add test for inspect.getmembers Make sure inspect.getmembers won't call properties or other dynamic attributes --- Lib/test/test_inspect.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 9d28d5ad570d11..d4b822c38357ea 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1191,6 +1191,23 @@ 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__(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) + class_members = inspect.getmembers(Foo) + except NotImplementedError: + self.fail('getmembers() called property!') + def test_getmembers_VirtualAttribute(self): class M(type): def __getattr__(cls, name): From 8a95946530e1ba9e9600ab48b413eaf70c933f43 Mon Sep 17 00:00:00 2001 From: Jonas Drotleff Date: Tue, 1 Oct 2019 23:48:08 +0200 Subject: [PATCH 5/8] Assert whether the property is in the list --- Lib/test/test_inspect.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index d4b822c38357ea..45010b51f7a956 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1204,7 +1204,11 @@ def bar(self): 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!') From b4152248739073b50c548393161ebc43b4d89b9c Mon Sep 17 00:00:00 2001 From: Jonas Drotleff Date: Thu, 3 Oct 2019 13:46:05 +0200 Subject: [PATCH 6/8] Fix constructor without self --- Lib/test/test_inspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 45010b51f7a956..7b4da03dcc044b 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1193,7 +1193,7 @@ def f(self): def test_getmembers_static(self): class Foo: - def __init__(bar): + def __init__(self, bar): self._bar = bar @property From 64f5954a144827de1ca78902d15747bd853f297f Mon Sep 17 00:00:00 2001 From: Jonas Drotleff Date: Thu, 3 Oct 2019 14:45:56 +0200 Subject: [PATCH 7/8] bpo-38337: Fix whitespace in test_inspect --- Lib/test/test_inspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 7b4da03dcc044b..350fb30227ad3b 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1200,7 +1200,7 @@ def __init__(self, bar): def bar(self): # This property should not be called by getmembers raise NotImplementedError - + foobar = Foo(42) try: members = inspect.getmembers(foobar) From 3ac2093a78b0fcb84646b790f3158cf563a0d6ce Mon Sep 17 00:00:00 2001 From: Jonas Drotleff Date: Mon, 7 Oct 2019 19:57:38 +0200 Subject: [PATCH 8/8] bpo-38337: Only use getattr_static for properties --- Lib/inspect.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/inspect.py b/Lib/inspect.py index 9ef03ade6b41e4..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_static(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