Mailing List Archive

bpo-30533:Add function inspect.getmembers_static that does not call properties or dynamic properties. (#20911)
https://github.com/python/cpython/commit/af8c8caaf5e07c02202d736a31f6a2f7e27819b8
commit: af8c8caaf5e07c02202d736a31f6a2f7e27819b8
branch: main
author: Weipeng Hong <hongweichen8888@sina.com>
committer: DinoV <dinoviehland@gmail.com>
date: 2021-11-30T10:23:13-08:00
summary:

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>

files:
A Misc/NEWS.d/next/Library/2020-06-16-18-00-56.bpo-30533.StL57t.rst
M Lib/inspect.py
M Lib/test/test_inspect.py

diff --git a/Lib/inspect.py b/Lib/inspect.py
index dd891112570c6..1eb2f2b575ef4 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -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):
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index d43486a219158..33665cf3c79eb 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -1215,6 +1215,23 @@ def eggs(self):
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):
diff --git a/Misc/NEWS.d/next/Library/2020-06-16-18-00-56.bpo-30533.StL57t.rst b/Misc/NEWS.d/next/Library/2020-06-16-18-00-56.bpo-30533.StL57t.rst
new file mode 100644
index 0000000000000..bc4523f626666
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-06-16-18-00-56.bpo-30533.StL57t.rst
@@ -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.

_______________________________________________
Python-checkins mailing list
Python-checkins@python.org
https://mail.python.org/mailman/listinfo/python-checkins