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()
This commit is contained in:
Henry Schreiner 2020-09-16 11:32:17 -04:00 committed by GitHub
parent a4cee36b6f
commit 41aa92601e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 42 additions and 20 deletions

View File

@ -17,10 +17,16 @@ See :ref:`upgrade-guide-2.6` for help upgrading to the new version.
This reduces binary size quite substantially (~25%). This reduces binary size quite substantially (~25%).
`#2463 <https://github.com/pybind/pybind11/pull/2463>`_ `#2463 <https://github.com/pybind/pybind11/pull/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 <https://github.com/pybind/pybind11/pull/2100>`_ `#2100 <https://github.com/pybind/pybind11/pull/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 <https://github.com/pybind/pybind11/pull/2459>`_
* Access to the type object now provided with ``py::type::of<T>()`` and
``py::type::of(h)``.
`#2364 <https://github.com/pybind/pybind11/pull/2364>`_
* Perfect forwarding support for methods. * Perfect forwarding support for methods.
`#2048 <https://github.com/pybind/pybind11/pull/2048>`_ `#2048 <https://github.com/pybind/pybind11/pull/2048>`_

View File

@ -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 incorrect before, but was not checked. Add a call to ``__init__`` if it is
missing. 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 If ``__eq__`` defined but not ``__hash__``, ``__hash__`` is now set to
``None``, as in normal CPython. You should add ``__hash__`` if you intended the ``None``, as in normal CPython. You should add ``__hash__`` if you intended the
class to be hashable, possibly using the new ``py::hash`` shortcut. class to be hashable, possibly using the new ``py::hash`` shortcut.

View File

@ -636,7 +636,7 @@ public:
/// native typeinfo, or when the native one wasn't able to produce a value. /// native typeinfo, or when the native one wasn't able to produce a value.
PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) { PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) {
constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID; 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)) if (!hasattr(pytype, local_key))
return false; return false;
@ -1130,7 +1130,7 @@ public:
} }
/* Check if this is a C++ type */ /* 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 if (bases.size() == 1) { // Only allowing loading from a single-value type
value = values_and_holders(reinterpret_cast<instance *>(h.ptr())).begin()->value_ptr(); value = values_and_holders(reinterpret_cast<instance *>(h.ptr())).begin()->value_ptr();
return true; return true;
@ -1708,7 +1708,7 @@ template <typename T, typename SFINAE> type_caster<T, SFINAE> &load_type(type_ca
throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)"); throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)");
#else #else
throw cast_error("Unable to cast Python instance of type " + throw cast_error("Unable to cast Python instance of type " +
(std::string) str(handle.get_type()) + " to C++ type '" + type_id<T>() + "'"); (std::string) str(type::handle_of(handle)) + " to C++ type '" + type_id<T>() + "'");
#endif #endif
} }
return conv; return conv;
@ -1759,7 +1759,7 @@ detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
throw cast_error("Unable to cast Python instance to C++ rvalue: instance has multiple references" throw cast_error("Unable to cast Python instance to C++ rvalue: instance has multiple references"
" (compile in debug mode for details)"); " (compile in debug mode for details)");
#else #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<T>() + " instance: instance has multiple references"); " instance to C++ " + type_id<T>() + " instance: instance has multiple references");
#endif #endif
@ -2206,13 +2206,13 @@ PYBIND11_NAMESPACE_END(detail)
template<typename T> template<typename T>
type type::of() { handle type::handle_of() {
static_assert( static_assert(
std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>::value, std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>::value,
"py::type::of<T> only supports the case where T is a registered C++ types." "py::type::of<T> 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);
} }

View File

@ -553,7 +553,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
object matrix_type = sparse_module.attr( object matrix_type = sparse_module.attr(
rowMajor ? "csr_matrix" : "csc_matrix"); rowMajor ? "csr_matrix" : "csc_matrix");
if (!obj.get_type().is(matrix_type)) { if (!type::handle_of(obj).is(matrix_type)) {
try { try {
obj = matrix_type(obj); obj = matrix_type(obj);
} catch (const error_already_set &) { } catch (const error_already_set &) {

View File

@ -1489,7 +1489,7 @@ struct enum_base {
m_base.attr("__repr__") = cpp_function( m_base.attr("__repr__") = cpp_function(
[](handle arg) -> str { [](handle arg) -> str {
handle type = arg.get_type(); handle type = type::handle_of(arg);
object type_name = type.attr("__name__"); object type_name = type.attr("__name__");
dict entries = type.attr("__entries"); dict entries = type.attr("__entries");
for (const auto &kv : entries) { for (const auto &kv : entries) {
@ -1503,7 +1503,7 @@ struct enum_base {
m_base.attr("name") = property(cpp_function( m_base.attr("name") = property(cpp_function(
[](handle arg) -> str { [](handle arg) -> str {
dict entries = arg.get_type().attr("__entries"); dict entries = type::handle_of(arg).attr("__entries");
for (const auto &kv : entries) { for (const auto &kv : entries) {
if (handle(kv.second[int_(0)]).equal(arg)) if (handle(kv.second[int_(0)]).equal(arg))
return pybind11::str(kv.first); return pybind11::str(kv.first);
@ -1542,7 +1542,7 @@ struct enum_base {
#define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior) \ #define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior) \
m_base.attr(op) = cpp_function( \ m_base.attr(op) = cpp_function( \
[](object a, object b) { \ [](object a, object b) { \
if (!a.get_type().is(b.get_type())) \ if (!type::handle_of(a).is(type::handle_of(b))) \
strict_behavior; \ strict_behavior; \
return expr; \ 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); handle self = get_object_handle(this_ptr, this_type);
if (!self) if (!self)
return function(); return function();
handle type = self.get_type(); handle type = type::handle_of(self);
auto key = std::make_pair(type.ptr(), name); auto key = std::make_pair(type.ptr(), name);
/* Cache functions that aren't overridden in Python to avoid /* Cache functions that aren't overridden in Python to avoid

View File

@ -152,7 +152,8 @@ public:
/// Return the object's current reference count /// Return the object's current reference count
int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); } int ref_count() const { return static_cast<int>(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; handle get_type() const;
private: private:
@ -897,13 +898,24 @@ class type : public object {
public: public:
PYBIND11_OBJECT(type, object, PyType_Check) 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 /// Return a type object from a handle or an object
// standard types, like int, float. etc. yet. static type of(handle h) { return type(type::handle_of(h), borrowed_t{}); }
// See https://github.com/pybind/pybind11/issues/2486
// 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<typename T> template<typename T>
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<typename T>
static type of() {return type(type::handle_of<T>(), borrowed_t{}); }
}; };
class iterable : public object { class iterable : public object {
@ -1568,7 +1580,8 @@ template <typename D>
str_attr_accessor object_api<D>::doc() const { return attr("__doc__"); } str_attr_accessor object_api<D>::doc() const { return attr("__doc__"); }
template <typename D> template <typename D>
handle object_api<D>::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); } PYBIND11_DEPRECATED("Use py::type::of(h) instead of h.get_type()")
handle object_api<D>::get_type() const { return type::handle_of(*this); }
template <typename D> template <typename D>
bool object_api<D>::rich_compare(object_api const &other, int value) const { bool object_api<D>::rich_compare(object_api const &other, int value) const {