diff options
Diffstat (limited to 'ext/pybind11/include/pybind11/pytypes.h')
-rw-r--r-- | ext/pybind11/include/pybind11/pytypes.h | 196 |
1 files changed, 142 insertions, 54 deletions
diff --git a/ext/pybind11/include/pybind11/pytypes.h b/ext/pybind11/include/pybind11/pytypes.h index 900c57564..d7fa17775 100644 --- a/ext/pybind11/include/pybind11/pytypes.h +++ b/ext/pybind11/include/pybind11/pytypes.h @@ -1,5 +1,5 @@ /* - pybind11/typeid.h: Convenience wrapper classes for basic Python types + pybind11/pytypes.h: Convenience wrapper classes for basic Python types Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> @@ -9,11 +9,12 @@ #pragma once -#include "common.h" +#include "detail/common.h" +#include "buffer_info.h" #include <utility> #include <type_traits> -NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) /* A few forward declarations */ class handle; class object; @@ -43,7 +44,7 @@ using tuple_accessor = accessor<accessor_policies::tuple_item>; /// Tag and check to identify a class which implements the Python object API class pyobject_tag { }; -template <typename T> using is_pyobject = std::is_base_of<pyobject_tag, typename std::remove_reference<T>::type>; +template <typename T> using is_pyobject = std::is_base_of<pyobject_tag, remove_reference_t<T>>; /** \rst A mixin class which adds common functions to `handle`, `object` and various accessors. @@ -109,11 +110,16 @@ public: PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)") object call(Args&&... args) const; + /// Equivalent to ``obj is other`` in Python. + bool is(object_api const& other) const { return derived().ptr() == other.derived().ptr(); } /// Equivalent to ``obj is None`` in Python. bool is_none() const { return derived().ptr() == Py_None; } PYBIND11_DEPRECATED("Use py::str(obj) instead") pybind11::str str() const; + /// Get or set the object's docstring, i.e. ``obj.__doc__``. + str_attr_accessor doc() const; + /// Return the object's current reference count int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); } /// Return a handle to the Python type object underlying the instance @@ -166,10 +172,12 @@ public: /// Return ``true`` when the `handle` wraps a valid Python object explicit operator bool() const { return m_ptr != nullptr; } /** \rst - Check that the underlying pointers are the same. + Deprecated: Check that the underlying pointers are the same. Equivalent to ``obj1 is obj2`` in Python. \endrst */ + PYBIND11_DEPRECATED("Use obj1.is(obj2) instead") bool operator==(const handle &h) const { return m_ptr == h.m_ptr; } + PYBIND11_DEPRECATED("Use !obj1.is(obj2) instead") bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; } PYBIND11_DEPRECATED("Use handle::operator bool() instead") bool check() const { return m_ptr != nullptr; } @@ -234,8 +242,8 @@ public: protected: // Tags for choosing constructors from raw PyObject * - struct borrowed_t { }; static constexpr borrowed_t borrowed{}; - struct stolen_t { }; static constexpr stolen_t stolen{}; + struct borrowed_t { }; + struct stolen_t { }; template <typename T> friend T reinterpret_borrow(handle); template <typename T> friend T reinterpret_steal(handle); @@ -259,7 +267,7 @@ public: // or py::tuple t = reinterpret_borrow<py::tuple>(p); // <-- `p` must be already be a `tuple` \endrst */ -template <typename T> T reinterpret_borrow(handle h) { return {h, object::borrowed}; } +template <typename T> T reinterpret_borrow(handle h) { return {h, object::borrowed_t{}}; } /** \rst Like `reinterpret_borrow`, but steals the reference. @@ -269,7 +277,43 @@ template <typename T> T reinterpret_borrow(handle h) { return {h, object::borrow PyObject *p = PyObject_Str(obj); py::str s = reinterpret_steal<py::str>(p); // <-- `p` must be already be a `str` \endrst */ -template <typename T> T reinterpret_steal(handle h) { return {h, object::stolen}; } +template <typename T> T reinterpret_steal(handle h) { return {h, object::stolen_t{}}; } + +NAMESPACE_BEGIN(detail) +inline std::string error_string(); +NAMESPACE_END(detail) + +/// Fetch and hold an error which was already set in Python. An instance of this is typically +/// thrown to propagate python-side errors back through C++ which can either be caught manually or +/// else falls back to the function dispatcher (which then raises the captured error back to +/// python). +class error_already_set : public std::runtime_error { +public: + /// Constructs a new exception from the current Python error indicator, if any. The current + /// Python error indicator will be cleared. + error_already_set() : std::runtime_error(detail::error_string()) { + PyErr_Fetch(&type.ptr(), &value.ptr(), &trace.ptr()); + } + + inline ~error_already_set(); + + /// Give the currently-held error back to Python, if any. If there is currently a Python error + /// already set it is cleared first. After this call, the current object no longer stores the + /// error variables (but the `.what()` string is still available). + void restore() { PyErr_Restore(type.release().ptr(), value.release().ptr(), trace.release().ptr()); } + + // Does nothing; provided for backwards compatibility. + PYBIND11_DEPRECATED("Use of error_already_set.clear() is deprecated") + void clear() {} + + /// Check if the currently trapped error type matches the given Python exception class (or a + /// subclass thereof). May also be passed a tuple to search for any exception class matches in + /// the given tuple. + bool matches(handle ex) const { return PyErr_GivenExceptionMatches(ex.ptr(), type.ptr()); } + +private: + object type, value, trace; +}; /** \defgroup python_builtins _ Unless stated otherwise, the following C++ functions behave the same @@ -346,6 +390,13 @@ inline void setattr(handle obj, handle name, handle value) { inline void setattr(handle obj, const char *name, handle value) { if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); } } + +inline ssize_t hash(handle obj) { + auto h = PyObject_Hash(obj.ptr()); + if (h == -1) { throw error_already_set(); } + return h; +} + /// @} python_builtins NAMESPACE_BEGIN(detail) @@ -354,6 +405,7 @@ inline handle get_function(handle value) { #if PY_MAJOR_VERSION >= 3 if (PyInstanceMethod_Check(value.ptr())) value = PyInstanceMethod_GET_FUNCTION(value.ptr()); + else #endif if (PyMethod_Check(value.ptr())) value = PyMethod_GET_FUNCTION(value.ptr()); @@ -379,6 +431,8 @@ class accessor : public object_api<accessor<Policy>> { public: accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) { } + accessor(const accessor &) = default; + accessor(accessor &&) = default; // accessor overload required to override default assignment operator (templates are not allowed // to replace default compiler-generated assignments). @@ -674,9 +728,9 @@ NAMESPACE_END(detail) #define PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ public: \ PYBIND11_DEPRECATED("Use reinterpret_borrow<"#Name">() or reinterpret_steal<"#Name">()") \ - Name(handle h, bool is_borrowed) : Parent(is_borrowed ? Parent(h, borrowed) : Parent(h, stolen)) { } \ - Name(handle h, borrowed_t) : Parent(h, borrowed) { } \ - Name(handle h, stolen_t) : Parent(h, stolen) { } \ + Name(handle h, bool is_borrowed) : Parent(is_borrowed ? Parent(h, borrowed_t{}) : Parent(h, stolen_t{})) { } \ + Name(handle h, borrowed_t) : Parent(h, borrowed_t{}) { } \ + Name(handle h, stolen_t) : Parent(h, stolen_t{}) { } \ PYBIND11_DEPRECATED("Use py::isinstance<py::python_type>(obj) instead") \ bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } \ static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } @@ -684,7 +738,14 @@ NAMESPACE_END(detail) #define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \ PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ /* This is deliberately not 'explicit' to allow implicit conversion from object: */ \ - Name(const object &o) : Parent(ConvertFun(o.ptr()), stolen) { if (!m_ptr) throw error_already_set(); } + Name(const object &o) \ + : Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) \ + { if (!m_ptr) throw error_already_set(); } \ + Name(object &&o) \ + : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) \ + { if (!m_ptr) throw error_already_set(); } \ + template <typename Policy_> \ + Name(const ::pybind11::detail::accessor<Policy_> &a) : Name(object(a)) { } #define PYBIND11_OBJECT(Name, Parent, CheckFun) \ PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ @@ -778,13 +839,13 @@ public: PYBIND11_OBJECT_CVT(str, object, detail::PyUnicode_Check_Permissive, raw_str) str(const char *c, size_t n) - : object(PyUnicode_FromStringAndSize(c, (ssize_t) n), stolen) { + : object(PyUnicode_FromStringAndSize(c, (ssize_t) n), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate string object!"); } // 'explicit' is explicitly omitted from the following constructors to allow implicit conversion to py::str from C++ string-like objects str(const char *c = "") - : object(PyUnicode_FromString(c), stolen) { + : object(PyUnicode_FromString(c), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate string object!"); } @@ -796,7 +857,7 @@ public: Return a string representation of the object. This is analogous to the ``str()`` function in Python. \endrst */ - explicit str(handle h) : object(raw_str(h.ptr()), stolen) { } + explicit str(handle h) : object(raw_str(h.ptr()), stolen_t{}) { } operator std::string() const { object temp = *this; @@ -846,12 +907,12 @@ public: // Allow implicit conversion: bytes(const char *c = "") - : object(PYBIND11_BYTES_FROM_STRING(c), stolen) { + : object(PYBIND11_BYTES_FROM_STRING(c), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); } bytes(const char *c, size_t n) - : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, (ssize_t) n), stolen) { + : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, (ssize_t) n), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); } @@ -900,15 +961,15 @@ inline str::str(const bytes& b) { class none : public object { public: PYBIND11_OBJECT(none, object, detail::PyNone_Check) - none() : object(Py_None, borrowed) { } + none() : object(Py_None, borrowed_t{}) { } }; class bool_ : public object { public: PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool) - bool_() : object(Py_False, borrowed) { } + bool_() : object(Py_False, borrowed_t{}) { } // Allow implicit conversion from and to `bool`: - bool_(bool value) : object(value ? Py_True : Py_False, borrowed) { } + bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) { } operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; } private: @@ -920,10 +981,32 @@ private: } }; +NAMESPACE_BEGIN(detail) +// Converts a value to the given unsigned type. If an error occurs, you get back (Unsigned) -1; +// otherwise you get back the unsigned long or unsigned long long value cast to (Unsigned). +// (The distinction is critically important when casting a returned -1 error value to some other +// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes). +template <typename Unsigned> +Unsigned as_unsigned(PyObject *o) { + if (sizeof(Unsigned) <= sizeof(unsigned long) +#if PY_VERSION_HEX < 0x03000000 + || PyInt_Check(o) +#endif + ) { + unsigned long v = PyLong_AsUnsignedLong(o); + return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; + } + else { + unsigned long long v = PyLong_AsUnsignedLongLong(o); + return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; + } +} +NAMESPACE_END(detail) + class int_ : public object { public: PYBIND11_OBJECT_CVT(int_, object, PYBIND11_LONG_CHECK, PyNumber_Long) - int_() : object(PyLong_FromLong(0), stolen) { } + int_() : object(PyLong_FromLong(0), stolen_t{}) { } // Allow implicit conversion from C++ integral types: template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0> @@ -945,17 +1028,11 @@ public: template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0> operator T() const { - if (sizeof(T) <= sizeof(long)) { - if (std::is_signed<T>::value) - return (T) PyLong_AsLong(m_ptr); - else - return (T) PyLong_AsUnsignedLong(m_ptr); - } else { - if (std::is_signed<T>::value) - return (T) PYBIND11_LONG_AS_LONGLONG(m_ptr); - else - return (T) PYBIND11_LONG_AS_UNSIGNED_LONGLONG(m_ptr); - } + return std::is_unsigned<T>::value + ? detail::as_unsigned<T>(m_ptr) + : sizeof(T) <= sizeof(long) + ? (T) PyLong_AsLong(m_ptr) + : (T) PYBIND11_LONG_AS_LONGLONG(m_ptr); } }; @@ -963,10 +1040,10 @@ class float_ : public object { public: PYBIND11_OBJECT_CVT(float_, object, PyFloat_Check, PyNumber_Float) // Allow implicit conversion from float/double: - float_(float value) : object(PyFloat_FromDouble((double) value), stolen) { + float_(float value) : object(PyFloat_FromDouble((double) value), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate float object!"); } - float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen) { + float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate float object!"); } operator float() const { return (float) PyFloat_AsDouble(m_ptr); } @@ -977,7 +1054,7 @@ class weakref : public object { public: PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check) explicit weakref(handle obj, handle callback = {}) - : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen) { + : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate weak reference!"); } }; @@ -1003,17 +1080,17 @@ class capsule : public object { public: PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact) PYBIND11_DEPRECATED("Use reinterpret_borrow<capsule>() or reinterpret_steal<capsule>()") - capsule(PyObject *ptr, bool is_borrowed) : object(is_borrowed ? object(ptr, borrowed) : object(ptr, stolen)) { } + capsule(PyObject *ptr, bool is_borrowed) : object(is_borrowed ? object(ptr, borrowed_t{}) : object(ptr, stolen_t{})) { } - explicit capsule(const void *value) - : object(PyCapsule_New(const_cast<void *>(value), nullptr, nullptr), stolen) { + explicit capsule(const void *value, const char *name = nullptr, void (*destructor)(PyObject *) = nullptr) + : object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate capsule object!"); } PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input") capsule(const void *value, void (*destruct)(PyObject *)) - : object(PyCapsule_New(const_cast<void*>(value), nullptr, destruct), stolen) { + : object(PyCapsule_New(const_cast<void*>(value), nullptr, destruct), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate capsule object!"); } @@ -1043,16 +1120,19 @@ public: } template <typename T> operator T *() const { - T * result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, nullptr)); + auto name = this->name(); + T * result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name)); if (!result) pybind11_fail("Unable to extract capsule contents!"); return result; } + + const char *name() const { return PyCapsule_GetName(m_ptr); } }; class tuple : public object { public: PYBIND11_OBJECT_CVT(tuple, object, PyTuple_Check, PySequence_Tuple) - explicit tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), stolen) { + explicit tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate tuple object!"); } size_t size() const { return (size_t) PyTuple_Size(m_ptr); } @@ -1064,7 +1144,7 @@ public: class dict : public object { public: PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict) - dict() : object(PyDict_New(), stolen) { + dict() : object(PyDict_New(), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate dict object!"); } template <typename... Args, @@ -1101,7 +1181,7 @@ public: class list : public object { public: PYBIND11_OBJECT_CVT(list, object, PyList_Check, PySequence_List) - explicit list(size_t size = 0) : object(PyList_New((ssize_t) size), stolen) { + explicit list(size_t size = 0) : object(PyList_New((ssize_t) size), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate list object!"); } size_t size() const { return (size_t) PyList_Size(m_ptr); } @@ -1119,7 +1199,7 @@ class kwargs : public dict { PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check) class set : public object { public: PYBIND11_OBJECT_CVT(set, object, PySet_Check, PySet_New) - set() : object(PySet_New(nullptr), stolen) { + set() : object(PySet_New(nullptr), stolen_t{}) { if (!m_ptr) pybind11_fail("Could not allocate set object!"); } size_t size() const { return (size_t) PySet_Size(m_ptr); } @@ -1132,10 +1212,13 @@ public: class function : public object { public: PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check) - bool is_cpp_function() const { + handle cpp_function() const { handle fun = detail::get_function(m_ptr); - return fun && PyCFunction_Check(fun.ptr()); + if (fun && PyCFunction_Check(fun.ptr())) + return fun; + return handle(); } + bool is_cpp_function() const { return (bool) cpp_function(); } }; class buffer : public object { @@ -1146,8 +1229,10 @@ public: int flags = PyBUF_STRIDES | PyBUF_FORMAT; if (writable) flags |= PyBUF_WRITABLE; Py_buffer *view = new Py_buffer(); - if (PyObject_GetBuffer(m_ptr, view, flags) != 0) + if (PyObject_GetBuffer(m_ptr, view, flags) != 0) { + delete view; throw error_already_set(); + } return buffer_info(view); } }; @@ -1160,15 +1245,15 @@ public: static std::vector<Py_ssize_t> py_strides { }; static std::vector<Py_ssize_t> py_shape { }; buf.buf = info.ptr; - buf.itemsize = (Py_ssize_t) info.itemsize; + buf.itemsize = info.itemsize; buf.format = const_cast<char *>(info.format.c_str()); buf.ndim = (int) info.ndim; - buf.len = (Py_ssize_t) info.size; + buf.len = info.size; py_strides.clear(); py_shape.clear(); - for (size_t i = 0; i < info.ndim; ++i) { - py_strides.push_back((Py_ssize_t) info.strides[i]); - py_shape.push_back((Py_ssize_t) info.shape[i]); + for (size_t i = 0; i < (size_t) info.ndim; ++i) { + py_strides.push_back(info.strides[i]); + py_shape.push_back(info.shape[i]); } buf.strides = py_strides.data(); buf.shape = py_shape.data(); @@ -1238,7 +1323,10 @@ template <typename D> pybind11::str object_api<D>::str() const { return pybind11::str(derived()); } template <typename D> +str_attr_accessor object_api<D>::doc() const { return attr("__doc__"); } + +template <typename D> handle object_api<D>::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); } NAMESPACE_END(detail) -NAMESPACE_END(pybind11) +NAMESPACE_END(PYBIND11_NAMESPACE) |