From: Weipeng Hong Date: Sun, 23 Jan 2022 17:40:38 +0000 (+0800) Subject: bpo-46103: Fix inspect.getmembers to only get __bases__ from class (GH-30147) X-Git-Tag: v3.11.0a5~128 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=691506f4e9408a1205166f99640946ad7822e302;p=thirdparty%2FPython%2Fcpython.git bpo-46103: Fix inspect.getmembers to only get __bases__ from class (GH-30147) --- diff --git a/Lib/inspect.py b/Lib/inspect.py index 879a577d43fb..d47f5b717471 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -540,23 +540,23 @@ def isabstract(object): return False def _getmembers(object, predicate, getter): + results = [] + processed = set() + names = dir(object) if isclass(object): mro = (object,) + getmro(object) + # add any DynamicClassAttributes to the list of names if object is a class; + # this may result in duplicate entries if, for example, a virtual + # attribute with the same name as a DynamicClassAttribute exists + try: + for base in object.__bases__: + for k, v in base.__dict__.items(): + if isinstance(v, types.DynamicClassAttribute): + names.append(k) + except AttributeError: + pass else: mro = () - results = [] - processed = set() - names = dir(object) - # :dd any DynamicClassAttributes to the list of names if object is a class; - # this may result in duplicate entries if, for example, a virtual - # attribute with the same name as a DynamicClassAttribute exists - try: - for base in object.__bases__: - for k, v in base.__dict__.items(): - if isinstance(v, types.DynamicClassAttribute): - names.append(k) - except AttributeError: - pass for key in names: # First try to get the value via getattr. Some descriptors don't # like calling their __get__ (see bug #1785), so fall back to diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index cdbb9eb6a8f7..76fa6f7e2dab 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1215,8 +1215,13 @@ class TestClassesAndFunctions(unittest.TestCase): @types.DynamicClassAttribute def eggs(self): return 'spam' + class B: + def __getattr__(self, attribute): + return None self.assertIn(('eggs', 'scrambled'), inspect.getmembers(A)) self.assertIn(('eggs', 'spam'), inspect.getmembers(A())) + b = B() + self.assertIn(('__getattr__', b.__getattr__), inspect.getmembers(b)) def test_getmembers_static(self): class A: diff --git a/Misc/NEWS.d/next/Library/2021-12-16-23-42-54.bpo-46103.LMnZAN.rst b/Misc/NEWS.d/next/Library/2021-12-16-23-42-54.bpo-46103.LMnZAN.rst new file mode 100644 index 000000000000..3becbc3de8fc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-12-16-23-42-54.bpo-46103.LMnZAN.rst @@ -0,0 +1,2 @@ +Now :func:`inspect.getmembers` only gets :attr:`__bases__` attribute from +class type. Patch by Weipeng Hong.