Skip to content

Commit f783428

Browse files
authored
bpo-44655: Include the name of the type in unset __slots__ attribute errors (GH-27199)
1 parent 6714dec commit f783428

File tree

3 files changed

+17
-4
lines changed

3 files changed

+17
-4
lines changed

Lib/test/test_descr.py

+6
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,12 @@ class X(object):
13031303
with self.assertRaises(AttributeError):
13041304
del X().a
13051305

1306+
# Inherit from object on purpose to check some backwards compatibility paths
1307+
class X(object):
1308+
__slots__ = "a"
1309+
with self.assertRaisesRegex(AttributeError, "'X' object has no attribute 'a'"):
1310+
X().a
1311+
13061312
def test_slots_special(self):
13071313
# Testing __dict__ and __weakref__ in __slots__...
13081314
class D(object):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Include the name of the type in unset __slots__ attribute errors. Patch by
2+
Pablo Galindo

Python/structmember.c

+9-4
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
#include "structmember.h" // PyMemberDef
66

77
PyObject *
8-
PyMember_GetOne(const char *addr, PyMemberDef *l)
8+
PyMember_GetOne(const char *obj_addr, PyMemberDef *l)
99
{
1010
PyObject *v;
1111

12-
addr += l->offset;
12+
const char* addr = obj_addr + l->offset;
1313
switch (l->type) {
1414
case T_BOOL:
1515
v = PyBool_FromLong(*(char*)addr);
@@ -69,8 +69,13 @@ PyMember_GetOne(const char *addr, PyMemberDef *l)
6969
break;
7070
case T_OBJECT_EX:
7171
v = *(PyObject **)addr;
72-
if (v == NULL)
73-
PyErr_SetString(PyExc_AttributeError, l->name);
72+
if (v == NULL) {
73+
PyObject *obj = (PyObject *)obj_addr;
74+
PyTypeObject *tp = Py_TYPE(obj);
75+
PyErr_Format(PyExc_AttributeError,
76+
"'%.200s' object has no attribute '%s'",
77+
tp->tp_name, l->name);
78+
}
7479
Py_XINCREF(v);
7580
break;
7681
case T_LONGLONG:

0 commit comments

Comments
 (0)