From b3e24a11b4e0cb555510cd233ecbd773f0434bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 9 Feb 2023 02:07:19 +0100 Subject: [PATCH] python: reorder trade.MeshData APIs to have enum overloads first. Because for some reason pybind11 on *some platforms* (or in some configurations?) picks the integer overload even for enum arguments, only because it's first in the overload set. This is extremely brittle, but for now I don't know any better solution. --- src/python/magnum/trade.cpp | 113 +++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 54 deletions(-) diff --git a/src/python/magnum/trade.cpp b/src/python/magnum/trade.cpp index 380b4fb..7d18f2e 100644 --- a/src/python/magnum/trade.cpp +++ b/src/python/magnum/trade.cpp @@ -520,6 +520,14 @@ void trade(py::module_& m) { .def("attribute_count", static_cast(&Trade::MeshData::attributeCount), "Attribute array count") /** @todo direct access to MeshAttributeData, once making custom MeshData is desired */ + .def("has_attribute", &Trade::MeshData::hasAttribute, "Whether the mesh has given attribute", py::arg("name")) + .def("attribute_count", static_cast(&Trade::MeshData::attributeCount), "Count of given named attribute", py::arg("name")) + + /* IMPORTANT: due to yet-uninvestigated pybind11 platform-specific + behavioral differences the following overloads need to have the + MeshAttribute overload *before* the UnsignedInt overload, otherwise + the integer overload gets picked even if an enum is passed from + Python, causing massive suffering */ .def("attribute_name", [](Trade::MeshData& self, UnsignedInt id) { if(id >= self.attributeCount()) { PyErr_SetString(PyExc_IndexError, ""); @@ -527,6 +535,12 @@ void trade(py::module_& m) { } return self.attributeName(id); }, "Attribute name", py::arg("id")) + .def("attribute_id", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { + if(const Containers::Optional found = self.findAttributeId(name, id)) + return *found; + PyErr_SetString(PyExc_KeyError, ""); + throw py::error_already_set{}; + }, "Absolute ID of a named attribute", py::arg("name"), py::arg("id") = 0) .def("attribute_id", [](Trade::MeshData& self, UnsignedInt id) { if(id >= self.attributeCount()) { PyErr_SetString(PyExc_IndexError, ""); @@ -534,6 +548,12 @@ void trade(py::module_& m) { } return self.attributeId(id); }, "Attribute ID in a set of attributes of the same name", py::arg("id")) + .def("attribute_format", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { + if(const Containers::Optional found = self.findAttributeId(name, id)) + return self.attributeFormat(*found); + PyErr_SetString(PyExc_KeyError, ""); + throw py::error_already_set{}; + }, "Format of a named attribute", py::arg("name"), py::arg("id") = 0) .def("attribute_format", [](Trade::MeshData& self, UnsignedInt id) { if(id >= self.attributeCount()) { PyErr_SetString(PyExc_IndexError, ""); @@ -541,6 +561,12 @@ void trade(py::module_& m) { } return self.attributeFormat(id); }, "Attribute format", py::arg("id")) + .def("attribute_offset", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { + if(const Containers::Optional found = self.findAttributeId(name, id)) + return self.attributeOffset(*found); + PyErr_SetString(PyExc_KeyError, ""); + throw py::error_already_set{}; + }, "Offset of a named attribute", py::arg("name"), py::arg("id") = 0) .def("attribute_offset", [](Trade::MeshData& self, UnsignedInt id) { if(id >= self.attributeCount()) { PyErr_SetString(PyExc_IndexError, ""); @@ -548,6 +574,12 @@ void trade(py::module_& m) { } return self.attributeOffset(id); }, "Attribute offset", py::arg("id")) + .def("attribute_stride", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { + if(const Containers::Optional found = self.findAttributeId(name, id)) + return self.attributeStride(*found); + PyErr_SetString(PyExc_KeyError, ""); + throw py::error_already_set{}; + }, "Stride of a named attribute", py::arg("name"), py::arg("id") = 0) .def("attribute_stride", [](Trade::MeshData& self, UnsignedInt id) { if(id >= self.attributeCount()) { PyErr_SetString(PyExc_IndexError, ""); @@ -555,93 +587,67 @@ void trade(py::module_& m) { } return self.attributeStride(id); }, "Attribute stride", py::arg("id")) - .def("attribute_array_size", [](Trade::MeshData& self, UnsignedInt id) { - if(id >= self.attributeCount()) { - PyErr_SetString(PyExc_IndexError, ""); - throw py::error_already_set{}; - } - return self.attributeArraySize(id); - }, "Attribute array size", py::arg("id")) - .def("has_attribute", &Trade::MeshData::hasAttribute, "Whether the mesh has given attribute", py::arg("name")) - .def("attribute_count", static_cast(&Trade::MeshData::attributeCount), "Count of given named attribute", py::arg("name")) - .def("attribute_id", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { - if(const Containers::Optional found = self.findAttributeId(name, id)) - return *found; - PyErr_SetString(PyExc_KeyError, ""); - throw py::error_already_set{}; - }, "Absolute ID of a named attribute", py::arg("name"), py::arg("id") = 0) - .def("attribute_format", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { - if(const Containers::Optional found = self.findAttributeId(name, id)) - return self.attributeFormat(*found); - PyErr_SetString(PyExc_KeyError, ""); - throw py::error_already_set{}; - }, "Format of a named attribute", py::arg("name"), py::arg("id") = 0) - .def("attribute_offset", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { - if(const Containers::Optional found = self.findAttributeId(name, id)) - return self.attributeOffset(*found); - PyErr_SetString(PyExc_KeyError, ""); - throw py::error_already_set{}; - }, "Offset of a named attribute", py::arg("name"), py::arg("id") = 0) - .def("attribute_stride", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { - if(const Containers::Optional found = self.findAttributeId(name, id)) - return self.attributeStride(*found); - PyErr_SetString(PyExc_KeyError, ""); - throw py::error_already_set{}; - }, "Stride of a named attribute", py::arg("name"), py::arg("id") = 0) .def("attribute_array_size", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { if(const Containers::Optional found = self.findAttributeId(name, id)) return self.attributeArraySize(*found); PyErr_SetString(PyExc_KeyError, ""); throw py::error_already_set{}; }, "Array size of a named attribute", py::arg("name"), py::arg("id") = 0) - .def("attribute", [](Trade::MeshData& self, UnsignedInt id) { + .def("attribute_array_size", [](Trade::MeshData& self, UnsignedInt id) { if(id >= self.attributeCount()) { PyErr_SetString(PyExc_IndexError, ""); throw py::error_already_set{}; } + return self.attributeArraySize(id); + }, "Attribute array size", py::arg("id")) + .def("attribute", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { + const Containers::Optional found = self.findAttributeId(name, id); + if(!found) { + PyErr_SetString(PyExc_KeyError, ""); + throw py::error_already_set{}; + } /** @todo handle arrays (return a 2D view, and especially annotate the return type properly in the docs) */ - if(self.attributeArraySize(id) != 0) { + if(self.attributeArraySize(*found) != 0) { PyErr_SetString(PyExc_NotImplementedError, "array attributes not implemented yet, sorry"); throw py::error_already_set{}; } - return meshAttributeView(self, id, self.attribute(id)); - }, "Data for given attribute", py::arg("id")) - .def("mutable_attribute", [](Trade::MeshData& self, UnsignedInt id) { + return meshAttributeView(self, *found, self.attribute(*found)); + }, "Data for given named attribute", py::arg("name"), py::arg("id") = 0) + .def("attribute", [](Trade::MeshData& self, UnsignedInt id) { if(id >= self.attributeCount()) { PyErr_SetString(PyExc_IndexError, ""); throw py::error_already_set{}; } - if(!(self.vertexDataFlags() & Trade::DataFlag::Mutable)) { - PyErr_SetString(PyExc_AttributeError, "mesh vertex data is not mutable"); - throw py::error_already_set{}; - } /** @todo handle arrays (return a 2D view, and especially annotate the return type properly in the docs) */ if(self.attributeArraySize(id) != 0) { PyErr_SetString(PyExc_NotImplementedError, "array attributes not implemented yet, sorry"); throw py::error_already_set{}; } - return meshAttributeView(self, id, self.mutableAttribute(id)); - }, "Mutable data for given attribute", py::arg("id")) - .def("attribute", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { + return meshAttributeView(self, id, self.attribute(id)); + }, "Data for given attribute", py::arg("id")) + .def("mutable_attribute", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { const Containers::Optional found = self.findAttributeId(name, id); if(!found) { PyErr_SetString(PyExc_KeyError, ""); throw py::error_already_set{}; } + if(!(self.vertexDataFlags() & Trade::DataFlag::Mutable)) { + PyErr_SetString(PyExc_AttributeError, "mesh vertex data is not mutable"); + throw py::error_already_set{}; + } /** @todo handle arrays (return a 2D view, and especially annotate the return type properly in the docs) */ if(self.attributeArraySize(*found) != 0) { PyErr_SetString(PyExc_NotImplementedError, "array attributes not implemented yet, sorry"); throw py::error_already_set{}; } - return meshAttributeView(self, *found, self.attribute(*found)); + return meshAttributeView(self, *found, self.mutableAttribute(*found)); }, "Data for given named attribute", py::arg("name"), py::arg("id") = 0) - .def("mutable_attribute", [](Trade::MeshData& self, Trade::MeshAttribute name, UnsignedInt id) { - const Containers::Optional found = self.findAttributeId(name, id); - if(!found) { - PyErr_SetString(PyExc_KeyError, ""); + .def("mutable_attribute", [](Trade::MeshData& self, UnsignedInt id) { + if(id >= self.attributeCount()) { + PyErr_SetString(PyExc_IndexError, ""); throw py::error_already_set{}; } if(!(self.vertexDataFlags() & Trade::DataFlag::Mutable)) { @@ -650,13 +656,12 @@ void trade(py::module_& m) { } /** @todo handle arrays (return a 2D view, and especially annotate the return type properly in the docs) */ - if(self.attributeArraySize(*found) != 0) { + if(self.attributeArraySize(id) != 0) { PyErr_SetString(PyExc_NotImplementedError, "array attributes not implemented yet, sorry"); throw py::error_already_set{}; } - return meshAttributeView(self, *found, self.mutableAttribute(*found)); - }, "Data for given named attribute", py::arg("name"), py::arg("id") = 0) - ; + return meshAttributeView(self, id, self.mutableAttribute(id)); + }, "Mutable data for given attribute", py::arg("id")); py::class_ imageData1D{m, "ImageData1D", "One-dimensional image data"}; py::class_ imageData2D{m, "ImageData2D", "Two-dimensional image data"};