Browse Source

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.
pull/8/head
Vladimír Vondruš 7 years ago
parent
commit
f20c5beb76
  1. 110
      src/python/corrade/containers.cpp
  2. 6
      src/python/magnum/gl.cpp
  3. 12
      src/python/magnum/math.cpp
  4. 28
      src/python/magnum/math.matrix.h
  5. 39
      src/python/magnum/math.vector.h
  6. 7
      src/python/magnum/scenegraph.cpp
  7. 6
      src/python/magnum/scenegraph.h

110
src/python/corrade/containers.cpp

@ -27,7 +27,6 @@
#include <pybind11/numpy.h> /* so ArrayView is convertible from python array */
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/ScopeGuard.h>
#include <Corrade/Utility/FormatStl.h>
#include "Corrade/Containers/Python.h"
@ -119,8 +118,10 @@ template<class T> void arrayView(py::class_<Containers::ArrayView<T>, 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<class T> void arrayView(py::class_<Containers::ArrayView<T>, 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<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")
@ -169,7 +173,10 @@ template<class T> void arrayView(py::class_<Containers::ArrayView<T>, Containers
template<class T> void mutableArrayView(py::class_<Containers::ArrayView<T>, Containers::PyArrayViewHolder<Containers::ArrayView<T>>>& c) {
c
.def("__setitem__", [](const Containers::ArrayView<T>& 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<unsigned dimensions, class T> void stridedArrayView(py::class_<Containe
Containers::ScopeGuard e{&buffer, PyBuffer_Release};
if(buffer.ndim != dimensions)
throw py::buffer_error{Utility::formatString("expected {} dimensions but got {}", dimensions, buffer.ndim)};
if(buffer.ndim != dimensions) {
PyErr_Format(PyExc_BufferError, "expected %u dimensions but got %i", dimensions, buffer.ndim);
throw py::error_already_set{};
}
Containers::StaticArrayView<dimensions, const std::size_t> sizes{reinterpret_cast<std::size_t*>(buffer.shape)};
Containers::StaticArrayView<dimensions, const std::ptrdiff_t> strides{reinterpret_cast<std::ptrdiff_t*>(buffer.strides)};
@ -379,26 +388,29 @@ template<unsigned dimensions, class T> void stridedArrayView(py::class_<Containe
template<class T> void stridedArrayView1D(py::class_<Containers::StridedArrayView<1, T>, Containers::PyArrayViewHolder<Containers::StridedArrayView<1, T>>>& 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<unsigned dimensions, class T> void stridedArrayViewND(py::class_<Containers::StridedArrayView<dimensions, T>, Containers::PyArrayViewHolder<Containers::StridedArrayView<dimensions, T>>>& 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<dimensions, T>& self, std::size_t i) {
if(i >= Containers::StridedDimensions<dimensions, const std::size_t>{self.size()}[0]) throw pybind11::index_error{};
if(i >= Containers::StridedDimensions<dimensions, const std::size_t>{self.size()}[0]) {
PyErr_SetNone(PyExc_IndexError);
throw py::error_already_set{};
}
return Containers::pyArrayViewHolder(self[i], pyObjectHolderFor<Containers::PyArrayViewHolder>(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<dimensions, T>& self, const typename DimensionsTuple<dimensions, py::slice>::Type& slice) {
Containers::StridedDimensions<dimensions, std::size_t> starts;
@ -422,39 +434,52 @@ template<unsigned dimensions, class T> void stridedArrayViewND(py::class_<Contai
template<class T> void stridedArrayView2D(py::class_<Containers::StridedArrayView<2, T>, Containers::PyArrayViewHolder<Containers::StridedArrayView<2, T>>>& 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<std::size_t, std::size_t>& 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<Containers::PyArrayViewHolder>(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<Containers::PyArrayViewHolder>(self).owner);
if(dimension == 1)
return Containers::pyArrayViewHolder(self.template flipped<1>(), pyObjectHolderFor<Containers::PyArrayViewHolder>(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<Containers::PyArrayViewHolder>(self).owner);
if(dimension == 1)
return Containers::pyArrayViewHolder(self.template broadcasted<1>(size), pyObjectHolderFor<Containers::PyArrayViewHolder>(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<class T> void stridedArrayView3D(py::class_<Containers::StridedArrayView<3, T>, Containers::PyArrayViewHolder<Containers::StridedArrayView<3, T>>>& 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<std::size_t, std::size_t, std::size_t>& 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<class T> void stridedArrayView3D(py::class_<Containers::StridedArrayVie
if((a == 1 && b == 2) ||
(a == 2 && b == 1))
return Containers::pyArrayViewHolder(self.template transposed<1, 2>(), pyObjectHolderFor<Containers::PyArrayViewHolder>(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<class T> void stridedArrayView3D(py::class_<Containers::StridedArrayVie
return Containers::pyArrayViewHolder(self.template flipped<1>(), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
if(dimension == 2)
return Containers::pyArrayViewHolder(self.template flipped<2>(), pyObjectHolderFor<Containers::PyArrayViewHolder>(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<class T> void stridedArrayView3D(py::class_<Containers::StridedArrayVie
return Containers::pyArrayViewHolder(self.template broadcasted<1>(size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
if(dimension == 2)
return Containers::pyArrayViewHolder(self.template broadcasted<2>(size), pyObjectHolderFor<Containers::PyArrayViewHolder>(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<class T> void stridedArrayView4D(py::class_<Containers::StridedArrayView<4, T>, Containers::PyArrayViewHolder<Containers::StridedArrayView<4, T>>>& 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<std::size_t, std::size_t, std::size_t, std::size_t>& 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<class T> void stridedArrayView4D(py::class_<Containers::StridedArrayVie
if((a == 2 && b == 3) ||
(a == 3 && b == 2))
return Containers::pyArrayViewHolder(self.template transposed<2, 3>(), pyObjectHolderFor<Containers::PyArrayViewHolder>(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<class T> void stridedArrayView4D(py::class_<Containers::StridedArrayVie
return Containers::pyArrayViewHolder(self.template flipped<2>(), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
if(dimension == 3)
return Containers::pyArrayViewHolder(self.template flipped<3>(), pyObjectHolderFor<Containers::PyArrayViewHolder>(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<class T> void stridedArrayView4D(py::class_<Containers::StridedArrayVie
return Containers::pyArrayViewHolder(self.template broadcasted<2>(size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
if(dimension == 3)
return Containers::pyArrayViewHolder(self.template broadcasted<3>(size), pyObjectHolderFor<Containers::PyArrayViewHolder>(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<class T> void mutableStridedArrayView1D(py::class_<Containers::StridedArrayView<1, T>, Containers::PyArrayViewHolder<Containers::StridedArrayView<1, T>>>& 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<class T> void mutableStridedArrayView2D(py::class_<Containers::StridedA
c
.def("__setitem__", [](const Containers::StridedArrayView<2, T>& self, const std::tuple<std::size_t, std::size_t>& 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<class T> void mutableStridedArrayView3D(py::class_<Containers::StridedA
.def("__setitem__", [](const Containers::StridedArrayView<3, T>& self, const std::tuple<std::size_t, std::size_t, std::size_t>& 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<class T> void mutableStridedArrayView4D(py::class_<Containers::StridedA
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{};
}
self[std::get<0>(i)][std::get<1>(i)][std::get<2>(i)][std::get<3>(i)] = value;
}, "Set a value at given position");
}

6
src/python/magnum/gl.cpp

@ -26,7 +26,6 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h> /* for Mesh.buffers */
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Utility/FormatStl.h>
#include <Magnum/Image.h>
#include <Magnum/ImageView.h>
#include <Magnum/GL/AbstractShaderProgram.h>
@ -777,7 +776,10 @@ void gl(py::module& m) {
self.setPrimitive(py::cast<MeshPrimitive>(primitive));
else if(py::isinstance<GL::MeshPrimitive>(primitive))
self.setPrimitive(py::cast<GL::MeshPrimitive>(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) */

12
src/python/magnum/math.cpp

@ -177,14 +177,20 @@ template<class T> void boolVector(py::class_<T>& 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")

28
src/python/magnum/math.matrix.h

@ -28,7 +28,6 @@
#include <pybind11/pybind11.h>
#include <pybind11/operators.h>
#include <Corrade/Containers/ScopeGuard.h>
#include <Corrade/Utility/FormatStl.h>
#include <Magnum/Math/Matrix3.h>
#include <Magnum/Math/Matrix4.h>
@ -114,11 +113,15 @@ template<class T, class ...Args> void everyRectangularMatrixBuffer(py::class_<T,
Containers::ScopeGuard e{&buffer, PyBuffer_Release};
if(buffer.ndim != 2)
throw py::buffer_error{Utility::formatString("expected 2 dimensions but got {}", buffer.ndim)};
if(buffer.ndim != 2) {
PyErr_Format(PyExc_BufferError, "expected 2 dimensions but got %i", buffer.ndim);
throw py::error_already_set{};
}
if(buffer.shape[0] != T::Rows || buffer.shape[1] != T::Cols)
throw py::buffer_error{Utility::formatString("expected {}x{} elements but got {}x{}", T::Cols, T::Rows, buffer.shape[1], buffer.shape[0])};
if(buffer.shape[0] != T::Rows || buffer.shape[1] != T::Cols) {
PyErr_Format(PyExc_BufferError, "expected %zux%zu elements but got %zix%zi", T::Cols, T::Rows, buffer.shape[1], buffer.shape[0]);
throw py::error_already_set{};
}
T out{Math::NoInit};
@ -127,7 +130,10 @@ template<class T, class ...Args> void everyRectangularMatrixBuffer(py::class_<T,
initFromBuffer<Float>(out, buffer);
else if(buffer.format[0] == 'd' && !buffer.format[1])
initFromBuffer<Double>(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<class T> void rectangularMatrix(py::class_<T>& 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<class T> void rectangularMatrix(py::class_<T>& c) {
.def("__setitem__", [](T& self, std::size_t i, const typename VectorTraits<T::Rows, typename T::Type>::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<T::Rows, typename T::Type>::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<class T> void rectangularMatrix(py::class_<T>& c) {
.def("__setitem__", [](T& self, const std::pair<std::size_t, std::size_t>& 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<std::size_t, std::size_t>& 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")

39
src/python/magnum/math.vector.h

@ -27,7 +27,6 @@
#include <pybind11/operators.h>
#include <Corrade/Containers/ScopeGuard.h>
#include <Corrade/Utility/FormatStl.h>
#include <Magnum/Math/Color.h>
#include <Magnum/Math/Vector4.h>
@ -142,15 +141,21 @@ template<class T, class ...Args> void everyVectorBuffer(py::class_<T, Args...>&
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<typename T::Type>(buffer.format[0]))
throw py::buffer_error{Utility::formatString("unexpected format {} for a {} vector", buffer.format, FormatStrings[formatIndex<typename T::Type>()])};
if(!buffer.format[0] || buffer.format[1] || !isTypeCompatible<typename T::Type>(buffer.format[0])) {
PyErr_Format(PyExc_BufferError, "unexpected format %s for a %s vector", buffer.format, FormatStrings[formatIndex<typename T::Type>()]);
throw py::error_already_set{};
}
T out{Math::NoInit};
initFromBuffer<T>(out, buffer);
@ -208,7 +213,7 @@ template<class T> void vector(py::module& m, py::class_<T>& 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<class T> void vector(py::module& m, py::class_<T>& 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<class T> void vector(py::module& m, py::class_<T>& 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<typename T::Type> out;
@ -246,7 +251,7 @@ template<class T> void vector(py::module& m, py::class_<T>& 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<class T> void vector(py::module& m, py::class_<T>& 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<class T> void vector(py::module& m, py::class_<T>& 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<class T> void vector(py::module& m, py::class_<T>& 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")

7
src/python/magnum/scenegraph.cpp

@ -64,10 +64,13 @@ template<class PyFeature, UnsignedInt dimensions, class Feature, class T> void f
.def("__len__", &SceneGraph::FeatureGroup<dimensions, Feature, T>::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<dimensions, Feature, T>& 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<PyFeature&>(self[index]);
}, "Feature at given index")
.def("add", [](SceneGraph::FeatureGroup<dimensions, Feature, T>& self, PyFeature& feature) {

6
src/python/magnum/scenegraph.h

@ -26,7 +26,6 @@
*/
#include <pybind11/pybind11.h>
#include <Corrade/Utility/FormatStl.h>
#include <Magnum/SceneGraph/Object.h>
#include <Magnum/SceneGraph/Scene.h>
@ -61,7 +60,10 @@ template<UnsignedInt dimensions, class T, class Transformation> void object(py::
parent = py::cast<SceneGraph::Scene<Transformation>*>(parentobj);
else if(py::isinstance<py::none>(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 */

Loading…
Cancel
Save