Skip to content

Commit

Permalink
py/objtype: Don't delegate lookup of descriptor methods to __getattr__.
Browse files Browse the repository at this point in the history
When descriptors are enabled, lookup of the `__get__`, `__set__` and
`__delete__` descriptor methods should not be delegated to `__getattr__`.
That follows CPython behaviour.

Signed-off-by: Damien George <[email protected]>
  • Loading branch information
dpgeorge committed Oct 16, 2024
1 parent 3fecab5 commit 1b89c50
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 0 deletions.
7 changes: 7 additions & 0 deletions py/objtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,13 @@ static void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des

// try __getattr__
if (attr != MP_QSTR___getattr__) {
#if MICROPY_PY_DESCRIPTORS
// With descriptors enabled, don't delegate lookups of __get__/__set__/__delete__.
if (attr == MP_QSTR___get__ || attr == MP_QSTR___set__ || attr == MP_QSTR___delete__) {
return;
}
#endif

#if MICROPY_PY_DELATTR_SETATTR
// If the requested attr is __setattr__/__delattr__ then don't delegate the lookup
// to __getattr__. If we followed CPython's behaviour then __setattr__/__delattr__
Expand Down
27 changes: 27 additions & 0 deletions tests/basics/class_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,41 @@ class Main:
try:
m.__class__
except AttributeError:
# Target doesn't support __class__.
print("SKIP")
raise SystemExit

r = m.Forward
if 'Descriptor' in repr(r.__class__):
# Target doesn't support descriptors.
print('SKIP')
raise SystemExit

# Test assignment and deletion.

print(r)
m.Forward = 'a'
del m.Forward

# Test that lookup of descriptors like __get__ are not passed into __getattr__.


class NonDescriptor:
def __getattr__(self, attr):
print("getattr", attr)


class TestClass:
non_descriptor = NonDescriptor()


print(isinstance(TestClass().non_descriptor, NonDescriptor))

t = TestClass()
t.non_descriptor = 123
print(t.non_descriptor)

try:
del TestClass().non_descriptor
except AttributeError:
print("AttributeError")

0 comments on commit 1b89c50

Please sign in to comment.