diff --git a/src/runner/pythonrunner.cpp b/src/runner/pythonrunner.cpp index 2738801..c3e274a 100644 --- a/src/runner/pythonrunner.cpp +++ b/src/runner/pythonrunner.cpp @@ -59,7 +59,6 @@ namespace mp11 = boost::mp11; return bpy::object{ (QClass*)w }.attr(str); \ }) - BOOST_PYTHON_MODULE(mobase) { PyEval_InitThreads(); @@ -111,7 +110,8 @@ BOOST_PYTHON_MODULE(mobase) utils::register_associative_container>(); // Required for QVariant since this is QVariantMap. utils::register_associative_container>(); - + utils::register_associative_container>(); + utils::register_associative_container(); // Tuple: @@ -132,7 +132,7 @@ BOOST_PYTHON_MODULE(mobase) utils::register_functor_converter(); utils::register_functor_converter(); utils::register_functor_converter(); // converter for the onModMoved-callback and onPluginMoved callbacks - utils::register_functor_converter(); // converter for the onModStateChanged-callback (IModList) + utils::register_functor_converter&)>(); // converter for the onModStateChanged-callback (IModList) utils::register_functor_converter(); // converter for the onPluginStateChanged-callback (IPluginList) utils::register_functor_converter(); utils::register_functor_converter(); @@ -143,6 +143,9 @@ BOOST_PYTHON_MODULE(mobase) utils::register_functor_converter const&)>(); utils::register_functor_converter(QString const&)>(); + // This one is kept for backward-compatibility while we deprecate onModStateChanged for singl mod. + utils::register_functor_converter(); // converter for the onModStateChanged-callback (IModList). + // // Class declarations: // @@ -646,9 +649,24 @@ BOOST_PYTHON_MODULE(mobase) .def("displayName", &MOBase::IModList::displayName, bpy::arg("name")) .def("allMods", &MOBase::IModList::allMods) .def("state", &MOBase::IModList::state, bpy::arg("name")) - .def("setActive", &MOBase::IModList::setActive, (bpy::arg("name"), "active")) + .def("setActive", + static_cast(&MOBase::IModList::setActive), (bpy::arg("names"), "active")) + .def("setActive", + static_cast(&MOBase::IModList::setActive), (bpy::arg("name"), "active")) .def("priority", &MOBase::IModList::priority, bpy::arg("name")) .def("setPriority", &MOBase::IModList::setPriority, (bpy::arg("name"), "priority")) + + // Kept but deprecated for backward compatibility: + .def("onModStateChanged", +[](IModList* modList, const std::function& fn) { + utils::show_deprecation_warning("onModStateChanged", + "onModStateChanged(Callable[[str, IModList.ModStates], None]) is deprecated, " + "use onModStateChanged(Callable[[Dict[str, IModList.ModStates], None]) instead."); + return modList->onModStateChanged([fn](auto const& map) { + for (const auto& entry : map) { + fn(entry.first, entry.second); + } + }); + }, bpy::arg("callback")) .def("onModStateChanged", &MOBase::IModList::onModStateChanged, bpy::arg("callback")) .def("onModMoved", &MOBase::IModList::onModMoved, bpy::arg("callback")) ; diff --git a/src/runner/pythonutils.cpp b/src/runner/pythonutils.cpp new file mode 100644 index 0000000..37445c5 --- /dev/null +++ b/src/runner/pythonutils.cpp @@ -0,0 +1,46 @@ +#include "pythonutils.h" + +#include +#include + +#include + +#include "log.h" + +namespace utils { + + void show_deprecation_warning(std::string_view name, std::string_view message, bool show_once) { + + // Contains the list of filename / line number for which a deprecation warning has already been shown. + static std::set> DeprecatedLines; + + // Find the caller: + auto inspect = bpy::import("inspect"); + auto current_frame = inspect.attr("currentframe")(); + auto callable_frame = inspect.attr("getouterframes")(current_frame, 2); + auto filename = bpy::extract(callable_frame[-1].attr("filename"))(); + auto function = bpy::extract(callable_frame[-1].attr("function"))(); + auto lineno = bpy::extract(callable_frame[-1].attr("lineno")); + + // Only show once if requested: + if (show_once && DeprecatedLines.contains({ filename, lineno })) { + return; + } + + // Register the deprecation: + DeprecatedLines.emplace(filename, lineno); + + auto path = relative(std::filesystem::path(filename), QCoreApplication::applicationDirPath().toStdWString()); + + // Show the message: + if (message.empty()) { + MOBase::log::warn( + "[deprecated] {} in {} [{}:{}].", name, function, path.native(), lineno); + } + else { + MOBase::log::warn( + "[deprecated] {} in {} [{}:{}]: {}", name, function, path.native(), lineno, message); + } + } + +} \ No newline at end of file diff --git a/src/runner/pythonutils.h b/src/runner/pythonutils.h index b424d15..92bb301 100644 --- a/src/runner/pythonutils.h +++ b/src/runner/pythonutils.h @@ -3,6 +3,8 @@ #include +#include "error.h" + namespace utils { namespace bpy = boost::python; @@ -195,6 +197,20 @@ namespace utils { , bpy::type_id()); }; + + /** + * @brief Show a deprecation warning. + * + * This methods will print a warning in MO2 log containing the location of the call to + * the deprecated function. If show_once is true, the deprecation warning will only be + * logged the first time the function is called at this location. + * + * @param name Name of the deprecated function. + * @param message Deprecation message. + * @param show_once Only show the message once per call location. + */ + void show_deprecation_warning(std::string_view name, std::string_view message = "", bool show_once = true); + } #endif \ No newline at end of file