From 37ae52a1922a3313fcbb14b363dca4cc293e0678 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Fri, 16 Jul 2021 21:34:50 +0100 Subject: [PATCH 1/3] bpo-44655: Include the name of the type in unset __slots__ attribute errors --- Lib/test/test_descr.py | 5 +++++ .../2021-07-16-21-35-14.bpo-44655.95I7M6.rst | 2 ++ Python/structmember.c | 13 +++++++++---- 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-07-16-21-35-14.bpo-44655.95I7M6.rst diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 0ff4d022586e18..23f226af7eb8b4 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1303,6 +1303,11 @@ class X(object): with self.assertRaises(AttributeError): del X().a + class X(object): + __slots__ = "a" + with self.assertRaisesRegex(AttributeError, "'X' object has no attribute 'a'"): + X().a + def test_slots_special(self): # Testing __dict__ and __weakref__ in __slots__... class D(object): diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-07-16-21-35-14.bpo-44655.95I7M6.rst b/Misc/NEWS.d/next/Core and Builtins/2021-07-16-21-35-14.bpo-44655.95I7M6.rst new file mode 100644 index 00000000000000..17733b3619a8f3 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-07-16-21-35-14.bpo-44655.95I7M6.rst @@ -0,0 +1,2 @@ +Include the name of the type in unset __slots__ attribute errors. Patch by +Pablo Galindo diff --git a/Python/structmember.c b/Python/structmember.c index ba88e15f938691..bd6299ff979d6b 100644 --- a/Python/structmember.c +++ b/Python/structmember.c @@ -5,11 +5,11 @@ #include "structmember.h" // PyMemberDef PyObject * -PyMember_GetOne(const char *addr, PyMemberDef *l) +PyMember_GetOne(const char *obj_addr, PyMemberDef *l) { PyObject *v; - addr += l->offset; + const char* addr = obj_addr + l->offset; switch (l->type) { case T_BOOL: v = PyBool_FromLong(*(char*)addr); @@ -69,8 +69,13 @@ PyMember_GetOne(const char *addr, PyMemberDef *l) break; case T_OBJECT_EX: v = *(PyObject **)addr; - if (v == NULL) - PyErr_SetString(PyExc_AttributeError, l->name); + if (v == NULL) { + PyObject *obj = (PyObject *)obj_addr; + PyTypeObject *tp = Py_TYPE(obj); + PyErr_Format(PyExc_AttributeError, + "'%.50s' object has no attribute '%s'", + tp->tp_name, l->name); + } Py_XINCREF(v); break; case T_LONGLONG: From e6ff15adf424b28b4d0441ffd5706bdd2d9ba58d Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Fri, 16 Jul 2021 22:23:40 +0100 Subject: [PATCH 2/3] fixup! bpo-44655: Include the name of the type in unset __slots__ attribute errors --- Python/structmember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/structmember.c b/Python/structmember.c index bd6299ff979d6b..c7e318811d82b8 100644 --- a/Python/structmember.c +++ b/Python/structmember.c @@ -73,7 +73,7 @@ PyMember_GetOne(const char *obj_addr, PyMemberDef *l) PyObject *obj = (PyObject *)obj_addr; PyTypeObject *tp = Py_TYPE(obj); PyErr_Format(PyExc_AttributeError, - "'%.50s' object has no attribute '%s'", + "'%.200s' object has no attribute '%s'", tp->tp_name, l->name); } Py_XINCREF(v); From 195db091d0c8a44a3e5f422fb43777540fc86641 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Fri, 16 Jul 2021 22:50:27 +0100 Subject: [PATCH 3/3] fixup! fixup! bpo-44655: Include the name of the type in unset __slots__ attribute errors --- Lib/test/test_descr.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 23f226af7eb8b4..71b6954b6fca35 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1303,6 +1303,7 @@ class X(object): with self.assertRaises(AttributeError): del X().a + # Inherit from object on purpose to check some backwards compatibility paths class X(object): __slots__ = "a" with self.assertRaisesRegex(AttributeError, "'X' object has no attribute 'a'"):