From f20c5beb76f96bb3177290584681f038eeeb43e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 16 Sep 2019 23:37:50 +0200 Subject: [PATCH] python: move away from concrete pybind exceptions. Use only py::error_already_set as that's the least heavy of them. Also changed all occurences of "throw" to "raise" so next time I'm doing a prune of all C++ exceptions for good, those are easy to find. --- src/python/corrade/containers.cpp | 110 +++++++++++++++++++++--------- src/python/magnum/gl.cpp | 6 +- src/python/magnum/math.cpp | 12 +++- src/python/magnum/math.matrix.h | 28 +++++--- src/python/magnum/math.vector.h | 39 ++++++----- src/python/magnum/scenegraph.cpp | 7 +- src/python/magnum/scenegraph.h | 6 +- 7 files changed, 140 insertions(+), 68 deletions(-) diff --git a/src/python/corrade/containers.cpp b/src/python/corrade/containers.cpp index 8b7452b..fd6b043 100644 --- a/src/python/corrade/containers.cpp +++ b/src/python/corrade/containers.cpp @@ -27,7 +27,6 @@ #include /* so ArrayView is convertible from python array */ #include #include -#include #include "Corrade/Containers/Python.h" @@ -119,8 +118,10 @@ template void arrayView(py::class_, Containers /* I would test for dimensions here but np.array() sometimes gives 0 for an one-dimensional array so ¯\_(ツ)_/¯ */ - if(buffer.strides && buffer.strides[0] != buffer.itemsize) - throw py::buffer_error{Utility::formatString("expected stride of {} but got {}", buffer.itemsize, buffer.strides[0])}; + if(buffer.strides && buffer.strides[0] != buffer.itemsize) { + PyErr_Format(PyExc_BufferError, "expected stride of %zi but got %zi", buffer.itemsize, buffer.strides[0]); + throw py::error_already_set{}; + } /* reinterpret_borrow converts PyObject* to an (automatically refcounted) py::object. We take the underlying object instead of @@ -141,10 +142,13 @@ template void arrayView(py::class_, Containers return py::bytes(self.data(), self.size()); }, "Convert to bytes") - /* Single item retrieval. Need to throw IndexError in order to allow + /* Single item retrieval. Need to raise IndexError in order to allow iteration: https://docs.python.org/3/reference/datamodel.html#object.__getitem__ */ .def("__getitem__", [](const Containers::ArrayView& self, std::size_t i) { - if(i >= self.size()) throw pybind11::index_error{}; + if(i >= self.size()) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } return self[i]; }, "Value at given position") @@ -169,7 +173,10 @@ template void arrayView(py::class_, Containers template void mutableArrayView(py::class_, Containers::PyArrayViewHolder>>& c) { c .def("__setitem__", [](const Containers::ArrayView& self, std::size_t i, const T& value) { - if(i >= self.size()) throw pybind11::index_error{}; + if(i >= self.size()) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } self[i] = value; }, "Set a value at given position"); } @@ -322,8 +329,10 @@ template void stridedArrayView(py::class_ sizes{reinterpret_cast(buffer.shape)}; Containers::StaticArrayView strides{reinterpret_cast(buffer.strides)}; @@ -379,26 +388,29 @@ template void stridedArrayView(py::class_ void stridedArrayView1D(py::class_, Containers::PyArrayViewHolder>>& c) { c - /* Single item retrieval. Need to throw IndexError in order to allow + /* Single item retrieval. Need to raise IndexError in order to allow iteration: https://docs.python.org/3/reference/datamodel.html#object.__getitem__ */ .def("__getitem__", [](const Containers::StridedArrayView<1, T>& self, std::size_t i) { - if(i >= self.size()) throw pybind11::index_error{}; + if(i >= self.size()) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } return self[i]; }, "Value at given position"); } template void stridedArrayViewND(py::class_, Containers::PyArrayViewHolder>>& c) { c - /* Sub-view retrieval. Need to throw IndexError in order to allow + /* Sub-view retrieval. Need to raise IndexError in order to allow iteration: https://docs.python.org/3/reference/datamodel.html#object.__getitem__ */ .def("__getitem__", [](const Containers::StridedArrayView& self, std::size_t i) { - if(i >= Containers::StridedDimensions{self.size()}[0]) throw pybind11::index_error{}; + if(i >= Containers::StridedDimensions{self.size()}[0]) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } return Containers::pyArrayViewHolder(self[i], pyObjectHolderFor(self).owner); }, "Sub-view at given position") - /* Single-item retrieval. Need to throw IndexError in order to allow - iteration: https://docs.python.org/3/reference/datamodel.html#object.__getitem__ */ - /* Multi-dimensional slicing */ .def("__getitem__", [](const Containers::StridedArrayView& self, const typename DimensionsTuple::Type& slice) { Containers::StridedDimensions starts; @@ -422,39 +434,52 @@ template void stridedArrayViewND(py::class_ void stridedArrayView2D(py::class_, Containers::PyArrayViewHolder>>& c) { c + /* Single-item retrieval. Need to raise IndexError in order to allow + iteration: https://docs.python.org/3/reference/datamodel.html#object.__getitem__ */ .def("__getitem__", [](const Containers::StridedArrayView<2, T>& self, const std::tuple& i) { if(std::get<0>(i) >= self.size()[0] || - std::get<1>(i) >= self.size()[1]) throw py::index_error{}; + std::get<1>(i) >= self.size()[1]) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } return self[std::get<0>(i)][std::get<1>(i)]; }, "Value at given position") .def("transposed", [](const Containers::StridedArrayView<2, T>& self, const std::size_t a, std::size_t b) { if((a == 0 && b == 1) || (a == 1 && b == 0)) return Containers::pyArrayViewHolder(self.template transposed<0, 1>(), pyObjectHolderFor(self).owner); - throw py::value_error{Utility::formatString("dimensions {}, {} can't be transposed in a {}D view", a, b, 2)}; + PyErr_Format(PyExc_ValueError, "dimensions %zu, %zu can't be transposed in a %iD view", a, b, 2); + throw py::error_already_set{}; }, "Transpose two dimensions") .def("flipped", [](const Containers::StridedArrayView<2, T>& self, const std::size_t dimension) { if(dimension == 0) return Containers::pyArrayViewHolder(self.template flipped<0>(), pyObjectHolderFor(self).owner); if(dimension == 1) return Containers::pyArrayViewHolder(self.template flipped<1>(), pyObjectHolderFor(self).owner); - throw py::value_error{Utility::formatString("dimension {} out of range for a {}D view", dimension, 2)}; + PyErr_Format(PyExc_ValueError, "dimension %zu out of range for a %iD view", dimension, 2); + throw py::error_already_set{}; }, "Flip a dimension") .def("broadcasted", [](const Containers::StridedArrayView<2, T>& self, const std::size_t dimension, std::size_t size) { if(dimension == 0) return Containers::pyArrayViewHolder(self.template broadcasted<0>(size), pyObjectHolderFor(self).owner); if(dimension == 1) return Containers::pyArrayViewHolder(self.template broadcasted<1>(size), pyObjectHolderFor(self).owner); - throw py::value_error{Utility::formatString("dimension {} out of range for a {}D view", dimension, 2)}; + PyErr_Format(PyExc_ValueError, "dimension %zu out of range for a %iD view", dimension, 2); + throw py::error_already_set{}; }, "Broadcast a dimension"); } template void stridedArrayView3D(py::class_, Containers::PyArrayViewHolder>>& c) { c + /* Single-item retrieval. Need to raise IndexError in order to allow + iteration: https://docs.python.org/3/reference/datamodel.html#object.__getitem__ */ .def("__getitem__", [](const Containers::StridedArrayView<3, T>& self, const std::tuple& i) { if(std::get<0>(i) >= self.size()[0] || std::get<1>(i) >= self.size()[1] || - std::get<2>(i) >= self.size()[2]) throw pybind11::index_error{}; + std::get<2>(i) >= self.size()[2]) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } return self[std::get<0>(i)][std::get<1>(i)][std::get<2>(i)]; }, "Value at given position") .def("transposed", [](const Containers::StridedArrayView<3, T>& self, const std::size_t a, std::size_t b) { @@ -467,7 +492,8 @@ template void stridedArrayView3D(py::class_(), pyObjectHolderFor(self).owner); - throw py::value_error{Utility::formatString("dimensions {}, {} can't be transposed in a {}D view", a, b, 3)}; + PyErr_Format(PyExc_ValueError, "dimensions %zu, %zu can't be transposed in a %iD view", a, b, 2); + throw py::error_already_set{}; }, "Transpose two dimensions") .def("flipped", [](const Containers::StridedArrayView<3, T>& self, const std::size_t dimension) { if(dimension == 0) @@ -476,7 +502,8 @@ template void stridedArrayView3D(py::class_(), pyObjectHolderFor(self).owner); if(dimension == 2) return Containers::pyArrayViewHolder(self.template flipped<2>(), pyObjectHolderFor(self).owner); - throw py::value_error{Utility::formatString("dimension {} out of range for a {}D view", dimension, 3)}; + PyErr_Format(PyExc_ValueError, "dimension %zu out of range for a %iD view", dimension, 3); + throw py::error_already_set{}; }, "Flip a dimension") .def("broadcasted", [](const Containers::StridedArrayView<3, T>& self, const std::size_t dimension, std::size_t size) { if(dimension == 0) @@ -485,17 +512,23 @@ template void stridedArrayView3D(py::class_(size), pyObjectHolderFor(self).owner); if(dimension == 2) return Containers::pyArrayViewHolder(self.template broadcasted<2>(size), pyObjectHolderFor(self).owner); - throw py::value_error{Utility::formatString("dimension {} out of range for a {}D view", dimension, 3)}; + PyErr_Format(PyExc_ValueError, "dimension %zu out of range for a %iD view", dimension, 3); + throw py::error_already_set{}; }, "Broadcast a dimension"); } template void stridedArrayView4D(py::class_, Containers::PyArrayViewHolder>>& c) { c + /* Single-item retrieval. Need to raise IndexError in order to allow + iteration: https://docs.python.org/3/reference/datamodel.html#object.__getitem__ */ .def("__getitem__", [](const Containers::StridedArrayView<4, T>& self, const std::tuple& i) { if(std::get<0>(i) >= self.size()[0] || std::get<1>(i) >= self.size()[1] || std::get<2>(i) >= self.size()[2] || - std::get<3>(i) >= self.size()[3]) throw pybind11::index_error{}; + std::get<3>(i) >= self.size()[3]) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } return self[std::get<0>(i)][std::get<1>(i)][std::get<2>(i)][std::get<3>(i)]; }, "Value at given position") .def("transposed", [](const Containers::StridedArrayView<4, T>& self, const std::size_t a, std::size_t b) { @@ -517,7 +550,8 @@ template void stridedArrayView4D(py::class_(), pyObjectHolderFor(self).owner); - throw py::value_error{Utility::formatString("dimensions {}, {} can't be transposed in a {}D view", a, b, 4)}; + PyErr_Format(PyExc_ValueError, "dimensions %zu, %zu can't be transposed in a %iD view", a, b, 4); + throw py::error_already_set{}; }, "Transpose two dimensions") .def("flipped", [](const Containers::StridedArrayView<4, T>& self, const std::size_t dimension) { if(dimension == 0) @@ -528,7 +562,8 @@ template void stridedArrayView4D(py::class_(), pyObjectHolderFor(self).owner); if(dimension == 3) return Containers::pyArrayViewHolder(self.template flipped<3>(), pyObjectHolderFor(self).owner); - throw py::value_error{Utility::formatString("dimension {} out of range for a {}D view", dimension, 4)}; + PyErr_Format(PyExc_ValueError, "dimension %zu out of range for a %iD view", dimension, 4); + throw py::error_already_set{}; }, "Flip a dimension") .def("broadcasted", [](const Containers::StridedArrayView<4, T>& self, const std::size_t dimension, std::size_t size) { if(dimension == 0) @@ -539,14 +574,18 @@ template void stridedArrayView4D(py::class_(size), pyObjectHolderFor(self).owner); if(dimension == 3) return Containers::pyArrayViewHolder(self.template broadcasted<3>(size), pyObjectHolderFor(self).owner); - throw py::value_error{Utility::formatString("dimension {} out of range for a {}D view", dimension, 4)}; + PyErr_Format(PyExc_ValueError, "dimension %zu out of range for a %iD view", dimension, 4); + throw py::error_already_set{}; }, "Broadcast a dimension"); } template void mutableStridedArrayView1D(py::class_, Containers::PyArrayViewHolder>>& c) { c .def("__setitem__", [](const Containers::StridedArrayView<1, T>& self, const std::size_t i, const T& value) { - if(i >= self.size()) throw pybind11::index_error{}; + if(i >= self.size()) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } self[i] = value; }, "Set a value at given position"); } @@ -555,7 +594,10 @@ template void mutableStridedArrayView2D(py::class_& self, const std::tuple& i, const T& value) { if(std::get<0>(i) >= self.size()[0] || - std::get<1>(i) >= self.size()[1]) throw pybind11::index_error{}; + std::get<1>(i) >= self.size()[1]) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } self[std::get<0>(i)][std::get<1>(i)] = value; }, "Set a value at given position"); } @@ -565,7 +607,10 @@ template void mutableStridedArrayView3D(py::class_& self, const std::tuple& i, const T& value) { if(std::get<0>(i) >= self.size()[0] || std::get<1>(i) >= self.size()[1] || - std::get<2>(i) >= self.size()[2]) throw pybind11::index_error{}; + std::get<2>(i) >= self.size()[2]) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } self[std::get<0>(i)][std::get<1>(i)][std::get<2>(i)] = value; }, "Set a value at given position"); } @@ -576,7 +621,10 @@ template void mutableStridedArrayView4D(py::class_(i) >= self.size()[0] || std::get<1>(i) >= self.size()[1] || std::get<2>(i) >= self.size()[2] || - std::get<3>(i) >= self.size()[3]) throw pybind11::index_error{}; + std::get<3>(i) >= self.size()[3]) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } self[std::get<0>(i)][std::get<1>(i)][std::get<2>(i)][std::get<3>(i)] = value; }, "Set a value at given position"); } diff --git a/src/python/magnum/gl.cpp b/src/python/magnum/gl.cpp index e46e35a..f7bc2ec 100644 --- a/src/python/magnum/gl.cpp +++ b/src/python/magnum/gl.cpp @@ -26,7 +26,6 @@ #include #include /* for Mesh.buffers */ #include -#include #include #include #include @@ -777,7 +776,10 @@ void gl(py::module& m) { self.setPrimitive(py::cast(primitive)); else if(py::isinstance(primitive)) self.setPrimitive(py::cast(primitive)); - else throw py::type_error{Utility::formatString("expected MeshPrimitive or gl.MeshPrimitive, got {}", std::string(py::str{primitive.get_type()}))}; + else { + PyErr_Format(PyExc_TypeError, "expected MeshPrimitive or gl.MeshPrimitive, got %A", primitive.get_type().ptr()); + throw py::error_already_set{}; + } }, "Primitive type") /* Have to use a lambda because it returns GL::Mesh which is not tracked (unlike PyMesh) */ diff --git a/src/python/magnum/math.cpp b/src/python/magnum/math.cpp index cdb02c5..ad0288a 100644 --- a/src/python/magnum/math.cpp +++ b/src/python/magnum/math.cpp @@ -177,14 +177,20 @@ template void boolVector(py::class_& c) { .def("none", &T::none, "Whether no bits are set") .def("any", &T::any, "Whether any bit is set") - /* Set / get. Need to throw IndexError in order to allow iteration: + /* Set / get. Need to raise IndexError in order to allow iteration: https://docs.python.org/3/reference/datamodel.html#object.__getitem__ */ .def("__setitem__",[](T& self, std::size_t i, bool value) { - if(i >= T::Size) throw pybind11::index_error{}; + if(i >= T::Size) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } self.set(i, value); }, "Set a bit at given position") .def("__getitem__", [](const T& self, std::size_t i) { - if(i >= T::Size) throw pybind11::index_error{}; + if(i >= T::Size) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } return self[i]; }, "Bit at given position") diff --git a/src/python/magnum/math.matrix.h b/src/python/magnum/math.matrix.h index f212b44..08bd8c2 100644 --- a/src/python/magnum/math.matrix.h +++ b/src/python/magnum/math.matrix.h @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -114,11 +113,15 @@ template void everyRectangularMatrixBuffer(py::class_ void everyRectangularMatrixBuffer(py::class_(out, buffer); else if(buffer.format[0] == 'd' && !buffer.format[1]) initFromBuffer(out, buffer); - else throw py::buffer_error{Utility::formatString("expected format f or d but got {}", buffer.format)}; + else { + PyErr_Format(PyExc_BufferError, "expected format f or d but got %s", buffer.format); + throw py::error_already_set{}; + } return out; }), "Construct from a buffer"); @@ -176,7 +182,7 @@ template void rectangularMatrix(py::class_& c) { .def(py::self == py::self, "Equality comparison") .def(py::self != py::self, "Non-equality comparison") - /* Set / get. Need to throw IndexError in order to allow iteration: + /* Set / get. Need to raise IndexError in order to allow iteration: https://docs.python.org/3/reference/datamodel.html#object.__getitem__ Using error_already_set is slightly faster than throwing index_error directly, but still much slower than not throwing at all. Waiting @@ -184,14 +190,14 @@ template void rectangularMatrix(py::class_& c) { .def("__setitem__", [](T& self, std::size_t i, const typename VectorTraits::Type& value) { if(i >= T::Cols) { PyErr_SetString(PyExc_IndexError, ""); - throw pybind11::error_already_set{}; + throw py::error_already_set{}; } self[i] = value; }, "Set a column at given position") .def("__getitem__", [](const T& self, std::size_t i) -> typename VectorTraits::Type { if(i >= T::Cols) { PyErr_SetString(PyExc_IndexError, ""); - throw pybind11::error_already_set{}; + throw py::error_already_set{}; } return self[i]; }, "Column at given position") @@ -200,14 +206,14 @@ template void rectangularMatrix(py::class_& c) { .def("__setitem__", [](T& self, const std::pair& i, typename T::Type value) { if(i.first >= T::Cols || i.second >= T::Rows) { PyErr_SetString(PyExc_IndexError, ""); - throw pybind11::error_already_set{}; + throw py::error_already_set{}; } self[i.first][i.second] = value; }, "Set a value at given col/row") .def("__getitem__", [](const T& self, const std::pair& i) { if(i.first >= T::Cols || i.second >= T::Rows) { PyErr_SetString(PyExc_IndexError, ""); - throw pybind11::error_already_set{}; + throw py::error_already_set{}; } return self[i.first][i.second]; }, "Value at given col/row") diff --git a/src/python/magnum/math.vector.h b/src/python/magnum/math.vector.h index 7b425af..b35e4ef 100644 --- a/src/python/magnum/math.vector.h +++ b/src/python/magnum/math.vector.h @@ -27,7 +27,6 @@ #include #include -#include #include #include @@ -142,15 +141,21 @@ template void everyVectorBuffer(py::class_& Containers::ScopeGuard e{&buffer, PyBuffer_Release}; - if(buffer.ndim != 1) - throw py::buffer_error{Utility::formatString("expected 1 dimension but got {}", buffer.ndim)}; + if(buffer.ndim != 1) { + PyErr_Format(PyExc_BufferError, "expected 1 dimension but got %i", buffer.ndim); + throw py::error_already_set{}; + } - if(buffer.shape[0] != T::Size) - throw py::buffer_error{Utility::formatString("expected {} elements but got {}", T::Size, buffer.shape[0])}; + if(buffer.shape[0] != T::Size) { + PyErr_Format(PyExc_BufferError, "expected %zu elements but got %zi", T::Size, buffer.shape[0]); + throw py::error_already_set{}; + } /* Expecting just an one-letter format */ - if(!buffer.format[0] || buffer.format[1] || !isTypeCompatible(buffer.format[0])) - throw py::buffer_error{Utility::formatString("unexpected format {} for a {} vector", buffer.format, FormatStrings[formatIndex()])}; + if(!buffer.format[0] || buffer.format[1] || !isTypeCompatible(buffer.format[0])) { + PyErr_Format(PyExc_BufferError, "unexpected format %s for a %s vector", buffer.format, FormatStrings[formatIndex()]); + throw py::error_already_set{}; + } T out{Math::NoInit}; initFromBuffer(out, buffer); @@ -208,7 +213,7 @@ template void vector(py::module& m, py::class_& c) { .def(py::self <= py::self, "Component-wise less than or equal comparison") .def(py::self >= py::self, "Component-wise greater than or equal comparison") - /* Set / get. Need to throw IndexError in order to allow iteration: + /* Set / get. Need to raise IndexError in order to allow iteration: https://docs.python.org/3/reference/datamodel.html#object.__getitem__ Using error_already_set is slightly faster than throwing index_error directly, but still much slower than not throwing at all. Waiting @@ -216,14 +221,14 @@ template void vector(py::module& m, py::class_& c) { .def("__setitem__", [](T& self, std::size_t i, typename T::Type value) { if(i >= T::Size) { PyErr_SetString(PyExc_IndexError, ""); - throw pybind11::error_already_set{}; + throw py::error_already_set{}; } self[i] = value; }, "Set a value at given position") .def("__getitem__", [](const T& self, std::size_t i) { if(i >= T::Size) { PyErr_SetString(PyExc_IndexError, ""); - throw pybind11::error_already_set{}; + throw py::error_already_set{}; } return self[i]; }, "Value at given position") @@ -235,7 +240,7 @@ template void vector(py::module& m, py::class_& c) { .def("__getattr__", [](T& self, const std::string& name) -> py::object { if(name.size() > 4) { PyErr_SetString(PyExc_AttributeError, "only four-component swizzles are supported at most"); - throw pybind11::error_already_set{}; + throw py::error_already_set{}; } Math::Vector4 out; @@ -246,7 +251,7 @@ template void vector(py::module& m, py::class_& c) { else if(T::Size > 3 && (name[i] == 'w' || name[i] == 'a')) out[i] = self[3]; else { PyErr_SetString(PyExc_AttributeError, "invalid swizzle"); - throw pybind11::error_already_set{}; + throw py::error_already_set{}; } } @@ -268,11 +273,11 @@ template void vector(py::module& m, py::class_& c) { (name.compare("rgb") == 0 && T::Size > 3) || name.find_first_not_of("xyzwrgba") != std::string::npos) { if(PySuper_Type.tp_setattro(py::cast(self).ptr(), nameO.ptr(), valueO.ptr()) != 0) - throw pybind11::error_already_set{}; + throw py::error_already_set{}; return; } - /* Here we can be certain it's a swizzle attempt, so throw clear + /* Here we can be certain it's a swizzle attempt, so raise clear error messages */ const typename T::Type* data; std::size_t size; @@ -287,12 +292,12 @@ template void vector(py::module& m, py::class_& c) { size = 4; } else { PyErr_SetString(PyExc_TypeError, "unrecognized swizzle type"); - throw pybind11::error_already_set{}; + throw py::error_already_set{}; } if(name.size() != size) { PyErr_SetString(PyExc_TypeError, "swizzle doesn't match passed vector component count"); - throw pybind11::error_already_set{}; + throw py::error_already_set{}; } for(std::size_t i = 0; i != name.size(); ++i) { if(name[i] == 'x' || name[i] == 'r') self[0] = data[i]; @@ -301,7 +306,7 @@ template void vector(py::module& m, py::class_& c) { else if(T::Size > 3 && (name[i] == 'w' || name[i] == 'a')) self[3] = data[i]; else { PyErr_SetString(PyExc_AttributeError, "invalid swizzle"); - throw pybind11::error_already_set{}; + throw py::error_already_set{}; } } }, "Vector swizzle") diff --git a/src/python/magnum/scenegraph.cpp b/src/python/magnum/scenegraph.cpp index 28137bc..cb3c71d 100644 --- a/src/python/magnum/scenegraph.cpp +++ b/src/python/magnum/scenegraph.cpp @@ -64,10 +64,13 @@ template void f .def("__len__", &SceneGraph::FeatureGroup::size, "Count of features in the group") /* Get item. Fetching the already registered instance and returning - that instead of wrapping the pointer again. Need to throw IndexError + that instead of wrapping the pointer again. Need to raise IndexError in order to allow iteration: https://docs.python.org/3/reference/datamodel.html#object.__getitem__ */ .def("__getitem__", [](SceneGraph::FeatureGroup& self, std::size_t index) -> PyFeature& { - if(index >= self.size()) throw pybind11::index_error{}; + if(index >= self.size()) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } return static_cast(self[index]); }, "Feature at given index") .def("add", [](SceneGraph::FeatureGroup& self, PyFeature& feature) { diff --git a/src/python/magnum/scenegraph.h b/src/python/magnum/scenegraph.h index 135cdce..d579790 100644 --- a/src/python/magnum/scenegraph.h +++ b/src/python/magnum/scenegraph.h @@ -26,7 +26,6 @@ */ #include -#include #include #include @@ -61,7 +60,10 @@ template void object(py:: parent = py::cast*>(parentobj); else if(py::isinstance(parentobj)) parent = nullptr; - else throw py::type_error{Utility::formatString("expected Scene, Object or None, got {}", std::string(py::str{parentobj.get_type()}))}; + else { + PyErr_Format(PyExc_TypeError, "expected Scene, Object or None, got %A", parentobj.get_type().ptr()); + throw py::error_already_set{}; + } /* Decrease refcount if a parent is removed, increase it if a parent gets added */