8000 ENH: Chain exceptions to give better error messages for invalid PEP3118 format strings by eric-wieser · Pull Request #11119 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content
Merged
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions numpy/core/include/numpy/npy_3kcompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,38 @@ npy_PyFile_CloseFile(PyObject *file)
return 0;
}


/* This is a copy of _PyErr_ChainExceptions, with:
* - a minimal implementation for python 2
* - __cause__ used instead of __context__
*/
static NPY_INLINE void
npy_PyErr_ChainExceptionsCause(PyObject *exc, PyObject *val, PyObject *tb)
{
if (exc == NULL)
return;

if (PyErr_Occurred()) {
/* only py3 supports this anyway */
#ifdef NPY_PY3K
PyObject *exc2, *val2, *tb2;
PyErr_Fetch(&exc2, &val2, &tb2);
PyErr_NormalizeException(&exc, &val, &tb);
if (tb != NULL) {
PyException_SetTraceback(val, tb);
Py_DECREF(tb);
}
Py_DECREF(exc);
PyErr_NormalizeException(&exc2, &val2, &tb2);
PyException_SetCause(val2, val);
PyErr_Restore(exc2, val2, tb2);
#endif
}
else {
PyErr_Restore(exc, val, tb);
}
}

/*
* PyObject_Cmp
*/
Expand Down
35 changes: 2 additions & 33 deletions numpy/core/src/multiarray/arrayobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1218,37 +1218,6 @@ _void_compare(PyArrayObject *self, PyArrayObject *other, int cmp_op)
}
}

/* This is a copy of _PyErr_ChainExceptions, with:
* - a minimal implementation for python 2
* - __cause__ used instead of __context__
*/
NPY_NO_EXPORT void
PyArray_ChainExceptionsCause(PyObject *exc, PyObject *val, PyObject *tb)
{
if (exc == NULL)
return;

if (PyErr_Occurred()) {
/* only py3 supports this anyway */
#ifdef NPY_PY3K
PyObject *exc2, *val2, *tb2;
PyErr_Fetch(&exc2, &val2, &tb2);
PyErr_NormalizeException(&exc, &val, &tb);
if (tb != NULL) {
PyException_SetTraceback(val, tb);
Py_DECREF(tb);
}
Py_DECREF(exc);
PyErr_NormalizeException(&exc2, &val2, &tb2);
PyException_SetCause(val2, val);
PyErr_Restore(exc2, val2, tb2);
#endif
}
else {
PyErr_Restore(exc, val, tb);
}
}

/*
* Silence the current error and emit a deprecation warning instead.
*
Expand All @@ -1260,7 +1229,7 @@ DEPRECATE_silence_error(const char *msg) {
PyObject *exc, *val, *tb;
PyErr_Fetch(&exc, &val, &tb);
if (DEPRECATE(msg) < 0) {
PyArray_ChainExceptionsCause(exc, val, tb);
npy_PyErr_ChainExceptionsCause(exc, val, tb);
return -1;
}
Py_XDECREF(exc);
Expand Down Expand Up @@ -1377,7 +1346,7 @@ _failed_comparison_workaround(PyArrayObject *self, PyObject *other, int cmp_op)
/*
* Reraise the original exception, possibly chaining with a new one.
*/
PyArray_ChainExceptionsCause(exc, val, tb);
npy_PyErr_ChainExceptionsCause(exc, val, tb);
return NULL;
}

Expand Down
3 changes: 3 additions & 0 deletions numpy/core/src/multiarray/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -989,8 +989,11 @@ _descriptor_from_pep3118_format(char *s)
Py_DECREF(str);
Py_DECREF(_numpy_internal);
if (descr == NULL) {
PyObject *exc, *val, *tb;
PyErr_Fetch(&exc, &val, &tb);
PyErr_Format(PyExc_ValueError,
"'%s' is not a valid PEP 3118 buffer format string", buf);
npy_PyErr_ChainExceptionsCause(exc, val, tb);
free(buf);
return NULL;
}
Expand Down
12 changes: 12 additions & 0 deletions numpy/core/tests/test_multiarray.py
3A3C
Original file line number Diff line number Diff line change
Expand Up @@ -6662,6 +6662,18 @@ def test_error_pointer_type(self):
ValueError, "format string",
np.array, m)

def test_error_message(self):
# wchar has no corresponding numpy type - if this changes in future, we
# need a better way to construct an invalid memoryview format.
t = ctypes.c_wchar * 4
with assert_raises(ValueError) as cm:
np.array(t())

exc = cm.exception
if sys.version_info.major > 2:
with assert_raises_regex(ValueError, "Unknown .* specifier 'u'"):
raise exc.__cause__

def test_ctypes_integer_via_memoryview(self):
# gh-11150, due to bpo-10746
for c_integer in {ctypes.c_int, ctypes.c_long, ctypes.c_longlong}:
Expand Down
0