summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Galindo Salgado <Pablogsal@gmail.com>2021-07-16 23:34:46 (GMT)
committerGitHub <noreply@github.com>2021-07-16 23:34:46 (GMT)
commitf783428a2313a729ca8b539c5a86ff114b9ff375 (patch)
tree0a7544bd351ea47745d7406bc1adba01e63f9681
parent6714dec5e104bdee4a0ed4d9966de27d1bfa1e3d (diff)
downloadcpython-f783428a2313a729ca8b539c5a86ff114b9ff375.zip
cpython-f783428a2313a729ca8b539c5a86ff114b9ff375.tar.gz
cpython-f783428a2313a729ca8b539c5a86ff114b9ff375.tar.bz2
bpo-44655: Include the name of the type in unset __slots__ attribute errors (GH-27199)
-rw-r--r--Lib/test/test_descr.py6
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2021-07-16-21-35-14.bpo-44655.95I7M6.rst2
-rw-r--r--Python/structmember.c13
3 files changed, 17 insertions, 4 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 0ff4d02..71b6954 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -1303,6 +1303,12 @@ order (MRO) for bases """
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'"):
+ 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 0000000..17733b3
--- /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 ba88e15..c7e3188 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,
+ "'%.200s' object has no attribute '%s'",
+ tp->tp_name, l->name);
+ }
Py_XINCREF(v);
break;
case T_LONGLONG: