Issue #28214: Improved exception reporting for problematic __set_name__

attributes.
This commit is contained in:
Serhiy Storchaka 2016-10-21 17:13:31 +03:00
parent 467ab194fc
commit d5d32d2127
3 changed files with 28 additions and 8 deletions

View File

@ -133,20 +133,32 @@ class Test(unittest.TestCase):
def test_set_name_error(self): def test_set_name_error(self):
class Descriptor: class Descriptor:
def __set_name__(self, owner, name): def __set_name__(self, owner, name):
raise RuntimeError 1/0
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError) as cm:
class A: class NotGoingToWork:
d = Descriptor() attr = Descriptor()
exc = cm.exception
self.assertRegex(str(exc), r'\bNotGoingToWork\b')
self.assertRegex(str(exc), r'\battr\b')
self.assertRegex(str(exc), r'\bDescriptor\b')
self.assertIsInstance(exc.__cause__, ZeroDivisionError)
def test_set_name_wrong(self): def test_set_name_wrong(self):
class Descriptor: class Descriptor:
def __set_name__(self): def __set_name__(self):
pass pass
with self.assertRaises(TypeError): with self.assertRaises(RuntimeError) as cm:
class A: class NotGoingToWork:
d = Descriptor() attr = Descriptor()
exc = cm.exception
self.assertRegex(str(exc), r'\bNotGoingToWork\b')
self.assertRegex(str(exc), r'\battr\b')
self.assertRegex(str(exc), r'\bDescriptor\b')
self.assertIsInstance(exc.__cause__, TypeError)
def test_set_name_lookup(self): def test_set_name_lookup(self):
resolved = [] resolved = []

View File

@ -10,6 +10,9 @@ What's New in Python 3.6.0 beta 3
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #28214: Improved exception reporting for problematic __set_name__
attributes.
- Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception - Issue #23782: Fixed possible memory leak in _PyTraceback_Add() and exception
loss in PyTraceBack_Here(). loss in PyTraceBack_Here().

View File

@ -7022,8 +7022,13 @@ set_names(PyTypeObject *type)
if (set_name != NULL) { if (set_name != NULL) {
tmp = PyObject_CallFunctionObjArgs(set_name, type, key, NULL); tmp = PyObject_CallFunctionObjArgs(set_name, type, key, NULL);
Py_DECREF(set_name); Py_DECREF(set_name);
if (tmp == NULL) if (tmp == NULL) {
_PyErr_FormatFromCause(PyExc_RuntimeError,
"Error calling __set_name__ on '%.100s' instance %R "
"in '%.100s'",
value->ob_type->tp_name, key, type->tp_name);
return -1; return -1;
}
else else
Py_DECREF(tmp); Py_DECREF(tmp);
} }