mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 14:45:12 +00:00
Show a deprecation warning for old-style __init__
and __setstate__
The warning is shown at module initialization time (on import, not when the functions are called). It's only visible when compiled in debug mode.
This commit is contained in:
parent
1e5a7da30d
commit
b8c5dbdef5
126
docs/upgrade.rst
126
docs/upgrade.rst
@ -37,6 +37,72 @@ The old macro emits a compile-time deprecation warning.
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
New API for defining custom constructors and pickling functions
|
||||||
|
---------------------------------------------------------------
|
||||||
|
|
||||||
|
The old placement-new custom constructors have been deprecated. The new approach
|
||||||
|
uses ``py::init()`` and factory functions to greatly improve type safety.
|
||||||
|
|
||||||
|
Placement-new can be called accidentally with an incompatible type (without any
|
||||||
|
compiler errors or warnings), or it can initialize the same object multiple times
|
||||||
|
if not careful with the Python-side ``__init__`` calls. The new-style custom
|
||||||
|
constructors prevent such mistakes. See :ref:`custom_constructors` for details.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// old -- deprecated (runtime warning shown only in debug mode)
|
||||||
|
py::class<Foo>(m, "Foo")
|
||||||
|
.def("__init__", [](Foo &self, ...) {
|
||||||
|
new (&self) Foo(...); // uses placement-new
|
||||||
|
});
|
||||||
|
|
||||||
|
// new
|
||||||
|
py::class<Foo>(m, "Foo")
|
||||||
|
.def(py::init([](...) { // Note: no `self` argument
|
||||||
|
return new Foo(...); // return by raw pointer
|
||||||
|
// or: return std::make_unique<Foo>(...); // return by holder
|
||||||
|
// or: return Foo(...); // return by value (move constructor)
|
||||||
|
}));
|
||||||
|
|
||||||
|
Mirroring the custom constructor changes, ``py::pickle()`` is now the preferred
|
||||||
|
way to get and set object state. See :ref:`pickling` for details.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// old -- deprecated (runtime warning shown only in debug mode)
|
||||||
|
py::class<Foo>(m, "Foo")
|
||||||
|
...
|
||||||
|
.def("__getstate__", [](const Foo &self) {
|
||||||
|
return py::make_tuple(self.value1(), self.value2(), ...);
|
||||||
|
})
|
||||||
|
.def("__setstate__", [](Foo &self, py::tuple t) {
|
||||||
|
new (&self) Foo(t[0].cast<std::string>(), ...);
|
||||||
|
});
|
||||||
|
|
||||||
|
// new
|
||||||
|
py::class<Foo>(m, "Foo")
|
||||||
|
...
|
||||||
|
.def(py::pickle(
|
||||||
|
[](const Foo &self) { // __getstate__
|
||||||
|
return py::make_tuple(f.value1(), f.value2(), ...); // unchanged
|
||||||
|
},
|
||||||
|
[](py::tuple t) { // __setstate__, note: no `self` argument
|
||||||
|
return new Foo(t[0].cast<std::string>(), ...);
|
||||||
|
// or: return std::make_unique<Foo>(...); // return by holder
|
||||||
|
// or: return Foo(...); // return by value (move constructor)
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
For both the constructors and pickling, warnings are shown at module
|
||||||
|
initialization time (on import, not when the functions are called).
|
||||||
|
They're only visible when compiled in debug mode. Sample warning:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
pybind11-bound class 'mymodule.Foo' is using an old-style placement-new '__init__'
|
||||||
|
which has been deprecated. See the upgrade guide in pybind11's docs.
|
||||||
|
|
||||||
|
|
||||||
Stricter enforcement of hidden symbol visibility for pybind11 modules
|
Stricter enforcement of hidden symbol visibility for pybind11 modules
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
@ -135,66 +201,6 @@ localize all common type bindings in order to avoid conflicts with
|
|||||||
third-party modules.
|
third-party modules.
|
||||||
|
|
||||||
|
|
||||||
New syntax for custom constructors
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
The old placement-new custom constructors are still valid, but the new approach
|
|
||||||
greatly improves type safety. Placement-new can be called accidentally with an
|
|
||||||
incompatible type (without any compiler errors or warnings), or it can initialize
|
|
||||||
the same object multiple times if not careful with the Python-side ``__init__``
|
|
||||||
calls. The new-style ``py::init()`` custom constructors prevent such mistakes.
|
|
||||||
See :ref:`custom_constructors` for details.
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
|
||||||
|
|
||||||
// old
|
|
||||||
py::class<Foo>(m, "Foo")
|
|
||||||
.def("__init__", [](Foo &self, ...) {
|
|
||||||
new (&self) Foo(...); // uses placement-new
|
|
||||||
});
|
|
||||||
|
|
||||||
// new
|
|
||||||
py::class<Foo>(m, "Foo")
|
|
||||||
.def(py::init([](...) { // Note: no `self` argument
|
|
||||||
return new Foo(...); // return by raw pointer
|
|
||||||
// or: return std::make_unique<Foo>(...); // return by holder
|
|
||||||
// or: return Foo(...); // return by value (move constructor)
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
New syntax for pickling support
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
Mirroring the custom constructor changes, ``py::pickle()`` is now the preferred
|
|
||||||
way to get and set object state. See :ref:`pickling` for details.
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
|
||||||
|
|
||||||
// old -- deprecated
|
|
||||||
py::class<Foo>(m, "Foo")
|
|
||||||
...
|
|
||||||
.def("__getstate__", [](const Foo &self) {
|
|
||||||
return py::make_tuple(self.value1(), self.value2(), ...);
|
|
||||||
})
|
|
||||||
.def("__setstate__", [](Foo &self, py::tuple t) {
|
|
||||||
new (&self) Foo(t[0].cast<std::string>(), ...);
|
|
||||||
});
|
|
||||||
|
|
||||||
// new
|
|
||||||
py::class<Foo>(m, "Foo")
|
|
||||||
...
|
|
||||||
.def(py::pickle(
|
|
||||||
[](const Foo &self) { // __getstate__
|
|
||||||
return py::make_tuple(f.value1(), f.value2(), ...); // unchanged
|
|
||||||
},
|
|
||||||
[](py::tuple t) { // __setstate__, note: no `self` argument
|
|
||||||
return new Foo(t[0].cast<std::string>(), ...);
|
|
||||||
// or: return std::make_unique<Foo>(...); // return by holder
|
|
||||||
// or: return Foo(...); // return by value (move constructor)
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
|
|
||||||
Deprecation of some ``py::object`` APIs
|
Deprecation of some ``py::object`` APIs
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
|
@ -201,6 +201,20 @@ protected:
|
|||||||
|
|
||||||
rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__");
|
rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__");
|
||||||
|
|
||||||
|
#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING)
|
||||||
|
if (rec->is_constructor && !rec->is_new_style_constructor) {
|
||||||
|
const auto class_name = std::string(((PyTypeObject *) rec->scope.ptr())->tp_name);
|
||||||
|
const auto func_name = std::string(rec->name);
|
||||||
|
PyErr_WarnEx(
|
||||||
|
PyExc_FutureWarning,
|
||||||
|
("pybind11-bound class '" + class_name + "' is using an old-style "
|
||||||
|
"placement-new '" + func_name + "' which has been deprecated. See "
|
||||||
|
"the upgrade guide in pybind11's docs. This message is only visible "
|
||||||
|
"when compiled in debug mode.").c_str(), 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Generate a proper function signature */
|
/* Generate a proper function signature */
|
||||||
std::string signature;
|
std::string signature;
|
||||||
size_t type_depth = 0, char_index = 0, type_index = 0, arg_index = 0;
|
size_t type_depth = 0, char_index = 0, type_index = 0, arg_index = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user