将 pybind11-binding 标记为已弃用的最佳方法
Best way to mark a pybind11-binding as deprecated
我有一个 C++ class,使用 pybind11 Python 绑定。
现在我想将一个方法的绑定标记为已弃用。让我们假设它看起来像这样:
PYBIND11_MODULE(my_module, m)
{
pybind11::class_<Foobar>(m, "PyFoobar")
.def("old_foo", &Foobar::foo) // <-- this is deprecated in favour of "new_foo"
.def("new_foo", &Foobar::foo);
}
将 PyFoobar.old_foo()
标记为已弃用以便用户在调用该方法时注意到它的最佳方法是什么?理想情况下,我希望触发 DeprecationWarning
。
我找到了一些方法来获得我想要的大部分内容:对已弃用的绑定使用 lambda。在此 lambda 中,发出警告,然后调用实际函数。在我的示例中,唯一的变化是名称,我只是在 old_foo
中调用 new_foo
。如果绑定的实际函数不同,这将变得更加复杂。
PYBIND11_MODULE(my_module, m)
{
pybind11::class_<Foobar>(m, "PyFoobar")
.def("old_foo",
[](pybind11::object &self, int arg_to_foo)
{
auto warnings = pybind11::module::import("warnings");
warnings.attr("warn")(
"old_foo() is deprecated, use new_foo() instead.");
return self.attr("new_foo")(arg_to_foo);
})
.def("new_foo", &Foobar::foo);
}
这导致
UserWarning: old_foo() is deprecated, use new_foo() instead.
第一次调用old_foo()
时
不幸的是,我还没有弄清楚如何使它成为 DeprecationWarning
而不是 UserWarning
。
好的,这是我的工作示例。我实际上想不出用 Python C 类型调用导入的 python 函数,所以我直接使用 C API,无论如何它应该表现更好
struct Foobar {
Foobar() {}
void foo(int32_t art) {}
};
PYBIND11_MODULE(example, m) {
pybind11::class_<Foobar>(m, "PyFoobar")
.def(py::init<>())
.def("old_foo",
[](pybind11::object &self, int arg_to_foo)
{
PyErr_WarnEx(PyExc_DeprecationWarning,
"old_foo() is deprecated, use new_foo() instead.",
1);
return self.attr("new_foo")(arg_to_foo);
})
.def("new_foo", &Foobar::foo);
}
您可以从此处将任何警告类型作为第一个参数传递:
https://docs.python.org/3/c-api/exceptions.html#standard-warning-categories
最终的 int 是您希望标记为已弃用的堆栈级别。
所以看看这个 python 代码
import example
import warnings
warnings.simplefilter("default")
def mary():
f = example.PyFoobar()
f.old_foo(1)
mary()
如果您将堆栈级别设置为 1
,您将获得
test.py:9: DeprecationWarning: old_foo() is deprecated, use new_foo() instead.
f.old_foo(1)
您可能需要 2
它将为您提供实际的调用上下文,但取决于您的用例是什么
test.py:11: DeprecationWarning: old_foo() is deprecated, use new_foo() instead.
mary()
同样重要的是要注意,默认情况下,python 的许多版本都关闭了弃用警告。您可以通过检查的值来检查这一点
warnings.filters
。这就是为什么在我的示例中我调用 warnings.simplefilter("default")
启用所有类型的警告,但仅在它们第一次被击中时。还有其他方法可以控制它,包括在 运行 python 或环境变量时使用 -W
标志。
https://docs.python.org/3/library/warnings.html#describing-warning-filters
我有一个 C++ class,使用 pybind11 Python 绑定。
现在我想将一个方法的绑定标记为已弃用。让我们假设它看起来像这样:
PYBIND11_MODULE(my_module, m)
{
pybind11::class_<Foobar>(m, "PyFoobar")
.def("old_foo", &Foobar::foo) // <-- this is deprecated in favour of "new_foo"
.def("new_foo", &Foobar::foo);
}
将 PyFoobar.old_foo()
标记为已弃用以便用户在调用该方法时注意到它的最佳方法是什么?理想情况下,我希望触发 DeprecationWarning
。
我找到了一些方法来获得我想要的大部分内容:对已弃用的绑定使用 lambda。在此 lambda 中,发出警告,然后调用实际函数。在我的示例中,唯一的变化是名称,我只是在 old_foo
中调用 new_foo
。如果绑定的实际函数不同,这将变得更加复杂。
PYBIND11_MODULE(my_module, m)
{
pybind11::class_<Foobar>(m, "PyFoobar")
.def("old_foo",
[](pybind11::object &self, int arg_to_foo)
{
auto warnings = pybind11::module::import("warnings");
warnings.attr("warn")(
"old_foo() is deprecated, use new_foo() instead.");
return self.attr("new_foo")(arg_to_foo);
})
.def("new_foo", &Foobar::foo);
}
这导致
UserWarning: old_foo() is deprecated, use new_foo() instead.
第一次调用old_foo()
时
不幸的是,我还没有弄清楚如何使它成为 DeprecationWarning
而不是 UserWarning
。
好的,这是我的工作示例。我实际上想不出用 Python C 类型调用导入的 python 函数,所以我直接使用 C API,无论如何它应该表现更好
struct Foobar {
Foobar() {}
void foo(int32_t art) {}
};
PYBIND11_MODULE(example, m) {
pybind11::class_<Foobar>(m, "PyFoobar")
.def(py::init<>())
.def("old_foo",
[](pybind11::object &self, int arg_to_foo)
{
PyErr_WarnEx(PyExc_DeprecationWarning,
"old_foo() is deprecated, use new_foo() instead.",
1);
return self.attr("new_foo")(arg_to_foo);
})
.def("new_foo", &Foobar::foo);
}
您可以从此处将任何警告类型作为第一个参数传递: https://docs.python.org/3/c-api/exceptions.html#standard-warning-categories
最终的 int 是您希望标记为已弃用的堆栈级别。
所以看看这个 python 代码
import example
import warnings
warnings.simplefilter("default")
def mary():
f = example.PyFoobar()
f.old_foo(1)
mary()
如果您将堆栈级别设置为 1
,您将获得
test.py:9: DeprecationWarning: old_foo() is deprecated, use new_foo() instead.
f.old_foo(1)
您可能需要 2
它将为您提供实际的调用上下文,但取决于您的用例是什么
test.py:11: DeprecationWarning: old_foo() is deprecated, use new_foo() instead.
mary()
同样重要的是要注意,默认情况下,python 的许多版本都关闭了弃用警告。您可以通过检查的值来检查这一点
warnings.filters
。这就是为什么在我的示例中我调用 warnings.simplefilter("default")
启用所有类型的警告,但仅在它们第一次被击中时。还有其他方法可以控制它,包括在 运行 python 或环境变量时使用 -W
标志。
https://docs.python.org/3/library/warnings.html#describing-warning-filters