Skip to content
17 changes: 14 additions & 3 deletions Lib/test/test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,22 +640,33 @@ class A:
pass
class B:
y = 0
__slots__ = ('z',)
__slots__ = ('z', "foo")

error_msg = "'A' object has no attribute 'x'"
with self.assertRaisesRegex(AttributeError, error_msg):
A().x
with self.assertRaisesRegex(AttributeError, error_msg):
del A().x

error_msg = "'B' object has no attribute 'x'"
error_msg = ("'B' object has no attribute 'x'")
with self.assertRaisesRegex(AttributeError, error_msg):
B().x
with self.assertRaisesRegex(AttributeError, error_msg):
del B().x
with self.assertRaisesRegex(AttributeError, error_msg):
with self.assertRaisesRegex(
AttributeError,
"'B' object has no attribute 'x' and no __dict__ for setting new attributes"
):
B().x = 0

with self.assertRaisesRegex(
AttributeError,
"'B' object has no attribute 'x' and no "
"__dict__ for setting new attributes. Did you mean: 'foo'"
""
):
B().fod = 1

error_msg = "'B' object attribute 'y' is read-only"
with self.assertRaisesRegex(AttributeError, error_msg):
del B().y
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a better, more introspect-able error message when setting attributes on classes without a ``__dict__`` and no slot member for the attribute.
8 changes: 6 additions & 2 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -1546,8 +1546,10 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
if (dictptr == NULL) {
if (descr == NULL) {
PyErr_Format(PyExc_AttributeError,
"'%.100s' object has no attribute '%U'",
"'%.100s' object has no attribute '%U' and no "
"__dict__ for setting new attributes",
tp->tp_name, name);
set_attribute_error_context(obj, name);
}
else {
PyErr_Format(PyExc_AttributeError,
Expand Down Expand Up @@ -1577,9 +1579,11 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
}
else {
PyErr_Format(PyExc_AttributeError,
"'%.100s' object has no attribute '%U'",
"'%.100s' object has no attribute '%U' and no "
"__dict__ for setting new attributes",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find the tests for this bit of code, are there any?

tp->tp_name, name);
}
set_attribute_error_context(obj, name);
}
done:
Py_XDECREF(descr);
Expand Down