with self.assertRaises(TypeError):
type.__setattr__(A, b'x', None)
+ def testTypeAttributeAccessErrorMessages(self):
+ class A:
+ pass
+
+ error_msg = "type object 'A' has no attribute 'x'"
+ with self.assertRaisesRegex(AttributeError, error_msg):
+ A.x
+ with self.assertRaisesRegex(AttributeError, error_msg):
+ del A.x
+
+ def testObjectAttributeAccessErrorMessages(self):
+ class A:
+ pass
+ class B:
+ y = 0
+ __slots__ = ('z',)
+
+ 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'"
+ with self.assertRaisesRegex(AttributeError, error_msg):
+ B().x
+ with self.assertRaisesRegex(AttributeError, error_msg):
+ del B().x
+ with self.assertRaisesRegex(AttributeError, error_msg):
+ B().x = 0
+
+ error_msg = "'B' object attribute 'y' is read-only"
+ with self.assertRaisesRegex(AttributeError, error_msg):
+ del B().y
+ with self.assertRaisesRegex(AttributeError, error_msg):
+ B().y = 0
+
+ error_msg = 'z'
+ with self.assertRaisesRegex(AttributeError, error_msg):
+ B().z
+ with self.assertRaisesRegex(AttributeError, error_msg):
+ del B().z
+
def testConstructorErrorMessages(self):
# bpo-31506: Improves the error message logic for object_new & object_init
values->values[ix] = value;
if (old_value == NULL) {
if (value == NULL) {
- PyErr_SetObject(PyExc_AttributeError, name);
+ PyErr_Format(PyExc_AttributeError,
+ "'%.100s' object has no attribute '%U'",
+ Py_TYPE(obj)->tp_name, name);
return -1;
}
_PyDictValues_AddToInsertionOrder(values, ix);
return -1;
Py_INCREF(name);
-
+ Py_INCREF(tp);
descr = _PyType_Lookup(tp, name);
if (descr != NULL) {
res = PyDict_SetItem(dict, name, value);
Py_DECREF(dict);
}
- if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
- PyErr_SetObject(PyExc_AttributeError, name);
-
+ if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) {
+ if (PyType_IsSubtype(tp, &PyType_Type)) {
+ PyErr_Format(PyExc_AttributeError,
+ "type object '%.50s' has no attribute '%U'",
+ ((PyTypeObject*)obj)->tp_name, name);
+ }
+ else {
+ PyErr_Format(PyExc_AttributeError,
+ "'%.100s' object has no attribute '%U'",
+ tp->tp_name, name);
+ }
+ }
done:
Py_XDECREF(descr);
+ Py_DECREF(tp);
Py_DECREF(name);
return res;
}