| /* |
| pybind11/pytypes.h: Convenience wrapper classes for basic Python types |
| |
| Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> |
| |
| All rights reserved. Use of this source code is governed by a |
| BSD-style license that can be found in the LICENSE file. |
| */ |
| |
| #pragma once |
| |
| #include "detail/common.h" |
| #include "buffer_info.h" |
| #include <utility> |
| #include <type_traits> |
| |
| NAMESPACE_BEGIN(PYBIND11_NAMESPACE) |
| |
| /* A few forward declarations */ |
| class handle; class object; |
| class str; class iterator; |
| struct arg; struct arg_v; |
| |
| NAMESPACE_BEGIN(detail) |
| class args_proxy; |
| inline bool isinstance_generic(handle obj, const std::type_info &tp); |
| |
| // Accessor forward declarations |
| template <typename Policy> class accessor; |
| namespace accessor_policies { |
| struct obj_attr; |
| struct str_attr; |
| struct generic_item; |
| struct sequence_item; |
| struct list_item; |
| struct tuple_item; |
| } |
| using obj_attr_accessor = accessor<accessor_policies::obj_attr>; |
| using str_attr_accessor = accessor<accessor_policies::str_attr>; |
| using item_accessor = accessor<accessor_policies::generic_item>; |
| using sequence_accessor = accessor<accessor_policies::sequence_item>; |
| using list_accessor = accessor<accessor_policies::list_item>; |
| 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, remove_reference_t<T>>; |
| |
| /** \rst |
| A mixin class which adds common functions to `handle`, `object` and various accessors. |
| The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``. |
| \endrst */ |
| template <typename Derived> |
| class object_api : public pyobject_tag { |
| const Derived &derived() const { return static_cast<const Derived &>(*this); } |
| |
| public: |
| /** \rst |
| Return an iterator equivalent to calling ``iter()`` in Python. The object |
| must be a collection which supports the iteration protocol. |
| \endrst */ |
| iterator begin() const; |
| /// Return a sentinel which ends iteration. |
| iterator end() const; |
| |
| /** \rst |
| Return an internal functor to invoke the object's sequence protocol. Casting |
| the returned ``detail::item_accessor`` instance to a `handle` or `object` |
| subclass causes a corresponding call to ``__getitem__``. Assigning a `handle` |
| or `object` subclass causes a call to ``__setitem__``. |
| \endrst */ |
| item_accessor operator[](handle key) const; |
| /// See above (the only difference is that they key is provided as a string literal) |
| item_accessor operator[](const char *key) const; |
| |
| /** \rst |
| Return an internal functor to access the object's attributes. Casting the |
| returned ``detail::obj_attr_accessor`` instance to a `handle` or `object` |
| subclass causes a corresponding call to ``getattr``. Assigning a `handle` |
| or `object` subclass causes a call to ``setattr``. |
| \endrst */ |
| obj_attr_accessor attr(handle key) const; |
| /// See above (the only difference is that they key is provided as a string literal) |
| str_attr_accessor attr(const char *key) const; |
| |
| /** \rst |
| Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple`` |
| or ``list`` for a function call. Applying another * to the result yields |
| ** unpacking, e.g. to unpack a dict as function keyword arguments. |
| See :ref:`calling_python_functions`. |
| \endrst */ |
| args_proxy operator*() const; |
| |
| /// Check if the given item is contained within this object, i.e. ``item in obj``. |
| template <typename T> bool contains(T &&item) const; |
| |
| /** \rst |
| Assuming the Python object is a function or implements the ``__call__`` |
| protocol, ``operator()`` invokes the underlying function, passing an |
| arbitrary set of parameters. The result is returned as a `object` and |
| may need to be converted back into a Python object using `handle::cast()`. |
| |
| When some of the arguments cannot be converted to Python objects, the |
| function will throw a `cast_error` exception. When the Python function |
| call fails, a `error_already_set` exception is thrown. |
| \endrst */ |
| template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args> |
| object operator()(Args &&...args) const; |
| template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args> |
| 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 |
| handle get_type() const; |
| }; |
| |
| NAMESPACE_END(detail) |
| |
| /** \rst |
| Holds a reference to a Python object (no reference counting) |
| |
| The `handle` class is a thin wrapper around an arbitrary Python object (i.e. a |
| ``PyObject *`` in Python's C API). It does not perform any automatic reference |
| counting and merely provides a basic C++ interface to various Python API functions. |
| |
| .. seealso:: |
| The `object` class inherits from `handle` and adds automatic reference |
| counting features. |
| \endrst */ |
| class handle : public detail::object_api<handle> { |
| public: |
| /// The default constructor creates a handle with a ``nullptr``-valued pointer |
| handle() = default; |
| /// Creates a ``handle`` from the given raw Python object pointer |
| handle(PyObject *ptr) : m_ptr(ptr) { } // Allow implicit conversion from PyObject* |
| |
| /// Return the underlying ``PyObject *`` pointer |
| PyObject *ptr() const { return m_ptr; } |
| PyObject *&ptr() { return m_ptr; } |
| |
| /** \rst |
| Manually increase the reference count of the Python object. Usually, it is |
| preferable to use the `object` class which derives from `handle` and calls |
| this function automatically. Returns a reference to itself. |
| \endrst */ |
| const handle& inc_ref() const & { Py_XINCREF(m_ptr); return *this; } |
| |
| /** \rst |
| Manually decrease the reference count of the Python object. Usually, it is |
| preferable to use the `object` class which derives from `handle` and calls |
| this function automatically. Returns a reference to itself. |
| \endrst */ |
| const handle& dec_ref() const & { Py_XDECREF(m_ptr); return *this; } |
| |
| /** \rst |
| Attempt to cast the Python object into the given C++ type. A `cast_error` |
| will be throw upon failure. |
| \endrst */ |
| template <typename T> T cast() const; |
| /// Return ``true`` when the `handle` wraps a valid Python object |
| explicit operator bool() const { return m_ptr != nullptr; } |
| /** \rst |
| 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; } |
| protected: |
| PyObject *m_ptr = nullptr; |
| }; |
| |
| /** \rst |
| Holds a reference to a Python object (with reference counting) |
| |
| Like `handle`, the `object` class is a thin wrapper around an arbitrary Python |
| object (i.e. a ``PyObject *`` in Python's C API). In contrast to `handle`, it |
| optionally increases the object's reference count upon construction, and it |
| *always* decreases the reference count when the `object` instance goes out of |
| scope and is destructed. When using `object` instances consistently, it is much |
| easier to get reference counting right at the first attempt. |
| \endrst */ |
| class object : public handle { |
| public: |
| object() = default; |
| PYBIND11_DEPRECATED("Use reinterpret_borrow<object>() or reinterpret_steal<object>()") |
| object(handle h, bool is_borrowed) : handle(h) { if (is_borrowed) inc_ref(); } |
| /// Copy constructor; always increases the reference count |
| object(const object &o) : handle(o) { inc_ref(); } |
| /// Move constructor; steals the object from ``other`` and preserves its reference count |
| object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; } |
| /// Destructor; automatically calls `handle::dec_ref()` |
| ~object() { dec_ref(); } |
| |
| /** \rst |
| Resets the internal pointer to ``nullptr`` without without decreasing the |
| object's reference count. The function returns a raw handle to the original |
| Python object. |
| \endrst */ |
| handle release() { |
| PyObject *tmp = m_ptr; |
| m_ptr = nullptr; |
| return handle(tmp); |
| } |
| |
| object& operator=(const object &other) { |
| other.inc_ref(); |
| dec_ref(); |
| m_ptr = other.m_ptr; |
| return *this; |
| } |
| |
| object& operator=(object &&other) noexcept { |
| if (this != &other) { |
| handle temp(m_ptr); |
| m_ptr = other.m_ptr; |
| other.m_ptr = nullptr; |
| temp.dec_ref(); |
| } |
| return *this; |
| } |
| |
| // Calling cast() on an object lvalue just copies (via handle::cast) |
| template <typename T> T cast() const &; |
| // Calling on an object rvalue does a move, if needed and/or possible |
| template <typename T> T cast() &&; |
| |
| protected: |
| // Tags for choosing constructors from raw PyObject * |
| struct borrowed_t { }; |
| struct stolen_t { }; |
| |
| template <typename T> friend T reinterpret_borrow(handle); |
| template <typename T> friend T reinterpret_steal(handle); |
| |
| public: |
| // Only accessible from derived classes and the reinterpret_* functions |
| object(handle h, borrowed_t) : handle(h) { inc_ref(); } |
| object(handle h, stolen_t) : handle(h) { } |
| }; |
| |
| /** \rst |
| Declare that a `handle` or ``PyObject *`` is a certain type and borrow the reference. |
| The target type ``T`` must be `object` or one of its derived classes. The function |
| doesn't do any conversions or checks. It's up to the user to make sure that the |
| target type is correct. |
| |
| .. code-block:: cpp |
| |
| PyObject *p = PyList_GetItem(obj, index); |
| py::object o = reinterpret_borrow<py::object>(p); |
| // 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_t{}}; } |
| |
| /** \rst |
| Like `reinterpret_borrow`, but steals the reference. |
| |
| .. code-block:: cpp |
| |
| 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_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 |
| as their Python counterparts. |
| */ |
| |
| /** \ingroup python_builtins |
| \rst |
| Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of |
| `object` or a class which was exposed to Python as ``py::class_<T>``. |
| \endrst */ |
| template <typename T, detail::enable_if_t<std::is_base_of<object, T>::value, int> = 0> |
| bool isinstance(handle obj) { return T::check_(obj); } |
| |
| template <typename T, detail::enable_if_t<!std::is_base_of<object, T>::value, int> = 0> |
| bool isinstance(handle obj) { return detail::isinstance_generic(obj, typeid(T)); } |
| |
| template <> inline bool isinstance<handle>(handle obj) = delete; |
| template <> inline bool isinstance<object>(handle obj) { return obj.ptr() != nullptr; } |
| |
| /// \ingroup python_builtins |
| /// Return true if ``obj`` is an instance of the ``type``. |
| inline bool isinstance(handle obj, handle type) { |
| const auto result = PyObject_IsInstance(obj.ptr(), type.ptr()); |
| if (result == -1) |
| throw error_already_set(); |
| return result != 0; |
| } |
| |
| /// \addtogroup python_builtins |
| /// @{ |
| inline bool hasattr(handle obj, handle name) { |
| return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1; |
| } |
| |
| inline bool hasattr(handle obj, const char *name) { |
| return PyObject_HasAttrString(obj.ptr(), name) == 1; |
| } |
| |
| inline object getattr(handle obj, handle name) { |
| PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr()); |
| if (!result) { throw error_already_set(); } |
| return reinterpret_steal<object>(result); |
| } |
| |
| inline object getattr(handle obj, const char *name) { |
| PyObject *result = PyObject_GetAttrString(obj.ptr(), name); |
| if (!result) { throw error_already_set(); } |
| return reinterpret_steal<object>(result); |
| } |
| |
| inline object getattr(handle obj, handle name, handle default_) { |
| if (PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr())) { |
| return reinterpret_steal<object>(result); |
| } else { |
| PyErr_Clear(); |
| return reinterpret_borrow<object>(default_); |
| } |
| } |
| |
| inline object getattr(handle obj, const char *name, handle default_) { |
| if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) { |
| return reinterpret_steal<object>(result); |
| } else { |
| PyErr_Clear(); |
| return reinterpret_borrow<object>(default_); |
| } |
| } |
| |
| inline void setattr(handle obj, handle name, handle value) { |
| if (PyObject_SetAttr(obj.ptr(), name.ptr(), value.ptr()) != 0) { throw error_already_set(); } |
| } |
| |
| 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) |
| inline handle get_function(handle value) { |
| if (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()); |
| } |
| return value; |
| } |
| |
| // Helper aliases/functions to support implicit casting of values given to python accessors/methods. |
| // When given a pyobject, this simply returns the pyobject as-is; for other C++ type, the value goes |
| // through pybind11::cast(obj) to convert it to an `object`. |
| template <typename T, enable_if_t<is_pyobject<T>::value, int> = 0> |
| auto object_or_cast(T &&o) -> decltype(std::forward<T>(o)) { return std::forward<T>(o); } |
| // The following casting version is implemented in cast.h: |
| template <typename T, enable_if_t<!is_pyobject<T>::value, int> = 0> |
| object object_or_cast(T &&o); |
| // Match a PyObject*, which we want to convert directly to handle via its converting constructor |
| inline handle object_or_cast(PyObject *ptr) { return ptr; } |
| |
| |
| template <typename Policy> |
| class accessor : public object_api<accessor<Policy>> { |
| using key_type = typename Policy::key_type; |
| |
| 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). |
| void operator=(const accessor &a) && { std::move(*this).operator=(handle(a)); } |
| void operator=(const accessor &a) & { operator=(handle(a)); } |
| |
| template <typename T> void operator=(T &&value) && { |
| Policy::set(obj, key, object_or_cast(std::forward<T>(value))); |
| } |
| template <typename T> void operator=(T &&value) & { |
| get_cache() = reinterpret_borrow<object>(object_or_cast(std::forward<T>(value))); |
| } |
| |
| template <typename T = Policy> |
| PYBIND11_DEPRECATED("Use of obj.attr(...) as bool is deprecated in favor of pybind11::hasattr(obj, ...)") |
| explicit operator enable_if_t<std::is_same<T, accessor_policies::str_attr>::value || |
| std::is_same<T, accessor_policies::obj_attr>::value, bool>() const { |
| return hasattr(obj, key); |
| } |
| template <typename T = Policy> |
| PYBIND11_DEPRECATED("Use of obj[key] as bool is deprecated in favor of obj.contains(key)") |
| explicit operator enable_if_t<std::is_same<T, accessor_policies::generic_item>::value, bool>() const { |
| return obj.contains(key); |
| } |
| |
| operator object() const { return get_cache(); } |
| PyObject *ptr() const { return get_cache().ptr(); } |
| template <typename T> T cast() const { return get_cache().template cast<T>(); } |
| |
| private: |
| object &get_cache() const { |
| if (!cache) { cache = Policy::get(obj, key); } |
| return cache; |
| } |
| |
| private: |
| handle obj; |
| key_type key; |
| mutable object cache; |
| }; |
| |
| NAMESPACE_BEGIN(accessor_policies) |
| struct obj_attr { |
| using key_type = object; |
| static object get(handle obj, handle key) { return getattr(obj, key); } |
| static void set(handle obj, handle key, handle val) { setattr(obj, key, val); } |
| }; |
| |
| struct str_attr { |
| using key_type = const char *; |
| static object get(handle obj, const char *key) { return getattr(obj, key); } |
| static void set(handle obj, const char *key, handle val) { setattr(obj, key, val); } |
| }; |
| |
| struct generic_item { |
| using key_type = object; |
| |
| static object get(handle obj, handle key) { |
| PyObject *result = PyObject_GetItem(obj.ptr(), key.ptr()); |
| if (!result) { throw error_already_set(); } |
| return reinterpret_steal<object>(result); |
| } |
| |
| static void set(handle obj, handle key, handle val) { |
| if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) { throw error_already_set(); } |
| } |
| }; |
| |
| struct sequence_item { |
| using key_type = size_t; |
| |
| static object get(handle obj, size_t index) { |
| PyObject *result = PySequence_GetItem(obj.ptr(), static_cast<ssize_t>(index)); |
| if (!result) { throw error_already_set(); } |
| return reinterpret_steal<object>(result); |
| } |
| |
| static void set(handle obj, size_t index, handle val) { |
| // PySequence_SetItem does not steal a reference to 'val' |
| if (PySequence_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.ptr()) != 0) { |
| throw error_already_set(); |
| } |
| } |
| }; |
| |
| struct list_item { |
| using key_type = size_t; |
| |
| static object get(handle obj, size_t index) { |
| PyObject *result = PyList_GetItem(obj.ptr(), static_cast<ssize_t>(index)); |
| if (!result) { throw error_already_set(); } |
| return reinterpret_borrow<object>(result); |
| } |
| |
| static void set(handle obj, size_t index, handle val) { |
| // PyList_SetItem steals a reference to 'val' |
| if (PyList_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.inc_ref().ptr()) != 0) { |
| throw error_already_set(); |
| } |
| } |
| }; |
| |
| struct tuple_item { |
| using key_type = size_t; |
| |
| static object get(handle obj, size_t index) { |
| PyObject *result = PyTuple_GetItem(obj.ptr(), static_cast<ssize_t>(index)); |
| if (!result) { throw error_already_set(); } |
| return reinterpret_borrow<object>(result); |
| } |
| |
| static void set(handle obj, size_t index, handle val) { |
| // PyTuple_SetItem steals a reference to 'val' |
| if (PyTuple_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.inc_ref().ptr()) != 0) { |
| throw error_already_set(); |
| } |
| } |
| }; |
| NAMESPACE_END(accessor_policies) |
| |
| /// STL iterator template used for tuple, list, sequence and dict |
| template <typename Policy> |
| class generic_iterator : public Policy { |
| using It = generic_iterator; |
| |
| public: |
| using difference_type = ssize_t; |
| using iterator_category = typename Policy::iterator_category; |
| using value_type = typename Policy::value_type; |
| using reference = typename Policy::reference; |
| using pointer = typename Policy::pointer; |
| |
| generic_iterator() = default; |
| generic_iterator(handle seq, ssize_t index) : Policy(seq, index) { } |
| |
| reference operator*() const { return Policy::dereference(); } |
| reference operator[](difference_type n) const { return *(*this + n); } |
| pointer operator->() const { return **this; } |
| |
| It &operator++() { Policy::increment(); return *this; } |
| It operator++(int) { auto copy = *this; Policy::increment(); return copy; } |
| It &operator--() { Policy::decrement(); return *this; } |
| It operator--(int) { auto copy = *this; Policy::decrement(); return copy; } |
| It &operator+=(difference_type n) { Policy::advance(n); return *this; } |
| It &operator-=(difference_type n) { Policy::advance(-n); return *this; } |
| |
| friend It operator+(const It &a, difference_type n) { auto copy = a; return copy += n; } |
| friend It operator+(difference_type n, const It &b) { return b + n; } |
| friend It operator-(const It &a, difference_type n) { auto copy = a; return copy -= n; } |
| friend difference_type operator-(const It &a, const It &b) { return a.distance_to(b); } |
| |
| friend bool operator==(const It &a, const It &b) { return a.equal(b); } |
| friend bool operator!=(const It &a, const It &b) { return !(a == b); } |
| friend bool operator< (const It &a, const It &b) { return b - a > 0; } |
| friend bool operator> (const It &a, const It &b) { return b < a; } |
| friend bool operator>=(const It &a, const It &b) { return !(a < b); } |
| friend bool operator<=(const It &a, const It &b) { return !(a > b); } |
| }; |
| |
| NAMESPACE_BEGIN(iterator_policies) |
| /// Quick proxy class needed to implement ``operator->`` for iterators which can't return pointers |
| template <typename T> |
| struct arrow_proxy { |
| T value; |
| |
| arrow_proxy(T &&value) : value(std::move(value)) { } |
| T *operator->() const { return &value; } |
| }; |
| |
| /// Lightweight iterator policy using just a simple pointer: see ``PySequence_Fast_ITEMS`` |
| class sequence_fast_readonly { |
| protected: |
| using iterator_category = std::random_access_iterator_tag; |
| using value_type = handle; |
| using reference = const handle; |
| using pointer = arrow_proxy<const handle>; |
| |
| sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) { } |
| |
| reference dereference() const { return *ptr; } |
| void increment() { ++ptr; } |
| void decrement() { --ptr; } |
| void advance(ssize_t n) { ptr += n; } |
| bool equal(const sequence_fast_readonly &b) const { return ptr == b.ptr; } |
| ssize_t distance_to(const sequence_fast_readonly &b) const { return ptr - b.ptr; } |
| |
| private: |
| PyObject **ptr; |
| }; |
| |
| /// Full read and write access using the sequence protocol: see ``detail::sequence_accessor`` |
| class sequence_slow_readwrite { |
| protected: |
| using iterator_category = std::random_access_iterator_tag; |
| using value_type = object; |
| using reference = sequence_accessor; |
| using pointer = arrow_proxy<const sequence_accessor>; |
| |
| sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) { } |
| |
| reference dereference() const { return {obj, static_cast<size_t>(index)}; } |
| void increment() { ++index; } |
| void decrement() { --index; } |
| void advance(ssize_t n) { index += n; } |
| bool equal(const sequence_slow_readwrite &b) const { return index == b.index; } |
| ssize_t distance_to(const sequence_slow_readwrite &b) const { return index - b.index; } |
| |
| private: |
| handle obj; |
| ssize_t index; |
| }; |
| |
| /// Python's dictionary protocol permits this to be a forward iterator |
| class dict_readonly { |
| protected: |
| using iterator_category = std::forward_iterator_tag; |
| using value_type = std::pair<handle, handle>; |
| using reference = const value_type; |
| using pointer = arrow_proxy<const value_type>; |
| |
| dict_readonly() = default; |
| dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); } |
| |
| reference dereference() const { return {key, value}; } |
| void increment() { if (!PyDict_Next(obj.ptr(), &pos, &key, &value)) { pos = -1; } } |
| bool equal(const dict_readonly &b) const { return pos == b.pos; } |
| |
| private: |
| handle obj; |
| PyObject *key, *value; |
| ssize_t pos = -1; |
| }; |
| NAMESPACE_END(iterator_policies) |
| |
| #if !defined(PYPY_VERSION) |
| using tuple_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>; |
| using list_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>; |
| #else |
| using tuple_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>; |
| using list_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>; |
| #endif |
| |
| using sequence_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>; |
| using dict_iterator = generic_iterator<iterator_policies::dict_readonly>; |
| |
| inline bool PyIterable_Check(PyObject *obj) { |
| PyObject *iter = PyObject_GetIter(obj); |
| if (iter) { |
| Py_DECREF(iter); |
| return true; |
| } else { |
| PyErr_Clear(); |
| return false; |
| } |
| } |
| |
| inline bool PyNone_Check(PyObject *o) { return o == Py_None; } |
| |
| inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); } |
| |
| class kwargs_proxy : public handle { |
| public: |
| explicit kwargs_proxy(handle h) : handle(h) { } |
| }; |
| |
| class args_proxy : public handle { |
| public: |
| explicit args_proxy(handle h) : handle(h) { } |
| kwargs_proxy operator*() const { return kwargs_proxy(*this); } |
| }; |
| |
| /// Python argument categories (using PEP 448 terms) |
| template <typename T> using is_keyword = std::is_base_of<arg, T>; |
| template <typename T> using is_s_unpacking = std::is_same<args_proxy, T>; // * unpacking |
| template <typename T> using is_ds_unpacking = std::is_same<kwargs_proxy, T>; // ** unpacking |
| template <typename T> using is_positional = satisfies_none_of<T, |
| is_keyword, is_s_unpacking, is_ds_unpacking |
| >; |
| template <typename T> using is_keyword_or_ds = satisfies_any_of<T, is_keyword, is_ds_unpacking>; |
| |
| // Call argument collector forward declarations |
| template <return_value_policy policy = return_value_policy::automatic_reference> |
| class simple_collector; |
| template <return_value_policy policy = return_value_policy::automatic_reference> |
| class unpacking_collector; |
| |
| NAMESPACE_END(detail) |
| |
| // TODO: After the deprecated constructors are removed, this macro can be simplified by |
| // inheriting ctors: `using Parent::Parent`. It's not an option right now because |
| // the `using` statement triggers the parent deprecation warning even if the ctor |
| // isn't even used. |
| #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_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()); } |
| |
| #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(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) \ |
| /* This is deliberately not 'explicit' to allow implicit conversion from object: */ \ |
| Name(const object &o) : Parent(o) { } \ |
| Name(object &&o) : Parent(std::move(o)) { } |
| |
| #define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \ |
| PYBIND11_OBJECT(Name, Parent, CheckFun) \ |
| Name() : Parent() { } |
| |
| /// \addtogroup pytypes |
| /// @{ |
| |
| /** \rst |
| Wraps a Python iterator so that it can also be used as a C++ input iterator |
| |
| Caveat: copying an iterator does not (and cannot) clone the internal |
| state of the Python iterable. This also applies to the post-increment |
| operator. This iterator should only be used to retrieve the current |
| value using ``operator*()``. |
| \endrst */ |
| class iterator : public object { |
| public: |
| using iterator_category = std::input_iterator_tag; |
| using difference_type = ssize_t; |
| using value_type = handle; |
| using reference = const handle; |
| using pointer = const handle *; |
| |
| PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check) |
| |
| iterator& operator++() { |
| advance(); |
| return *this; |
| } |
| |
| iterator operator++(int) { |
| auto rv = *this; |
| advance(); |
| return rv; |
| } |
| |
| reference operator*() const { |
| if (m_ptr && !value.ptr()) { |
| auto& self = const_cast<iterator &>(*this); |
| self.advance(); |
| } |
| return value; |
| } |
| |
| pointer operator->() const { operator*(); return &value; } |
| |
| /** \rst |
| The value which marks the end of the iteration. ``it == iterator::sentinel()`` |
| is equivalent to catching ``StopIteration`` in Python. |
| |
| .. code-block:: cpp |
| |
| void foo(py::iterator it) { |
| while (it != py::iterator::sentinel()) { |
| // use `*it` |
| ++it; |
| } |
| } |
| \endrst */ |
| static iterator sentinel() { return {}; } |
| |
| friend bool operator==(const iterator &a, const iterator &b) { return a->ptr() == b->ptr(); } |
| friend bool operator!=(const iterator &a, const iterator &b) { return a->ptr() != b->ptr(); } |
| |
| private: |
| void advance() { |
| value = reinterpret_steal<object>(PyIter_Next(m_ptr)); |
| if (PyErr_Occurred()) { throw error_already_set(); } |
| } |
| |
| private: |
| object value = {}; |
| }; |
| |
| class iterable : public object { |
| public: |
| PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check) |
| }; |
| |
| class bytes; |
| |
| class str : public object { |
| 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_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_t{}) { |
| if (!m_ptr) pybind11_fail("Could not allocate string object!"); |
| } |
| |
| str(const std::string &s) : str(s.data(), s.size()) { } |
| |
| explicit str(const bytes &b); |
| |
| /** \rst |
| 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_t{}) { } |
| |
| operator std::string() const { |
| object temp = *this; |
| if (PyUnicode_Check(m_ptr)) { |
| temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(m_ptr)); |
| if (!temp) |
| pybind11_fail("Unable to extract string contents! (encoding issue)"); |
| } |
| char *buffer; |
| ssize_t length; |
| if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) |
| pybind11_fail("Unable to extract string contents! (invalid type)"); |
| return std::string(buffer, (size_t) length); |
| } |
| |
| template <typename... Args> |
| str format(Args &&...args) const { |
| return attr("format")(std::forward<Args>(args)...); |
| } |
| |
| private: |
| /// Return string representation -- always returns a new reference, even if already a str |
| static PyObject *raw_str(PyObject *op) { |
| PyObject *str_value = PyObject_Str(op); |
| #if PY_MAJOR_VERSION < 3 |
| if (!str_value) throw error_already_set(); |
| PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr); |
| Py_XDECREF(str_value); str_value = unicode; |
| #endif |
| return str_value; |
| } |
| }; |
| /// @} pytypes |
| |
| inline namespace literals { |
| /** \rst |
| String literal version of `str` |
| \endrst */ |
| inline str operator"" _s(const char *s, size_t size) { return {s, size}; } |
| } |
| |
| /// \addtogroup pytypes |
| /// @{ |
| class bytes : public object { |
| public: |
| PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK) |
| |
| // Allow implicit conversion: |
| bytes(const char *c = "") |
| : 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_t{}) { |
| if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); |
| } |
| |
| // Allow implicit conversion: |
| bytes(const std::string &s) : bytes(s.data(), s.size()) { } |
| |
| explicit bytes(const pybind11::str &s); |
| |
| operator std::string() const { |
| char *buffer; |
| ssize_t length; |
| if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) |
| pybind11_fail("Unable to extract bytes contents!"); |
| return std::string(buffer, (size_t) length); |
| } |
| }; |
| |
| inline bytes::bytes(const pybind11::str &s) { |
| object temp = s; |
| if (PyUnicode_Check(s.ptr())) { |
| temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr())); |
| if (!temp) |
| pybind11_fail("Unable to extract string contents! (encoding issue)"); |
| } |
| char *buffer; |
| ssize_t length; |
| if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) |
| pybind11_fail("Unable to extract string contents! (invalid type)"); |
| auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length)); |
| if (!obj) |
| pybind11_fail("Could not allocate bytes object!"); |
| m_ptr = obj.release().ptr(); |
| } |
| |
| inline str::str(const bytes& b) { |
| char *buffer; |
| ssize_t length; |
| if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) |
| pybind11_fail("Unable to extract bytes contents!"); |
| auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, (ssize_t) length)); |
| if (!obj) |
| pybind11_fail("Could not allocate string object!"); |
| m_ptr = obj.release().ptr(); |
| } |
| |
| class none : public object { |
| public: |
| PYBIND11_OBJECT(none, object, detail::PyNone_Check) |
| 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_t{}) { } |
| // Allow implicit conversion from and to `bool`: |
| bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) { } |
| operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; } |
| |
| private: |
| /// Return the truth value of an object -- always returns a new reference |
| static PyObject *raw_bool(PyObject *op) { |
| const auto value = PyObject_IsTrue(op); |
| if (value == -1) return nullptr; |
| return handle(value ? Py_True : Py_False).inc_ref().ptr(); |
| } |
| }; |
| |
| 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_t{}) { } |
| // Allow implicit conversion from C++ integral types: |
| template <typename T, |
| detail::enable_if_t<std::is_integral<T>::value, int> = 0> |
| int_(T value) { |
| if (sizeof(T) <= sizeof(long)) { |
| if (std::is_signed<T>::value) |
| m_ptr = PyLong_FromLong((long) value); |
| else |
| m_ptr = PyLong_FromUnsignedLong((unsigned long) value); |
| } else { |
| if (std::is_signed<T>::value) |
| m_ptr = PyLong_FromLongLong((long long) value); |
| else |
| m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value); |
| } |
| if (!m_ptr) pybind11_fail("Could not allocate int object!"); |
| } |
| |
| template <typename T, |
| detail::enable_if_t<std::is_integral<T>::value, int> = 0> |
| operator T() const { |
| 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); |
| } |
| }; |
| |
| 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_t{}) { |
| if (!m_ptr) pybind11_fail("Could not allocate float object!"); |
| } |
| 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); } |
| operator double() const { return (double) PyFloat_AsDouble(m_ptr); } |
| }; |
| |
| 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_t{}) { |
| if (!m_ptr) pybind11_fail("Could not allocate weak reference!"); |
| } |
| }; |
| |
| class slice : public object { |
| public: |
| PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check) |
| slice(ssize_t start_, ssize_t stop_, ssize_t step_) { |
| int_ start(start_), stop(stop_), step(step_); |
| m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr()); |
| if (!m_ptr) pybind11_fail("Could not allocate slice object!"); |
| } |
| bool compute(size_t length, size_t *start, size_t *stop, size_t *step, |
| size_t *slicelength) const { |
| return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, |
| (ssize_t) length, (ssize_t *) start, |
| (ssize_t *) stop, (ssize_t *) step, |
| (ssize_t *) slicelength) == 0; |
| } |
| }; |
| |
| 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_t{}) : object(ptr, stolen_t{})) { } |
| |
| 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_t{}) { |
| if (!m_ptr) |
| pybind11_fail("Could not allocate capsule object!"); |
| } |
| |
| capsule(const void *value, void (*destructor)(void *)) { |
| m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) { |
| auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o)); |
| void *ptr = PyCapsule_GetPointer(o, nullptr); |
| destructor(ptr); |
| }); |
| |
| if (!m_ptr) |
| pybind11_fail("Could not allocate capsule object!"); |
| |
| if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) |
| pybind11_fail("Could not set capsule context!"); |
| } |
| |
| capsule(void (*destructor)()) { |
| m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) { |
| auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, nullptr)); |
| destructor(); |
| }); |
| |
| if (!m_ptr) |
| pybind11_fail("Could not allocate capsule object!"); |
| } |
| |
| template <typename T> operator T *() const { |
| 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_t{}) { |
| if (!m_ptr) pybind11_fail("Could not allocate tuple object!"); |
| } |
| size_t size() const { return (size_t) PyTuple_Size(m_ptr); } |
| detail::tuple_accessor operator[](size_t index) const { return {*this, index}; } |
| detail::tuple_iterator begin() const { return {*this, 0}; } |
| detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; } |
| }; |
| |
| class dict : public object { |
| public: |
| PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict) |
| dict() : object(PyDict_New(), stolen_t{}) { |
| if (!m_ptr) pybind11_fail("Could not allocate dict object!"); |
| } |
| template <typename... Args, |
| typename = detail::enable_if_t<detail::all_of<detail::is_keyword_or_ds<Args>...>::value>, |
| // MSVC workaround: it can't compile an out-of-line definition, so defer the collector |
| typename collector = detail::deferred_t<detail::unpacking_collector<>, Args...>> |
| explicit dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) { } |
| |
| size_t size() const { return (size_t) PyDict_Size(m_ptr); } |
| detail::dict_iterator begin() const { return {*this, 0}; } |
| detail::dict_iterator end() const { return {}; } |
| void clear() const { PyDict_Clear(ptr()); } |
| bool contains(handle key) const { return PyDict_Contains(ptr(), key.ptr()) == 1; } |
| bool contains(const char *key) const { return PyDict_Contains(ptr(), pybind11::str(key).ptr()) == 1; } |
| |
| private: |
| /// Call the `dict` Python type -- always returns a new reference |
| static PyObject *raw_dict(PyObject *op) { |
| if (PyDict_Check(op)) |
| return handle(op).inc_ref().ptr(); |
| return PyObject_CallFunctionObjArgs((PyObject *) &PyDict_Type, op, nullptr); |
| } |
| }; |
| |
| class sequence : public object { |
| public: |
| PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check) |
| size_t size() const { return (size_t) PySequence_Size(m_ptr); } |
| detail::sequence_accessor operator[](size_t index) const { return {*this, index}; } |
| detail::sequence_iterator begin() const { return {*this, 0}; } |
| detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; } |
| }; |
| |
| 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_t{}) { |
| if (!m_ptr) pybind11_fail("Could not allocate list object!"); |
| } |
| size_t size() const { return (size_t) PyList_Size(m_ptr); } |
| detail::list_accessor operator[](size_t index) const { return {*this, index}; } |
| detail::list_iterator begin() const { return {*this, 0}; } |
| detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; } |
| template <typename T> void append(T &&val) const { |
| PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()); |
| } |
| }; |
| |
| class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) }; |
| 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_t{}) { |
| if (!m_ptr) pybind11_fail("Could not allocate set object!"); |
| } |
| size_t size() const { return (size_t) PySet_Size(m_ptr); } |
| template <typename T> bool add(T &&val) const { |
| return PySet_Add(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 0; |
| } |
| void clear() const { PySet_Clear(m_ptr); } |
| }; |
| |
| class function : public object { |
| public: |
| PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check) |
| handle cpp_function() const { |
| handle fun = detail::get_function(m_ptr); |
| if (fun && PyCFunction_Check(fun.ptr())) |
| return fun; |
| return handle(); |
| } |
| bool is_cpp_function() const { return (bool) cpp_function(); } |
| }; |
| |
| class buffer : public object { |
| public: |
| PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer) |
| |
| buffer_info request(bool writable = false) { |
| 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) { |
| delete view; |
| throw error_already_set(); |
| } |
| return buffer_info(view); |
| } |
| }; |
| |
| class memoryview : public object { |
| public: |
| explicit memoryview(const buffer_info& info) { |
| static Py_buffer buf { }; |
| // Py_buffer uses signed sizes, strides and shape!.. |
| static std::vector<Py_ssize_t> py_strides { }; |
| static std::vector<Py_ssize_t> py_shape { }; |
| buf.buf = info.ptr; |
| buf.itemsize = info.itemsize; |
| buf.format = const_cast<char *>(info.format.c_str()); |
| buf.ndim = (int) info.ndim; |
| buf.len = info.size; |
| py_strides.clear(); |
| py_shape.clear(); |
| 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(); |
| buf.suboffsets = nullptr; |
| buf.readonly = false; |
| buf.internal = nullptr; |
| |
| m_ptr = PyMemoryView_FromBuffer(&buf); |
| if (!m_ptr) |
| pybind11_fail("Unable to create memoryview from buffer descriptor"); |
| } |
| |
| PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject) |
| }; |
| /// @} pytypes |
| |
| /// \addtogroup python_builtins |
| /// @{ |
| inline size_t len(handle h) { |
| ssize_t result = PyObject_Length(h.ptr()); |
| if (result < 0) |
| pybind11_fail("Unable to compute length of object"); |
| return (size_t) result; |
| } |
| |
| inline str repr(handle h) { |
| PyObject *str_value = PyObject_Repr(h.ptr()); |
| if (!str_value) throw error_already_set(); |
| #if PY_MAJOR_VERSION < 3 |
| PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr); |
| Py_XDECREF(str_value); str_value = unicode; |
| if (!str_value) throw error_already_set(); |
| #endif |
| return reinterpret_steal<str>(str_value); |
| } |
| |
| inline iterator iter(handle obj) { |
| PyObject *result = PyObject_GetIter(obj.ptr()); |
| if (!result) { throw error_already_set(); } |
| return reinterpret_steal<iterator>(result); |
| } |
| /// @} python_builtins |
| |
| NAMESPACE_BEGIN(detail) |
| template <typename D> iterator object_api<D>::begin() const { return iter(derived()); } |
| template <typename D> iterator object_api<D>::end() const { return iterator::sentinel(); } |
| template <typename D> item_accessor object_api<D>::operator[](handle key) const { |
| return {derived(), reinterpret_borrow<object>(key)}; |
| } |
| template <typename D> item_accessor object_api<D>::operator[](const char *key) const { |
| return {derived(), pybind11::str(key)}; |
| } |
| template <typename D> obj_attr_accessor object_api<D>::attr(handle key) const { |
| return {derived(), reinterpret_borrow<object>(key)}; |
| } |
| template <typename D> str_attr_accessor object_api<D>::attr(const char *key) const { |
| return {derived(), key}; |
| } |
| template <typename D> args_proxy object_api<D>::operator*() const { |
| return args_proxy(derived().ptr()); |
| } |
| template <typename D> template <typename T> bool object_api<D>::contains(T &&item) const { |
| return attr("__contains__")(std::forward<T>(item)).template cast<bool>(); |
| } |
| |
| 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) |