mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Issue 9732: fetch the method resolution order from the type metaclass directly in getattr_static
This commit is contained in:
parent
6bb9989ae3
commit
e516265bbc
3 changed files with 28 additions and 21 deletions
|
@ -587,26 +587,14 @@ but avoids executing code when it fetches attributes.
|
||||||
that raise AttributeError). It can also return descriptors objects
|
that raise AttributeError). It can also return descriptors objects
|
||||||
instead of instance members.
|
instead of instance members.
|
||||||
|
|
||||||
There are several cases that will break `getattr_static` or be handled
|
The only known case that can cause `getattr_static` to trigger code execution,
|
||||||
incorrectly. These are pathological enough not to worry about (i.e. if you do
|
and cause it to return incorrect results (or even break), is where a class uses
|
||||||
any of these then you deserve to have everything break anyway):
|
:data:`~object.__slots__` and provides a `__dict__` member using a property or
|
||||||
|
descriptor. If you find other cases please report them so they can be fixed
|
||||||
|
or documented.
|
||||||
|
|
||||||
* :data:`~object.__dict__` existing (e.g. as a property) but returning the
|
`getattr_static` does not resolve descriptors, for example slot descriptors or
|
||||||
wrong dictionary or even returning something other than a
|
getset descriptors on objects implemented in C. The descriptor object
|
||||||
dictionary
|
|
||||||
* classes created with :data:`~object.__slots__` that have the `__slots__`
|
|
||||||
member deleted from the class, or a fake `__slots__` attribute
|
|
||||||
attached to the instance, or any other monkeying with
|
|
||||||
`__slots__`
|
|
||||||
* type objects that lie about their :term:`MRO`
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Classes that override :data:`~object.__mro__` as a property will have this
|
|
||||||
code executed by `getattr_static`.
|
|
||||||
|
|
||||||
Descriptors are not resolved (for example slot descriptors or
|
|
||||||
getset descriptors on objects implemented in C). The descriptor
|
|
||||||
is returned instead of the underlying attribute.
|
is returned instead of the underlying attribute.
|
||||||
|
|
||||||
You can handle these with code like the following. Note that
|
You can handle these with code like the following. Note that
|
||||||
|
|
|
@ -1060,6 +1060,9 @@ def trace(context=1):
|
||||||
|
|
||||||
_sentinel = object()
|
_sentinel = object()
|
||||||
|
|
||||||
|
def _static_getmro(klass):
|
||||||
|
return type.__dict__['__mro__'].__get__(klass)
|
||||||
|
|
||||||
def _check_instance(obj, attr):
|
def _check_instance(obj, attr):
|
||||||
instance_dict = {}
|
instance_dict = {}
|
||||||
try:
|
try:
|
||||||
|
@ -1070,7 +1073,7 @@ def _check_instance(obj, attr):
|
||||||
|
|
||||||
|
|
||||||
def _check_class(klass, attr):
|
def _check_class(klass, attr):
|
||||||
for entry in getmro(klass):
|
for entry in _static_getmro(klass):
|
||||||
try:
|
try:
|
||||||
return entry.__dict__[attr]
|
return entry.__dict__[attr]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -1110,7 +1113,7 @@ def getattr_static(obj, attr, default=_sentinel):
|
||||||
|
|
||||||
if obj is klass:
|
if obj is klass:
|
||||||
# for types we check the metaclass too
|
# for types we check the metaclass too
|
||||||
for entry in getmro(type(klass)):
|
for entry in _static_getmro(type(klass)):
|
||||||
try:
|
try:
|
||||||
return entry.__dict__[attr]
|
return entry.__dict__[attr]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
|
@ -867,6 +867,22 @@ class TestGetattrStatic(unittest.TestCase):
|
||||||
self.assertEqual(inspect.getattr_static(Something(), 'foo'), 3)
|
self.assertEqual(inspect.getattr_static(Something(), 'foo'), 3)
|
||||||
self.assertEqual(inspect.getattr_static(Something, 'foo'), 3)
|
self.assertEqual(inspect.getattr_static(Something, 'foo'), 3)
|
||||||
|
|
||||||
|
def test_mro_as_property(self):
|
||||||
|
class Meta(type):
|
||||||
|
@property
|
||||||
|
def __mro__(self):
|
||||||
|
return (object,)
|
||||||
|
|
||||||
|
class Base(object):
|
||||||
|
foo = 3
|
||||||
|
|
||||||
|
class Something(Base, metaclass=Meta):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.assertEqual(inspect.getattr_static(Something(), 'foo'), 3)
|
||||||
|
self.assertEqual(inspect.getattr_static(Something, 'foo'), 3)
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
run_unittest(
|
run_unittest(
|
||||||
TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases,
|
TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue