diff --git a/CMakeLists.txt b/CMakeLists.txt index ec07537df35c46518a3e9899c3230e4709d6e1d5..bcc8f9897f45aeb0ef2b2ebbb720f82ec45cde4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,6 +220,7 @@ set(${PROJECT_NAME}_HEADERS ${${PROJECT_NAME}_DECOMPOSITIONS_HEADERS} include/eigenpy/alignment.hpp include/eigenpy/computation-info.hpp + include/eigenpy/deprecation-policy.hpp include/eigenpy/eigenpy.hpp include/eigenpy/exception.hpp include/eigenpy/scalar-conversion.hpp diff --git a/include/eigenpy/deprecation-policy.hpp b/include/eigenpy/deprecation-policy.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c1635ea1703557841a115d70599ecf1b6f725e25 --- /dev/null +++ b/include/eigenpy/deprecation-policy.hpp @@ -0,0 +1,62 @@ +// +// Copyright (C) 2024 LAAS-CNRS, INRIA +// +#ifndef __eigenpy_deprecation_hpp__ +#define __eigenpy_deprecation_hpp__ + +#include "eigenpy/fwd.hpp" + +namespace eigenpy { + +enum class DeprecationType { DEPRECATION, FUTURE }; + +namespace detail { + +constexpr PyObject *deprecationTypeToPyObj(DeprecationType dep) { + switch (dep) { + case DeprecationType::DEPRECATION: + return PyExc_DeprecationWarning; + case DeprecationType::FUTURE: + return PyExc_FutureWarning; + } +} + +} // namespace detail + +constexpr char defaultDeprecationMessage[] = + "This function or attribute has been marked as deprecated, and will be " + "removed in the " + "future."; + +/// @brief A Boost.Python call policy which triggers a Python warning on +/// precall. +template <DeprecationType deprecation_type = DeprecationType::DEPRECATION, + class BasePolicy = bp::default_call_policies> +struct deprecation_warning_policy : BasePolicy { + using result_converter = typename BasePolicy::result_converter; + using argument_package = typename BasePolicy::argument_package; + + deprecation_warning_policy( + const std::string &warning_msg = defaultDeprecationMessage) + : BasePolicy(), m_what(warning_msg) {} + + const std::string what() const { return m_what; } + + const BasePolicy *derived() const { + return static_cast<const BasePolicy *>(this); + } + + template <class ArgPackage> + bool precall(const ArgPackage &args) const { + PyErr_WarnEx(detail::deprecationTypeToPyObj(deprecation_type), + m_what.c_str(), 1); + return derived()->precall(args); + } + + private: + const std::string m_what; +}; + +} // namespace eigenpy + +#endif // ifndef __eigenpy_deprecation_hpp__ diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index 09b35a02727f7008b6ca737847e0a537c5d9c4c9..d0c216fb56eb7bd230d90e20fd73bba63bf11a5c 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -37,6 +37,7 @@ endif() add_lib_unit_test(tensor) add_lib_unit_test(geometry) add_lib_unit_test(complex) +add_lib_unit_test(deprecation_policy) add_lib_unit_test(return_by_ref) add_lib_unit_test(include) if(NOT ${EIGEN3_VERSION} VERSION_LESS "3.2.0") @@ -104,6 +105,8 @@ add_python_lib_unit_test("py-matrix" "unittest/python/test_matrix.py") add_python_lib_unit_test("py-tensor" "unittest/python/test_tensor.py") add_python_lib_unit_test("py-geometry" "unittest/python/test_geometry.py") add_python_lib_unit_test("py-complex" "unittest/python/test_complex.py") +add_python_lib_unit_test("py-deprecation-policy" + "unittest/python/test_deprecation_policy.py") add_python_lib_unit_test("py-return-by-ref" "unittest/python/test_return_by_ref.py") add_python_lib_unit_test("py-eigen-ref" "unittest/python/test_eigen_ref.py") diff --git a/unittest/deprecation_policy.cpp b/unittest/deprecation_policy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d06d4954fff9804228b42495f64bc4579b64ed85 --- /dev/null +++ b/unittest/deprecation_policy.cpp @@ -0,0 +1,24 @@ +#include "eigenpy/eigenpy.hpp" +#include "eigenpy/deprecation-policy.hpp" + +#include <iostream> + +namespace bp = boost::python; +using eigenpy::DeprecationType; + +void some_deprecated_function() { + std::cout << "Calling this should produce a warning" << std::endl; +} + +void some_future_deprecated_function() { + std::cout + << "Calling this should produce a warning about a future deprecation" + << std::endl; +} + +BOOST_PYTHON_MODULE(deprecation_policy) { + bp::def("some_deprecated_function", some_deprecated_function, + eigenpy::deprecation_warning_policy<DeprecationType::DEPRECATION>()); + bp::def("some_future_deprecated_function", some_future_deprecated_function, + eigenpy::deprecation_warning_policy<DeprecationType::FUTURE>()); +} diff --git a/unittest/python/test_deprecation_policy.py b/unittest/python/test_deprecation_policy.py new file mode 100644 index 0000000000000000000000000000000000000000..b47550c7536f828e40d764e4f4f7a383fff2d701 --- /dev/null +++ b/unittest/python/test_deprecation_policy.py @@ -0,0 +1,4 @@ +from deprecation_policy import some_deprecated_function, some_future_deprecated_function + +some_deprecated_function() +some_future_deprecated_function()