array: set exception message on failure

When attempting to get a raw array pointer we return nullptr if given a
nullptr, which triggers an error_already_set(), but we haven't set an
exception message, which results in "Unknown internal error".

Callers that want explicit allowing of a nullptr here already handle it
(by clearing the exception after the call).
This commit is contained in:
Jason Rhinelander 2017-04-10 11:05:26 -04:00
parent 257df10ffe
commit 5749b50239
3 changed files with 22 additions and 2 deletions

View File

@ -702,8 +702,10 @@ protected:
/// Create array from any object -- always returns a new reference /// Create array from any object -- always returns a new reference
static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) { static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) {
if (ptr == nullptr) if (ptr == nullptr) {
PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array from a nullptr");
return nullptr; return nullptr;
}
return detail::npy_api::get().PyArray_FromAny_( return detail::npy_api::get().PyArray_FromAny_(
ptr, nullptr, 0, 0, detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr); ptr, nullptr, 0, 0, detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr);
} }
@ -808,8 +810,10 @@ public:
protected: protected:
/// Create array from any object -- always returns a new reference /// Create array from any object -- always returns a new reference
static PyObject *raw_array_t(PyObject *ptr) { static PyObject *raw_array_t(PyObject *ptr) {
if (ptr == nullptr) if (ptr == nullptr) {
PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr");
return nullptr; return nullptr;
}
return detail::npy_api::get().PyArray_FromAny_( return detail::npy_api::get().PyArray_FromAny_(
ptr, dtype::of<T>().release().ptr(), 0, 0, ptr, dtype::of<T>().release().ptr(), 0, 0,
detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr); detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr);

View File

@ -264,4 +264,8 @@ test_initializer numpy_array([](py::module &m) {
sm.def("array_auxiliaries2", [](py::array_t<double> a) { sm.def("array_auxiliaries2", [](py::array_t<double> a) {
return auxiliaries(a, a); return auxiliaries(a, a);
}); });
// Issue #785: Uninformative "Unknown internal error" exception when constructing array from empty object:
sm.def("array_fail_test", []() { return py::array(py::object()); });
sm.def("array_t_fail_test", []() { return py::array_t<double>(py::object()); });
}); });

View File

@ -377,3 +377,15 @@ def test_array_unchecked_dyn_dims(msg):
assert proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32] assert proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
assert proxy_auxiliaries2_dyn(z1) == array_auxiliaries2(z1) assert proxy_auxiliaries2_dyn(z1) == array_auxiliaries2(z1)
def test_array_failure():
from pybind11_tests.array import array_fail_test, array_t_fail_test
with pytest.raises(ValueError) as excinfo:
array_fail_test()
assert str(excinfo.value) == 'cannot create a pybind11::array from a nullptr'
with pytest.raises(ValueError) as excinfo:
array_t_fail_test()
assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr'