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 False
|
||||
|
||||
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."""
|
||||
def _getmembers(object, predicate, getter):
|
||||
if isclass(object):
|
||||
mro = (object,) + getmro(object)
|
||||
else:
|
||||
|
@ -465,7 +463,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 = getter(object, key)
|
||||
# handle the duplicate key
|
||||
if key in processed:
|
||||
raise AttributeError
|
||||
|
@ -484,6 +482,25 @@ def getmembers(object, predicate=None):
|
|||
results.sort(key=lambda pair: pair[0])
|
||||
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')
|
||||
|
||||
def classify_class_attrs(cls):
|
||||
|
|
|
@ -1215,6 +1215,23 @@ class TestClassesAndFunctions(unittest.TestCase):
|
|||
self.assertIn(('eggs', 'scrambled'), 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):
|
||||
class M(type):
|
||||
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