mirror of https://github.com/python/cpython
bpo-30533:Add function inspect.getmembers_static that does not call properties or dynamic properties. (#20911)
* Add function inspect.getmembers_static that does not call properties or dynamic properties. * update _getmembers args * Update Misc/NEWS.d/next/Library/2020-06-16-18-00-56.bpo-30533.StL57t.rst Co-authored-by: Itamar Ostricher <itamarost@gmail.com> * Update Lib/inspect.py Co-authored-by: Itamar Ostricher <itamarost@gmail.com> * Removes the copy pasted doc string Co-authored-by: Itamar Ostricher <itamarost@gmail.com> Co-authored-by: Dino Viehland <dinoviehland@gmail.com>
This commit is contained in:
parent
4b97d974ec
commit
af8c8caaf5
|
@ -440,9 +440,7 @@ def isabstract(object):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def getmembers(object, predicate=None):
|
def _getmembers(object, predicate, getter):
|
||||||
"""Return all members of an object as (name, value) pairs sorted by name.
|
|
||||||
Optionally, only return members that satisfy a given predicate."""
|
|
||||||
if isclass(object):
|
if isclass(object):
|
||||||
mro = (object,) + getmro(object)
|
mro = (object,) + getmro(object)
|
||||||
else:
|
else:
|
||||||
|
@ -465,7 +463,7 @@ def getmembers(object, predicate=None):
|
||||||
# like calling their __get__ (see bug #1785), so fall back to
|
# like calling their __get__ (see bug #1785), so fall back to
|
||||||
# looking in the __dict__.
|
# looking in the __dict__.
|
||||||
try:
|
try:
|
||||||
value = getattr(object, key)
|
value = getter(object, key)
|
||||||
# handle the duplicate key
|
# handle the duplicate key
|
||||||
if key in processed:
|
if key in processed:
|
||||||
raise AttributeError
|
raise AttributeError
|
||||||
|
@ -484,6 +482,25 @@ def getmembers(object, predicate=None):
|
||||||
results.sort(key=lambda pair: pair[0])
|
results.sort(key=lambda pair: pair[0])
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
def getmembers(object, predicate=None):
|
||||||
|
"""Return all members of an object as (name, value) pairs sorted by name.
|
||||||
|
Optionally, only return members that satisfy a given predicate."""
|
||||||
|
return _getmembers(object, predicate, getattr)
|
||||||
|
|
||||||
|
def getmembers_static(object, predicate=None):
|
||||||
|
"""Return all members of an object as (name, value) pairs sorted by name
|
||||||
|
without triggering dynamic lookup via the descriptor protocol,
|
||||||
|
__getattr__ or __getattribute__. Optionally, only return members that
|
||||||
|
satisfy a given predicate.
|
||||||
|
|
||||||
|
Note: this function may not be able to retrieve all members
|
||||||
|
that getmembers can fetch (like dynamically created attributes)
|
||||||
|
and may find members that getmembers can't (like descriptors
|
||||||
|
that raise AttributeError). It can also return descriptor objects
|
||||||
|
instead of instance members in some cases.
|
||||||
|
"""
|
||||||
|
return _getmembers(object, predicate, getattr_static)
|
||||||
|
|
||||||
Attribute = namedtuple('Attribute', 'name kind defining_class object')
|
Attribute = namedtuple('Attribute', 'name kind defining_class object')
|
||||||
|
|
||||||
def classify_class_attrs(cls):
|
def classify_class_attrs(cls):
|
||||||
|
|
|
@ -1215,6 +1215,23 @@ class TestClassesAndFunctions(unittest.TestCase):
|
||||||
self.assertIn(('eggs', 'scrambled'), inspect.getmembers(A))
|
self.assertIn(('eggs', 'scrambled'), inspect.getmembers(A))
|
||||||
self.assertIn(('eggs', 'spam'), inspect.getmembers(A()))
|
self.assertIn(('eggs', 'spam'), inspect.getmembers(A()))
|
||||||
|
|
||||||
|
def test_getmembers_static(self):
|
||||||
|
class A:
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
@types.DynamicClassAttribute
|
||||||
|
def eggs(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
a = A()
|
||||||
|
instance_members = inspect.getmembers_static(a)
|
||||||
|
class_members = inspect.getmembers_static(A)
|
||||||
|
self.assertIn(('name', inspect.getattr_static(a, 'name')), instance_members)
|
||||||
|
self.assertIn(('eggs', inspect.getattr_static(a, 'eggs')), instance_members)
|
||||||
|
self.assertIn(('name', inspect.getattr_static(A, 'name')), class_members)
|
||||||
|
self.assertIn(('eggs', inspect.getattr_static(A, 'eggs')), class_members)
|
||||||
|
|
||||||
def test_getmembers_with_buggy_dir(self):
|
def test_getmembers_with_buggy_dir(self):
|
||||||
class M(type):
|
class M(type):
|
||||||
def __dir__(cls):
|
def __dir__(cls):
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Add :func:`inspect.getmembers_static` , it return all members without
|
||||||
|
triggering dynamic lookup via the descriptor protocol. Patch by Weipeng Hong.
|
Loading…
Reference in New Issue