← index #6600PR #15940
Related · high · value 0.139
QUERY · ISSUE

py/objtype.c: Issue with bytecode cache invalidation and incorrect lookup order for descriptors.

openby jimmoopened 2020-11-05updated 2020-12-07

@pmp-p referenced https://bugs.python.org/issue42266 on the IRC channel. For context on that bug, what they're saying is that the Python 3.8 behavior is correct (i.e. prints 2) and Python 3.10's caching breaks it (and it prints 1, because f(o) is caching the lookup of o.x, without using the descriptor).

MicroPython also has the same bug, but also it looks like our implementation of descriptor lookup is also incorrect in this case and it still does the wrong thing with bytecode lookup caching disabled. A simpler repro for MicroPython is:

class Descriptor:
    pass

class C:
    x = Descriptor()

    def __init__(self):
        self.x = 1

o = C()

Descriptor.__get__ = lambda *args: 2
Descriptor.__set__ = lambda *args: None

print(o.x)

In CPython (3.8), the behavior is that the o.x on the last line (as per https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance) will first see that type(o).x is a descriptor, and use that instead of o.x. MicroPython doesn't do that -- mp_obj_instance_load_attr will return immediately with the result of mp_map_lookup(&self->members...) and only after that look up the type's members.

Additionally, setting the __get__ property on Descriptor will not set MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS on C, so the extra descriptor behavior will not apply on type(o).

And finally, just like CPython 3.10, if bytecode lookup caching is enabled, o.x will bypass all of this and use the cached value anyway.

CANDIDATE · PULL REQUEST

py/objtype: Don't delegate lookup of descriptor methods to __getattr__.

mergedby dpgeorgeopened 2024-10-01updated 2024-10-16
py-core

Summary

When descriptors are enabled, lookup of the __get__, __set__ and __delete__ descriptor methods should not be delegated to __getattr__. That follows CPython behaviour.

Issue initially found by @ntoll.

Testing

Added a test for these cases.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied