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; }
+ /// Equivalent to obj == other in Python
+ bool equal(object_api const &other) const { return rich_compare(other, Py_EQ); }
+ bool not_equal(object_api const &other) const { return rich_compare(other, Py_NE); }
+ bool operator<(object_api const &other) const { return rich_compare(other, Py_LT); }
+ bool operator<=(object_api const &other) const { return rich_compare(other, Py_LE); }
+ bool operator>(object_api const &other) const { return rich_compare(other, Py_GT); }
+ bool operator>=(object_api const &other) const { return rich_compare(other, Py_GE); }
+
+ object operator-() const;
+ object operator~() const;
+ object operator+(object_api const &other) const;
+ object operator+=(object_api const &other) const;
+ object operator-(object_api const &other) const;
+ object operator-=(object_api const &other) const;
+ object operator*(object_api const &other) const;
+ object operator*=(object_api const &other) const;
+ object operator/(object_api const &other) const;
+ object operator/=(object_api const &other) const;
+ object operator|(object_api const &other) const;
+ object operator|=(object_api const &other) const;
+ object operator&(object_api const &other) const;
+ object operator&=(object_api const &other) const;
+ object operator^(object_api const &other) const;
+ object operator^=(object_api const &other) const;
+ object operator<<(object_api const &other) const;
+ object operator<<=(object_api const &other) const;
+ object operator>>(object_api const &other) const;
+ object operator>>=(object_api const &other) const;
+
PYBIND11_DEPRECATED("Use py::str(obj) instead")
pybind11::str str() const;
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;
+
+private:
+ bool rich_compare(object_api const &other, int value) const;
};
NAMESPACE_END(detail)
/// 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());
+ PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
}
+ error_already_set(const error_already_set &) = default;
+ error_already_set(error_already_set &&) = default;
+
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()); }
+ void restore() { PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr()); }
// Does nothing; provided for backwards compatibility.
PYBIND11_DEPRECATED("Use of error_already_set.clear() is deprecated")
/// 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()); }
+ bool matches(handle exc) const { return PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()); }
+
+ const object& type() const { return m_type; }
+ const object& value() const { return m_value; }
+ const object& trace() const { return m_trace; }
private:
- object type, value, trace;
+ object m_type, m_value, m_trace;
};
/** \defgroup python_builtins _
return PyObject_HasAttrString(obj.ptr(), name) == 1;
}
+inline void delattr(handle obj, handle name) {
+ if (PyObject_DelAttr(obj.ptr(), name.ptr()) != 0) { throw error_already_set(); }
+}
+
+inline void delattr(handle obj, const char *name) {
+ if (PyObject_DelAttrString(obj.ptr(), name) != 0) { throw error_already_set(); }
+}
+
inline object getattr(handle obj, handle name) {
PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr());
if (!result) { throw error_already_set(); }
// 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;
private:
handle obj;
- PyObject *key, *value;
+ PyObject *key = nullptr, *value = nullptr;
ssize_t pos = -1;
};
NAMESPACE_END(iterator_policies)
}
inline bool PyNone_Check(PyObject *o) { return o == Py_None; }
+#if PY_MAJOR_VERSION >= 3
+inline bool PyEllipsis_Check(PyObject *o) { return o == Py_Ellipsis; }
+#endif
inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); }
+inline bool PyStaticMethod_Check(PyObject *o) { return o->ob_type == &PyStaticMethod_Type; }
+
class kwargs_proxy : public handle {
public:
explicit kwargs_proxy(handle h) : handle(h) { }
none() : object(Py_None, borrowed_t{}) { }
};
+#if PY_MAJOR_VERSION >= 3
+class ellipsis : public object {
+public:
+ PYBIND11_OBJECT(ellipsis, object, detail::PyEllipsis_Check)
+ ellipsis() : object(Py_Ellipsis, borrowed_t{}) { }
+};
+#endif
+
class bool_ : public object {
public:
PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool)
(ssize_t *) stop, (ssize_t *) step,
(ssize_t *) slicelength) == 0;
}
+ bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step,
+ ssize_t *slicelength) const {
+ return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr,
+ length, start,
+ stop, step,
+ slicelength) == 0;
+ }
};
class capsule : public object {
if (!m_ptr) pybind11_fail("Could not allocate tuple object!");
}
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
+ bool empty() const { return size() == 0; }
detail::tuple_accessor operator[](size_t index) const { return {*this, index}; }
+ detail::item_accessor operator[](handle h) const { return object::operator[](h); }
detail::tuple_iterator begin() const { return {*this, 0}; }
detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; }
};
explicit dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) { }
size_t size() const { return (size_t) PyDict_Size(m_ptr); }
+ bool empty() const { return size() == 0; }
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; }
+ template <typename T> bool contains(T &&key) const {
+ return PyDict_Contains(m_ptr, detail::object_or_cast(std::forward<T>(key)).ptr()) == 1;
+ }
private:
/// Call the `dict` Python type -- always returns a new reference
public:
PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check)
size_t size() const { return (size_t) PySequence_Size(m_ptr); }
+ bool empty() const { return size() == 0; }
detail::sequence_accessor operator[](size_t index) const { return {*this, index}; }
+ detail::item_accessor operator[](handle h) const { return object::operator[](h); }
detail::sequence_iterator begin() const { return {*this, 0}; }
detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; }
};
if (!m_ptr) pybind11_fail("Could not allocate list object!");
}
size_t size() const { return (size_t) PyList_Size(m_ptr); }
+ bool empty() const { return size() == 0; }
detail::list_accessor operator[](size_t index) const { return {*this, index}; }
+ detail::item_accessor operator[](handle h) const { return object::operator[](h); }
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());
}
+ template <typename T> void insert(size_t index, T &&val) const {
+ PyList_Insert(m_ptr, static_cast<ssize_t>(index),
+ detail::object_or_cast(std::forward<T>(val)).ptr());
+ }
};
class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) };
if (!m_ptr) pybind11_fail("Could not allocate set object!");
}
size_t size() const { return (size_t) PySet_Size(m_ptr); }
+ bool empty() const { return size() == 0; }
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); }
+ template <typename T> bool contains(T &&val) const {
+ return PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 1;
+ }
};
class function : public object {
bool is_cpp_function() const { return (bool) cpp_function(); }
};
+class staticmethod : public object {
+public:
+ PYBIND11_OBJECT_CVT(staticmethod, object, detail::PyStaticMethod_Check, PyStaticMethod_New)
+};
+
class buffer : public object {
public:
PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer)
- buffer_info request(bool writable = false) {
+ buffer_info request(bool writable = false) const {
int flags = PyBUF_STRIDES | PyBUF_FORMAT;
if (writable) flags |= PyBUF_WRITABLE;
Py_buffer *view = new Py_buffer();
buf.strides = py_strides.data();
buf.shape = py_shape.data();
buf.suboffsets = nullptr;
- buf.readonly = false;
+ buf.readonly = info.readonly;
buf.internal = nullptr;
m_ptr = PyMemoryView_FromBuffer(&buf);
return (size_t) result;
}
+inline size_t len_hint(handle h) {
+#if PY_VERSION_HEX >= 0x03040000
+ ssize_t result = PyObject_LengthHint(h.ptr(), 0);
+#else
+ ssize_t result = PyObject_Length(h.ptr());
+#endif
+ if (result < 0) {
+ // Sometimes a length can't be determined at all (eg generators)
+ // In which case simply return 0
+ PyErr_Clear();
+ return 0;
+ }
+ return (size_t) result;
+}
+
inline str repr(handle h) {
PyObject *str_value = PyObject_Repr(h.ptr());
if (!str_value) throw error_already_set();
template <typename D>
handle object_api<D>::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); }
+template <typename D>
+bool object_api<D>::rich_compare(object_api const &other, int value) const {
+ int rv = PyObject_RichCompareBool(derived().ptr(), other.derived().ptr(), value);
+ if (rv == -1)
+ throw error_already_set();
+ return rv == 1;
+}
+
+#define PYBIND11_MATH_OPERATOR_UNARY(op, fn) \
+ template <typename D> object object_api<D>::op() const { \
+ object result = reinterpret_steal<object>(fn(derived().ptr())); \
+ if (!result.ptr()) \
+ throw error_already_set(); \
+ return result; \
+ }
+
+#define PYBIND11_MATH_OPERATOR_BINARY(op, fn) \
+ template <typename D> \
+ object object_api<D>::op(object_api const &other) const { \
+ object result = reinterpret_steal<object>( \
+ fn(derived().ptr(), other.derived().ptr())); \
+ if (!result.ptr()) \
+ throw error_already_set(); \
+ return result; \
+ }
+
+PYBIND11_MATH_OPERATOR_UNARY (operator~, PyNumber_Invert)
+PYBIND11_MATH_OPERATOR_UNARY (operator-, PyNumber_Negative)
+PYBIND11_MATH_OPERATOR_BINARY(operator+, PyNumber_Add)
+PYBIND11_MATH_OPERATOR_BINARY(operator+=, PyNumber_InPlaceAdd)
+PYBIND11_MATH_OPERATOR_BINARY(operator-, PyNumber_Subtract)
+PYBIND11_MATH_OPERATOR_BINARY(operator-=, PyNumber_InPlaceSubtract)
+PYBIND11_MATH_OPERATOR_BINARY(operator*, PyNumber_Multiply)
+PYBIND11_MATH_OPERATOR_BINARY(operator*=, PyNumber_InPlaceMultiply)
+PYBIND11_MATH_OPERATOR_BINARY(operator/, PyNumber_TrueDivide)
+PYBIND11_MATH_OPERATOR_BINARY(operator/=, PyNumber_InPlaceTrueDivide)
+PYBIND11_MATH_OPERATOR_BINARY(operator|, PyNumber_Or)
+PYBIND11_MATH_OPERATOR_BINARY(operator|=, PyNumber_InPlaceOr)
+PYBIND11_MATH_OPERATOR_BINARY(operator&, PyNumber_And)
+PYBIND11_MATH_OPERATOR_BINARY(operator&=, PyNumber_InPlaceAnd)
+PYBIND11_MATH_OPERATOR_BINARY(operator^, PyNumber_Xor)
+PYBIND11_MATH_OPERATOR_BINARY(operator^=, PyNumber_InPlaceXor)
+PYBIND11_MATH_OPERATOR_BINARY(operator<<, PyNumber_Lshift)
+PYBIND11_MATH_OPERATOR_BINARY(operator<<=, PyNumber_InPlaceLshift)
+PYBIND11_MATH_OPERATOR_BINARY(operator>>, PyNumber_Rshift)
+PYBIND11_MATH_OPERATOR_BINARY(operator>>=, PyNumber_InPlaceRshift)
+
+#undef PYBIND11_MATH_OPERATOR_UNARY
+#undef PYBIND11_MATH_OPERATOR_BINARY
+
NAMESPACE_END(detail)
NAMESPACE_END(PYBIND11_NAMESPACE)