Skip to content

Commit 691506f

Browse files
authored
bpo-46103: Fix inspect.getmembers to only get __bases__ from class (GH-30147)
1 parent 76dc047 commit 691506f

File tree

3 files changed

+20
-13
lines changed

3 files changed

+20
-13
lines changed

Lib/inspect.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -540,23 +540,23 @@ def isabstract(object):
540540
return False
541541

542542
def _getmembers(object, predicate, getter):
543+
results = []
544+
processed = set()
545+
names = dir(object)
543546
if isclass(object):
544547
mro = (object,) + getmro(object)
548+
# add any DynamicClassAttributes to the list of names if object is a class;
549+
# this may result in duplicate entries if, for example, a virtual
550+
# attribute with the same name as a DynamicClassAttribute exists
551+
try:
552+
for base in object.__bases__:
553+
for k, v in base.__dict__.items():
554+
if isinstance(v, types.DynamicClassAttribute):
555+
names.append(k)
556+
except AttributeError:
557+
pass
545558
else:
546559
mro = ()
547-
results = []
548-
processed = set()
549-
names = dir(object)
550-
# :dd any DynamicClassAttributes to the list of names if object is a class;
551-
# this may result in duplicate entries if, for example, a virtual
552-
# attribute with the same name as a DynamicClassAttribute exists
553-
try:
554-
for base in object.__bases__:
555-
for k, v in base.__dict__.items():
556-
if isinstance(v, types.DynamicClassAttribute):
557-
names.append(k)
558-
except AttributeError:
559-
pass
560560
for key in names:
561561
# First try to get the value via getattr. Some descriptors don't
562562
# like calling their __get__ (see bug #1785), so fall back to

Lib/test/test_inspect.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,8 +1215,13 @@ class A(metaclass=M):
12151215
@types.DynamicClassAttribute
12161216
def eggs(self):
12171217
return 'spam'
1218+
class B:
1219+
def __getattr__(self, attribute):
1220+
return None
12181221
self.assertIn(('eggs', 'scrambled'), inspect.getmembers(A))
12191222
self.assertIn(('eggs', 'spam'), inspect.getmembers(A()))
1223+
b = B()
1224+
self.assertIn(('__getattr__', b.__getattr__), inspect.getmembers(b))
12201225

12211226
def test_getmembers_static(self):
12221227
class A:
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Now :func:`inspect.getmembers` only gets :attr:`__bases__` attribute from
2+
class type. Patch by Weipeng Hong.

0 commit comments

Comments
 (0)