diff --git a/src/python/corrade/pluginmanager.cpp b/src/python/corrade/pluginmanager.cpp index e231baa..487bf06 100644 --- a/src/python/corrade/pluginmanager.cpp +++ b/src/python/corrade/pluginmanager.cpp @@ -25,6 +25,8 @@ #include #include /* for pluginList() and aliasList() */ +#include +#include /** @todo drop once we have our string casters */ #include #include "Corrade/PythonBindings.h" @@ -55,14 +57,38 @@ void pluginmanager(py::module_& m) { PyNonDestructibleClass manager{m, "AbstractManager", "Base for plugin managers"}; manager.attr("VERSION") = PluginManager::AbstractManager::Version; manager - .def_property_readonly("plugin_interface", &PluginManager::AbstractManager::pluginInterface, "Plugin interface") - .def_property("plugin_directory", &PluginManager::AbstractManager::pluginDirectory, &PluginManager::AbstractManager::setPluginDirectory, "Plugin directory") + .def_property_readonly("plugin_interface", [](PluginManager::AbstractManager& self) { + /** @todo drop std::string in favor of our own string caster */ + return std::string{self.pluginInterface()}; + }, "Plugin interface") + .def_property("plugin_directory", + /** @todo drop std::string in favor of our own string caster */ + [](PluginManager::AbstractManager& self) { + return std::string{self.pluginDirectory()}; + }, [](PluginManager::AbstractManager& self, const std::string& directory) { + self.setPluginDirectory(directory); + }, "Plugin directory") .def("reload_plugin_directory", &PluginManager::AbstractManager::reloadPluginDirectory, "Reload plugin directory") /** @todo setPreferredPlugins (takes an init list) */ - .def_property_readonly("plugin_list", &PluginManager::AbstractManager::pluginList, "List of all available plugin names") - .def_property_readonly("alias_list", &PluginManager::AbstractManager::aliasList, "List of all available alias names") + .def_property_readonly("plugin_list", [](PluginManager::AbstractManager& self) { + /** @todo make a generic caster for arbitrary arrays and strings */ + std::vector out; + for(Containers::StringView i: self.pluginList()) + out.push_back(i); + return out; + }, "List of all available plugin names") + .def_property_readonly("alias_list", [](PluginManager::AbstractManager& self) { + /** @todo make a generic caster for arbitrary arrays and strings */ + std::vector out; + for(Containers::StringView i: self.aliasList()) + out.push_back(i); + return out; + }, "List of all available alias names") /** @todo metadata() (figure out the ownership) */ - .def("load_state", &PluginManager::AbstractManager::loadState, "Load state of a plugin") + /** @todo drop std::string in favor of our own string caster */ + .def("load_state", [](PluginManager::AbstractManager& self, const std::string& plugin) { + return self.loadState(plugin); + }, "Load state of a plugin") .def("load", [](PluginManager::AbstractManager& self, const std::string& plugin) { /** @todo log redirection -- but we'd need assertions to not be part of that so when it dies, the user can still see why */ diff --git a/src/python/magnum/trade.cpp b/src/python/magnum/trade.cpp index 0491441..6761ce1 100644 --- a/src/python/magnum/trade.cpp +++ b/src/python/magnum/trade.cpp @@ -26,6 +26,7 @@ #include #include #include +#include /** @todo drop once we have our string casters */ #include #include #include @@ -154,6 +155,14 @@ template R checkOpene } return (self.*f)(arg1); } +/** @todo drop this in favor of our own string caster */ +template R checkOpenedString(Trade::AbstractImporter& self, const std::string& arg1) { + if(!self.isOpened()) { + PyErr_SetString(PyExc_RuntimeError, "no file opened"); + throw py::error_already_set{}; + } + return (self.*f)(arg1); +} template R checkOpenedBounds(Trade::AbstractImporter& self, UnsignedInt id) { if(!self.isOpened()) { @@ -168,6 +177,20 @@ template std::string checkOpenedBoundsReturnsString(Trade::AbstractImporter& self, UnsignedInt id) { + if(!self.isOpened()) { + PyErr_SetString(PyExc_RuntimeError, "no file opened"); + throw py::error_already_set{}; + } + + if(id >= (self.*bounds)()) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } + + return (self.*f)(id); +} template(Trade::AbstractImporter::*f)(UnsignedInt), UnsignedInt(Trade::AbstractImporter::*bounds)() const> R checkOpenedBoundsResult(Trade::AbstractImporter& self, UnsignedInt id) { if(!self.isOpened()) { @@ -257,6 +280,7 @@ void trade(py::module_& m) { PyErr_SetString(PyExc_RuntimeError, "opening data failed"); throw py::error_already_set{}; }, "Open raw data", py::arg("data")) + /** @todo drop std::string in favor of our own string caster */ .def("open_file", [](Trade::AbstractImporter& self, const std::string& filename) { /** @todo log redirection -- but we'd need assertions to not be part of that so when it dies, the user can still see why */ @@ -270,8 +294,8 @@ void trade(py::module_& m) { /** @todo all other data types */ .def_property_readonly("mesh_count", checkOpened, "Mesh count") .def("mesh_level_count", checkOpenedBounds, "Mesh level count", py::arg("id")) - .def("mesh_for_name", checkOpened, "Mesh ID for given name") - .def("mesh_name", checkOpenedBounds, "Mesh name", py::arg("id")) + .def("mesh_for_name", checkOpenedString, "Mesh ID for given name") + .def("mesh_name", checkOpenedBoundsReturnsString<&Trade::AbstractImporter::meshName, &Trade::AbstractImporter::meshCount>, "Mesh name", py::arg("id")) .def("mesh", checkOpenedBoundsResult, "Mesh", py::arg("id"), py::arg("level") = 0) /** @todo mesh_attribute_for_name / mesh_attribute_name */ @@ -281,12 +305,12 @@ void trade(py::module_& m) { .def("image1d_level_count", checkOpenedBounds, "One-dimensional image level count", py::arg("id")) .def("image2d_level_count", checkOpenedBounds, "Two-dimensional image level count", py::arg("id")) .def("image3d_level_count", checkOpenedBounds, "Three-dimensional image level count", py::arg("id")) - .def("image1d_for_name", checkOpened, "One-dimensional image ID for given name") - .def("image2d_for_name", checkOpened, "Two-dimensional image ID for given name") - .def("image3d_for_name", checkOpened, "Three-dimensional image ID for given name") - .def("image1d_name", checkOpenedBounds, "One-dimensional image name", py::arg("id")) - .def("image2d_name", checkOpenedBounds, "Two-dimensional image name", py::arg("id")) - .def("image3d_name", checkOpenedBounds, "Three-dimensional image name", py::arg("id")) + .def("image1d_for_name", checkOpenedString, "One-dimensional image ID for given name") + .def("image2d_for_name", checkOpenedString, "Two-dimensional image ID for given name") + .def("image3d_for_name", checkOpenedString, "Three-dimensional image ID for given name") + .def("image1d_name", checkOpenedBoundsReturnsString<&Trade::AbstractImporter::image1DName, &Trade::AbstractImporter::image1DCount>, "One-dimensional image name", py::arg("id")) + .def("image2d_name", checkOpenedBoundsReturnsString<&Trade::AbstractImporter::image2DName, &Trade::AbstractImporter::image2DCount>, "Two-dimensional image name", py::arg("id")) + .def("image3d_name", checkOpenedBoundsReturnsString< &Trade::AbstractImporter::image3DName, &Trade::AbstractImporter::image3DCount>, "Three-dimensional image name", py::arg("id")) .def("image1d", checkOpenedBoundsResult, "One-dimensional image", py::arg("id"), py::arg("level") = 0) .def("image2d", checkOpenedBoundsResult, "Two-dimensional image", py::arg("id"), py::arg("level") = 0) .def("image3d", checkOpenedBoundsResult, "Three-dimensional image", py::arg("id"), py::arg("level") = 0);