From 41aa92601ebce548290f6a9efcd66e64216bf972 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 16 Sep 2020 11:32:17 -0400 Subject: [PATCH] refactor: replace .get_type with type::handle_of (#2492) * refactor: replace .get_type with type::handle_of * refactor: use impl for handle_of * fix: deprecate h.get_type() --- docs/changelog.rst | 10 ++++++++-- docs/upgrade.rst | 3 +++ include/pybind11/cast.h | 12 ++++++------ include/pybind11/eigen.h | 2 +- include/pybind11/pybind11.h | 8 ++++---- include/pybind11/pytypes.h | 27 ++++++++++++++++++++------- 6 files changed, 42 insertions(+), 20 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 35460400..448192ff 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -17,10 +17,16 @@ See :ref:`upgrade-guide-2.6` for help upgrading to the new version. This reduces binary size quite substantially (~25%). `#2463 `_ -* Keyword-only argument supported in Python 2 or 3 with ``py::kw_only()``. +* Keyword-only arguments supported in Python 2 or 3 with ``py::kw_only()``. `#2100 `_ -* Positional-only argument supported in Python 2 or 3 with ``py::pos_only()``. +* Positional-only arguments supported in Python 2 or 3 with ``py::pos_only()``. + `#2459 `_ + +* Access to the type object now provided with ``py::type::of()`` and + ``py::type::of(h)``. + `#2364 `_ + * Perfect forwarding support for methods. `#2048 `_ diff --git a/docs/upgrade.rst b/docs/upgrade.rst index 502ce76e..7320cfc0 100644 --- a/docs/upgrade.rst +++ b/docs/upgrade.rst @@ -17,6 +17,9 @@ An error is now thrown when ``__init__`` is forgotten on subclasses. This was incorrect before, but was not checked. Add a call to ``__init__`` if it is missing. +The undocumented ``h.get_type()`` method has been deprecated and replaced by +``py::type::of(h)``. + If ``__eq__`` defined but not ``__hash__``, ``__hash__`` is now set to ``None``, as in normal CPython. You should add ``__hash__`` if you intended the class to be hashable, possibly using the new ``py::hash`` shortcut. diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index e3573e90..b071008e 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -636,7 +636,7 @@ public: /// native typeinfo, or when the native one wasn't able to produce a value. PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) { constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID; - const auto pytype = src.get_type(); + const auto pytype = type::handle_of(src); if (!hasattr(pytype, local_key)) return false; @@ -1130,7 +1130,7 @@ public: } /* Check if this is a C++ type */ - auto &bases = all_type_info((PyTypeObject *) h.get_type().ptr()); + auto &bases = all_type_info((PyTypeObject *) type::handle_of(h).ptr()); if (bases.size() == 1) { // Only allowing loading from a single-value type value = values_and_holders(reinterpret_cast(h.ptr())).begin()->value_ptr(); return true; @@ -1708,7 +1708,7 @@ template type_caster &load_type(type_ca throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)"); #else throw cast_error("Unable to cast Python instance of type " + - (std::string) str(handle.get_type()) + " to C++ type '" + type_id() + "'"); + (std::string) str(type::handle_of(handle)) + " to C++ type '" + type_id() + "'"); #endif } return conv; @@ -1759,7 +1759,7 @@ detail::enable_if_t::value, T> move(object &&obj) { throw cast_error("Unable to cast Python instance to C++ rvalue: instance has multiple references" " (compile in debug mode for details)"); #else - throw cast_error("Unable to move from Python " + (std::string) str(obj.get_type()) + + throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj)) + " instance to C++ " + type_id() + " instance: instance has multiple references"); #endif @@ -2206,13 +2206,13 @@ PYBIND11_NAMESPACE_END(detail) template -type type::of() { +handle type::handle_of() { static_assert( std::is_base_of>::value, "py::type::of only supports the case where T is a registered C++ types." ); - return type((PyObject*) detail::get_type_handle(typeid(T), true).ptr(), borrowed_t()); + return detail::get_type_handle(typeid(T), true); } diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index 22139def..12ce9bd3 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -553,7 +553,7 @@ struct type_caster::value>> { object matrix_type = sparse_module.attr( rowMajor ? "csr_matrix" : "csc_matrix"); - if (!obj.get_type().is(matrix_type)) { + if (!type::handle_of(obj).is(matrix_type)) { try { obj = matrix_type(obj); } catch (const error_already_set &) { diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index af5d9f50..e27a44a7 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1489,7 +1489,7 @@ struct enum_base { m_base.attr("__repr__") = cpp_function( [](handle arg) -> str { - handle type = arg.get_type(); + handle type = type::handle_of(arg); object type_name = type.attr("__name__"); dict entries = type.attr("__entries"); for (const auto &kv : entries) { @@ -1503,7 +1503,7 @@ struct enum_base { m_base.attr("name") = property(cpp_function( [](handle arg) -> str { - dict entries = arg.get_type().attr("__entries"); + dict entries = type::handle_of(arg).attr("__entries"); for (const auto &kv : entries) { if (handle(kv.second[int_(0)]).equal(arg)) return pybind11::str(kv.first); @@ -1542,7 +1542,7 @@ struct enum_base { #define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior) \ m_base.attr(op) = cpp_function( \ [](object a, object b) { \ - if (!a.get_type().is(b.get_type())) \ + if (!type::handle_of(a).is(type::handle_of(b))) \ strict_behavior; \ return expr; \ }, \ @@ -2115,7 +2115,7 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty handle self = get_object_handle(this_ptr, this_type); if (!self) return function(); - handle type = self.get_type(); + handle type = type::handle_of(self); auto key = std::make_pair(type.ptr(), name); /* Cache functions that aren't overridden in Python to avoid diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 9563e22f..a2f7cec4 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -152,7 +152,8 @@ public: /// Return the object's current reference count int ref_count() const { return static_cast(Py_REFCNT(derived().ptr())); } - /// Return a handle to the Python type object underlying the instance + + PYBIND11_DEPRECATED("Call py::type::handle_of(h) or py::type::of(h) instead of h.get_type()") handle get_type() const; private: @@ -897,13 +898,24 @@ class type : public object { public: PYBIND11_OBJECT(type, object, PyType_Check) - static type of(handle h) { return type((PyObject*) Py_TYPE(h.ptr()), borrowed_t{}); } + /// Return a type handle from a handle or an object + static handle handle_of(handle h) { return handle((PyObject*) Py_TYPE(h.ptr())); } - /// Convert C++ type to py::type if previously registered. Does not convert - // standard types, like int, float. etc. yet. - // See https://github.com/pybind/pybind11/issues/2486 + /// Return a type object from a handle or an object + static type of(handle h) { return type(type::handle_of(h), borrowed_t{}); } + + // Defined in pybind11/cast.h + /// Convert C++ type to handle if previously registered. Does not convert + /// standard types, like int, float. etc. yet. + /// See https://github.com/pybind/pybind11/issues/2486 template - static type of(); + static handle handle_of(); + + /// Convert C++ type to type if previously registered. Does not convert + /// standard types, like int, float. etc. yet. + /// See https://github.com/pybind/pybind11/issues/2486 + template + static type of() {return type(type::handle_of(), borrowed_t{}); } }; class iterable : public object { @@ -1568,7 +1580,8 @@ template str_attr_accessor object_api::doc() const { return attr("__doc__"); } template -handle object_api::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); } +PYBIND11_DEPRECATED("Use py::type::of(h) instead of h.get_type()") +handle object_api::get_type() const { return type::handle_of(*this); } template bool object_api::rich_compare(object_api const &other, int value) const {