diff --git a/doc/python/conf.py b/doc/python/conf.py index 7857b43..41186d8 100644 --- a/doc/python/conf.py +++ b/doc/python/conf.py @@ -1,5 +1,6 @@ import os import sys +from typing import List # TODO make this less brittle sys.path = [os.path.join(os.path.dirname(__file__), '../../build/src/python/')] + sys.path @@ -52,6 +53,25 @@ magnum.TARGET_WEBGL = DoNotPrintValue() magnum.TARGET_EGL = DoNotPrintValue() magnum.TARGET_VK = DoNotPrintValue() +# TODO ugh... can this be expressed directly in pybind? and the docs parsed +# from it so i don't need to repeat them in docs/*.rst files? +for i in [magnum.text.AbstractFont, + magnum.trade.AbstractImporter, + magnum.trade.AbstractImageConverter, + magnum.trade.AbstractSceneConverter]: + i.__annotations__ = { + 'plugin_interface': str, + 'plugin_search_paths': List[str], + 'plugin_suffix': str, + 'plugin_metadata_suffix': str + } + + # Don't show the values. Without delattr() first it complains that the + # attribute can't be set + for key in i.__annotations__: + delattr(i, key) + setattr(i, key, DoNotPrintValue()) + # TODO ugh... can this be expressed directly in pybind? corrade.__annotations__ = { 'BUILD_DEPRECATED': bool, diff --git a/doc/python/magnum.text.rst b/doc/python/magnum.text.rst index 5a9ea59..c8c4796 100644 --- a/doc/python/magnum.text.rst +++ b/doc/python/magnum.text.rst @@ -31,7 +31,14 @@ :ref:`AbstractFont.manager`, ensuring the manager is not deleted before the plugin instances are. +.. TODO couldn't the plugin_interface etc. docs be parsed from pybind's docs? + repeating them for every plugin is annoying + .. py:class:: magnum.text.AbstractFont + :data plugin_interface: Plugin interface string + :data plugin_search_paths: Plugin search paths + :data plugin_suffix: Plugin suffix + :data plugin_metadata_suffix: Plugin metadata suffix Similarly to C++, font plugins are loaded through :ref:`FontManager`: diff --git a/doc/python/magnum.trade.rst b/doc/python/magnum.trade.rst index 8f8650a..6782f1f 100644 --- a/doc/python/magnum.trade.rst +++ b/doc/python/magnum.trade.rst @@ -289,7 +289,14 @@ :ref:`AbstractImporter.manager`, ensuring the manager is not deleted before the plugin instances are. +.. TODO couldn't the plugin_interface etc. docs be parsed from pybind's docs? + repeating them for every plugin is annoying + .. py:class:: magnum.trade.AbstractImporter + :data plugin_interface: Plugin interface string + :data plugin_search_paths: Plugin search paths + :data plugin_suffix: Plugin suffix + :data plugin_metadata_suffix: Plugin metadata suffix Similarly to C++, importer plugins are loaded through :ref:`ImporterManager`: @@ -429,7 +436,14 @@ :ref:`AbstractImageConverter.manager`, ensuring the manager is not deleted before the plugin instances are. +.. TODO couldn't the plugin_interface etc. docs be parsed from pybind's docs? + repeating them for every plugin is annoying + .. py:class:: magnum.trade.AbstractImageConverter + :data plugin_interface: Plugin interface string + :data plugin_search_paths: Plugin search paths + :data plugin_suffix: Plugin suffix + :data plugin_metadata_suffix: Plugin metadata suffix Similarly to C++, image converter plugins are loaded through :ref:`ImageConverterManager`: @@ -462,7 +476,14 @@ :ref:`AbstractSceneConverter.manager`, ensuring the manager is not deleted before the plugin instances are. +.. TODO couldn't the plugin_interface etc. docs be parsed from pybind's docs? + repeating them for every plugin is annoying + .. py:class:: magnum.trade.AbstractSceneConverter + :data plugin_interface: Plugin interface string + :data plugin_search_paths: Plugin search paths + :data plugin_suffix: Plugin suffix + :data plugin_metadata_suffix: Plugin metadata suffix Similarly to C++, image converter plugins are loaded through :ref:`SceneConverterManager`: diff --git a/src/python/corrade/pluginmanager.cpp b/src/python/corrade/pluginmanager.cpp index 4f9094b..948a8d4 100644 --- a/src/python/corrade/pluginmanager.cpp +++ b/src/python/corrade/pluginmanager.cpp @@ -27,7 +27,6 @@ #include #include /* for pluginList() and aliasList() */ -#include #include /** @todo drop once we have our string casters */ #include #include diff --git a/src/python/corrade/pluginmanager.h b/src/python/corrade/pluginmanager.h index 9694b29..b77c2c9 100644 --- a/src/python/corrade/pluginmanager.h +++ b/src/python/corrade/pluginmanager.h @@ -27,6 +27,9 @@ #include /* :( */ #include +#include /** @todo remove once I can return Array directly */ +#include +#include /** @todo drop once we have our string casters */ #include #include "Corrade/PythonBindings.h" @@ -70,6 +73,27 @@ namespace corrade { template void plugin(py::class_, PluginManager::AbstractPlugin>& c) { c + .def_property_readonly_static("plugin_interface", [](const py::object&) { + /** @todo drop std::string in favor of our own string caster */ + return std::string{T::pluginInterface()}; + }, "Plugin interface string") + .def_property_readonly_static("plugin_search_paths", [](const py::object&) { + /** @todo drop std::string in favor of our own string caster */ + std::vector out; + for(auto&& i: T::pluginSearchPaths()) + out.push_back(i); + return out; + }, "Plugin search paths") + .def_property_readonly_static("plugin_suffix", [](const py::object&) { + /** @todo drop std::string in favor of our own string caster */ + return std::string{T::pluginSuffix()}; + }, "Plugin binary suffix") + .def_property_readonly_static("plugin_metadata_suffix", [](const py::object&) { + /** @todo drop std::string in favor of our own string caster */ + return std::string{T::pluginMetadataSuffix()}; + }, "Plugin metadata file suffix") + /** @todo plugin interface string, search paths, suffix, metadata file + suffix (all are static properties) */ .def_property_readonly("manager", [](const T& self) { return pyObjectHolderFor(self).manager; }, "Manager owning this plugin instance"); diff --git a/src/python/magnum/test/test_trade.py b/src/python/magnum/test/test_trade.py index 0fb51d0..801ef55 100644 --- a/src/python/magnum/test/test_trade.py +++ b/src/python/magnum/test/test_trade.py @@ -24,6 +24,7 @@ # import os +import platform import sys import tempfile import unittest @@ -1005,7 +1006,17 @@ class Importer(unittest.TestCase): manager.unload('NonexistentImporter') def test(self): - importer = trade.ImporterManager().load_and_instantiate('StbImageImporter') + manager = trade.ImporterManager() + + self.assertIn('cz.mosra.magnum.Trade.AbstractImporter', trade.AbstractImporter.plugin_interface) + self.assertIn(manager.plugin_directory, trade.AbstractImporter.plugin_search_paths) + if platform.system() == 'Windows': + self.assertEqual(trade.AbstractImporter.plugin_suffix, '.dll') + else: + self.assertEqual(trade.AbstractImporter.plugin_suffix, '.so') + self.assertEqual(trade.AbstractImporter.plugin_metadata_suffix, '.conf') + + importer = manager.load_and_instantiate('StbImageImporter') self.assertEqual(importer.plugin, 'StbImageImporter') def test_set_plugin_directory(self):