Commit ec24786e by Ralf W. Grosse-Kunstleve Committed by GitHub

Fully-automatic clang-format with include reordering (#3713)

* chore: add clang-format

* Removing check-style (Classic check-style)

Ported from @henryiii's https://github.com/pybind/pybind11/pull/3683/commits/53056b1b0eeb4136b0d7362a8261b6b59658e0a7

* Automatic clang-format changes (NO manual changes).

Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
parent e96221be
...@@ -141,11 +141,7 @@ repos: ...@@ -141,11 +141,7 @@ repos:
entry: PyBind|Numpy|Cmake|CCache|PyTest entry: PyBind|Numpy|Cmake|CCache|PyTest
exclude: .pre-commit-config.yaml exclude: .pre-commit-config.yaml
- repo: local - repo: https://github.com/pre-commit/mirrors-clang-format
rev: "v13.0.0"
hooks: hooks:
- id: check-style - id: clang-format
name: Classic check-style
language: system
types:
- c++
entry: ./tools/check-style.sh
...@@ -44,8 +44,8 @@ struct buffer_info { ...@@ -44,8 +44,8 @@ struct buffer_info {
void *ptr = nullptr; // Pointer to the underlying storage void *ptr = nullptr; // Pointer to the underlying storage
ssize_t itemsize = 0; // Size of individual items in bytes ssize_t itemsize = 0; // Size of individual items in bytes
ssize_t size = 0; // Total number of entries ssize_t size = 0; // Total number of entries
std::string format; // For homogeneous buffers, this should be set to std::string format; // For homogeneous buffers, this should be set to
// format_descriptor<T>::format() // format_descriptor<T>::format()
ssize_t ndim = 0; // Number of dimensions ssize_t ndim = 0; // Number of dimensions
std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension) std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension)
std::vector<ssize_t> strides; // Number of bytes between adjacent entries std::vector<ssize_t> strides; // Number of bytes between adjacent entries
...@@ -54,10 +54,15 @@ struct buffer_info { ...@@ -54,10 +54,15 @@ struct buffer_info {
buffer_info() = default; buffer_info() = default;
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, buffer_info(void *ptr,
detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in, bool readonly=false) ssize_t itemsize,
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), const std::string &format,
shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) { ssize_t ndim,
detail::any_container<ssize_t> shape_in,
detail::any_container<ssize_t> strides_in,
bool readonly = false)
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) {
if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) { if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) {
pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
} }
...@@ -67,29 +72,48 @@ struct buffer_info { ...@@ -67,29 +72,48 @@ struct buffer_info {
} }
template <typename T> template <typename T>
buffer_info(T *ptr, detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in, bool readonly=false) buffer_info(T *ptr,
: buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor<T>::format(), static_cast<ssize_t>(shape_in->size()), std::move(shape_in), std::move(strides_in), readonly) { } detail::any_container<ssize_t> shape_in,
detail::any_container<ssize_t> strides_in,
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size, bool readonly=false) bool readonly = false)
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) { } : buffer_info(private_ctr_tag(),
ptr,
sizeof(T),
format_descriptor<T>::format(),
static_cast<ssize_t>(shape_in->size()),
std::move(shape_in),
std::move(strides_in),
readonly) {}
buffer_info(void *ptr,
ssize_t itemsize,
const std::string &format,
ssize_t size,
bool readonly = false)
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) {}
template <typename T> template <typename T>
buffer_info(T *ptr, ssize_t size, bool readonly=false) buffer_info(T *ptr, ssize_t size, bool readonly = false)
: buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) { } : buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) {}
template <typename T> template <typename T>
buffer_info(const T *ptr, ssize_t size, bool readonly=true) buffer_info(const T *ptr, ssize_t size, bool readonly = true)
: buffer_info(const_cast<T*>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) { } : buffer_info(
const_cast<T *>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) {}
explicit buffer_info(Py_buffer *view, bool ownview = true) explicit buffer_info(Py_buffer *view, bool ownview = true)
: buffer_info(view->buf, view->itemsize, view->format, view->ndim, : buffer_info(
view->buf,
view->itemsize,
view->format,
view->ndim,
{view->shape, view->shape + view->ndim}, {view->shape, view->shape + view->ndim},
/* Though buffer::request() requests PyBUF_STRIDES, ctypes objects /* Though buffer::request() requests PyBUF_STRIDES, ctypes objects
* ignore this flag and return a view with NULL strides. * ignore this flag and return a view with NULL strides.
* When strides are NULL, build them manually. */ * When strides are NULL, build them manually. */
view->strides view->strides
? std::vector<ssize_t>(view->strides, view->strides + view->ndim) ? std::vector<ssize_t>(view->strides, view->strides + view->ndim)
: detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize), : detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize),
(view->readonly != 0)) { (view->readonly != 0)) {
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
this->m_view = view; this->m_view = view;
...@@ -98,7 +122,7 @@ struct buffer_info { ...@@ -98,7 +122,7 @@ struct buffer_info {
} }
buffer_info(const buffer_info &) = delete; buffer_info(const buffer_info &) = delete;
buffer_info& operator=(const buffer_info &) = delete; buffer_info &operator=(const buffer_info &) = delete;
buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); } buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); }
...@@ -117,17 +141,28 @@ struct buffer_info { ...@@ -117,17 +141,28 @@ struct buffer_info {
} }
~buffer_info() { ~buffer_info() {
if (m_view && ownview) { PyBuffer_Release(m_view); delete m_view; } if (m_view && ownview) {
PyBuffer_Release(m_view);
delete m_view;
}
} }
Py_buffer *view() const { return m_view; } Py_buffer *view() const { return m_view; }
Py_buffer *&view() { return m_view; } Py_buffer *&view() { return m_view; }
private:
struct private_ctr_tag { };
buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, private:
detail::any_container<ssize_t> &&shape_in, detail::any_container<ssize_t> &&strides_in, bool readonly) struct private_ctr_tag {};
: buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) { }
buffer_info(private_ctr_tag,
void *ptr,
ssize_t itemsize,
const std::string &format,
ssize_t ndim,
detail::any_container<ssize_t> &&shape_in,
detail::any_container<ssize_t> &&strides_in,
bool readonly)
: buffer_info(
ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {}
Py_buffer *m_view = nullptr; Py_buffer *m_view = nullptr;
bool ownview = false; bool ownview = false;
...@@ -135,17 +170,22 @@ private: ...@@ -135,17 +170,22 @@ private:
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
template <typename T, typename SFINAE = void> struct compare_buffer_info { template <typename T, typename SFINAE = void>
static bool compare(const buffer_info& b) { struct compare_buffer_info {
static bool compare(const buffer_info &b) {
return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T); return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);
} }
}; };
template <typename T> struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> { template <typename T>
static bool compare(const buffer_info& b) { struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value || static bool compare(const buffer_info &b) {
((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned<T>::value ? "L" : "l")) || return (size_t) b.itemsize == sizeof(T)
((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned<T>::value ? "N" : "n"))); && (b.format == format_descriptor<T>::value
|| ((sizeof(T) == sizeof(long))
&& b.format == (std::is_unsigned<T>::value ? "L" : "l"))
|| ((sizeof(T) == sizeof(size_t))
&& b.format == (std::is_unsigned<T>::value ? "N" : "n")));
} }
}; };
......
...@@ -10,36 +10,42 @@ ...@@ -10,36 +10,42 @@
#pragma once #pragma once
#include "pybind11.h" #include "pybind11.h"
#include <complex> #include <complex>
/// glibc defines I as a macro which breaks things, e.g., boost template names /// glibc defines I as a macro which breaks things, e.g., boost template names
#ifdef I #ifdef I
# undef I # undef I
#endif #endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
template <typename T> struct format_descriptor<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> { template <typename T>
struct format_descriptor<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
static constexpr const char c = format_descriptor<T>::c; static constexpr const char c = format_descriptor<T>::c;
static constexpr const char value[3] = { 'Z', c, '\0' }; static constexpr const char value[3] = {'Z', c, '\0'};
static std::string format() { return std::string(value); } static std::string format() { return std::string(value); }
}; };
#ifndef PYBIND11_CPP17 #ifndef PYBIND11_CPP17
template <typename T> constexpr const char format_descriptor< template <typename T>
std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>>::value[3]; constexpr const char
format_descriptor<std::complex<T>,
detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];
#endif #endif
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> { template <typename T>
struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
static constexpr bool value = true; static constexpr bool value = true;
static constexpr int index = is_fmt_numeric<T>::index + 3; static constexpr int index = is_fmt_numeric<T>::index + 3;
}; };
template <typename T> class type_caster<std::complex<T>> { template <typename T>
class type_caster<std::complex<T>> {
public: public:
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
if (!src) { if (!src) {
...@@ -57,7 +63,8 @@ public: ...@@ -57,7 +63,8 @@ public:
return true; return true;
} }
static handle cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) { static handle
cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
return PyComplex_FromDoubles((double) src.real(), (double) src.imag()); return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
} }
......
...@@ -16,12 +16,13 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) ...@@ -16,12 +16,13 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
#if PY_VERSION_HEX >= 0x03030000 && !defined(PYPY_VERSION) #if PY_VERSION_HEX >= 0x03030000 && !defined(PYPY_VERSION)
# define PYBIND11_BUILTIN_QUALNAME # define PYBIND11_BUILTIN_QUALNAME
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) # define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)
#else #else
// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type // In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type
// signatures; in 3.3+ this macro expands to nothing: // signatures; in 3.3+ this macro expands to nothing:
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) setattr((PyObject *) obj, "__qualname__", nameobj) # define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) \
setattr((PyObject *) obj, "__qualname__", nameobj)
#endif #endif
inline std::string get_fully_qualified_tp_name(PyTypeObject *type) { inline std::string get_fully_qualified_tp_name(PyTypeObject *type) {
...@@ -71,9 +72,9 @@ inline PyTypeObject *make_static_property_type() { ...@@ -71,9 +72,9 @@ inline PyTypeObject *make_static_property_type() {
} }
heap_type->ht_name = name_obj.inc_ref().ptr(); heap_type->ht_name = name_obj.inc_ref().ptr();
#ifdef PYBIND11_BUILTIN_QUALNAME # ifdef PYBIND11_BUILTIN_QUALNAME
heap_type->ht_qualname = name_obj.inc_ref().ptr(); heap_type->ht_qualname = name_obj.inc_ref().ptr();
#endif # endif
auto *type = &heap_type->ht_type; auto *type = &heap_type->ht_type;
type->tp_name = name; type->tp_name = name;
...@@ -107,8 +108,10 @@ inline PyTypeObject *make_static_property_type() { ...@@ -107,8 +108,10 @@ inline PyTypeObject *make_static_property_type() {
def __set__(self, obj, value): def __set__(self, obj, value):
cls = obj if isinstance(obj, type) else type(obj) cls = obj if isinstance(obj, type) else type(obj)
property.__set__(self, cls, value) property.__set__(self, cls, value)
)", Py_file_input, d.ptr(), d.ptr() )",
); Py_file_input,
d.ptr(),
d.ptr());
if (result == nullptr) if (result == nullptr)
throw error_already_set(); throw error_already_set();
Py_DECREF(result); Py_DECREF(result);
...@@ -121,7 +124,7 @@ inline PyTypeObject *make_static_property_type() { ...@@ -121,7 +124,7 @@ inline PyTypeObject *make_static_property_type() {
By default, Python replaces the `static_property` itself, but for wrapped C++ types By default, Python replaces the `static_property` itself, but for wrapped C++ types
we need to call `static_property.__set__()` in order to propagate the new value to we need to call `static_property.__set__()` in order to propagate the new value to
the underlying C++ data structure. */ the underlying C++ data structure. */
extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyObject* value) { extern "C" inline int pybind11_meta_setattro(PyObject *obj, PyObject *name, PyObject *value) {
// Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw // Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw
// descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`). // descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`).
PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name); PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
...@@ -184,7 +187,8 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P ...@@ -184,7 +187,8 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
// Ensure that the base __init__ function(s) were called // Ensure that the base __init__ function(s) were called
for (const auto &vh : values_and_holders(instance)) { for (const auto &vh : values_and_holders(instance)) {
if (!vh.holder_constructed()) { if (!vh.holder_constructed()) {
PyErr_Format(PyExc_TypeError, "%.200s.__init__() must be called when overriding __init__", PyErr_Format(PyExc_TypeError,
"%.200s.__init__() must be called when overriding __init__",
get_fully_qualified_tp_name(vh.type->type).c_str()); get_fully_qualified_tp_name(vh.type->type).c_str());
Py_DECREF(self); Py_DECREF(self);
return nullptr; return nullptr;
...@@ -203,9 +207,8 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) { ...@@ -203,9 +207,8 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
// 1) be found in internals.registered_types_py // 1) be found in internals.registered_types_py
// 2) have exactly one associated `detail::type_info` // 2) have exactly one associated `detail::type_info`
auto found_type = internals.registered_types_py.find(type); auto found_type = internals.registered_types_py.find(type);
if (found_type != internals.registered_types_py.end() && if (found_type != internals.registered_types_py.end() && found_type->second.size() == 1
found_type->second.size() == 1 && && found_type->second[0]->type == type) {
found_type->second[0]->type == type) {
auto *tinfo = found_type->second[0]; auto *tinfo = found_type->second[0];
auto tindex = std::type_index(*tinfo->cpptype); auto tindex = std::type_index(*tinfo->cpptype);
...@@ -220,7 +223,7 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) { ...@@ -220,7 +223,7 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
// Actually just `std::erase_if`, but that's only available in C++20 // Actually just `std::erase_if`, but that's only available in C++20
auto &cache = internals.inactive_override_cache; auto &cache = internals.inactive_override_cache;
for (auto it = cache.begin(), last = cache.end(); it != last; ) { for (auto it = cache.begin(), last = cache.end(); it != last;) {
if (it->first == (PyObject *) tinfo->type) { if (it->first == (PyObject *) tinfo->type) {
it = cache.erase(it); it = cache.erase(it);
} else { } else {
...@@ -237,7 +240,7 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) { ...@@ -237,7 +240,7 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
/** This metaclass is assigned by default to all pybind11 types and is required in order /** This metaclass is assigned by default to all pybind11 types and is required in order
for static properties to function correctly. Users may override this using `py::metaclass`. for static properties to function correctly. Users may override this using `py::metaclass`.
Return value: New reference. */ Return value: New reference. */
inline PyTypeObject* make_default_metaclass() { inline PyTypeObject *make_default_metaclass() {
constexpr auto *name = "pybind11_type"; constexpr auto *name = "pybind11_type";
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name)); auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
...@@ -281,9 +284,12 @@ inline PyTypeObject* make_default_metaclass() { ...@@ -281,9 +284,12 @@ inline PyTypeObject* make_default_metaclass() {
/// For multiple inheritance types we need to recursively register/deregister base pointers for any /// For multiple inheritance types we need to recursively register/deregister base pointers for any
/// base classes with pointers that are difference from the instance value pointer so that we can /// base classes with pointers that are difference from the instance value pointer so that we can
/// correctly recognize an offset base class pointer. This calls a function with any offset base ptrs. /// correctly recognize an offset base class pointer. This calls a function with any offset base
inline void traverse_offset_bases(void *valueptr, const detail::type_info *tinfo, instance *self, /// ptrs.
bool (*f)(void * /*parentptr*/, instance * /*self*/)) { inline void traverse_offset_bases(void *valueptr,
const detail::type_info *tinfo,
instance *self,
bool (*f)(void * /*parentptr*/, instance * /*self*/)) {
for (handle h : reinterpret_borrow<tuple>(tinfo->type->tp_bases)) { for (handle h : reinterpret_borrow<tuple>(tinfo->type->tp_bases)) {
if (auto *parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) { if (auto *parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) {
for (auto &c : parent_tinfo->implicit_casts) { for (auto &c : parent_tinfo->implicit_casts) {
...@@ -331,13 +337,13 @@ inline bool deregister_instance(instance *self, void *valptr, const type_info *t ...@@ -331,13 +337,13 @@ inline bool deregister_instance(instance *self, void *valptr, const type_info *t
return ret; return ret;
} }
/// Instance creation function for all pybind11 types. It allocates the internal instance layout for /// Instance creation function for all pybind11 types. It allocates the internal instance layout
/// holding C++ objects and holders. Allocation is done lazily (the first time the instance is cast /// for holding C++ objects and holders. Allocation is done lazily (the first time the instance is
/// to a reference or pointer), and initialization is done by an `__init__` function. /// cast to a reference or pointer), and initialization is done by an `__init__` function.
inline PyObject *make_new_instance(PyTypeObject *type) { inline PyObject *make_new_instance(PyTypeObject *type) {
#if defined(PYPY_VERSION) #if defined(PYPY_VERSION)
// PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first inherited // PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first
// object is a plain Python type (i.e. not derived from an extension type). Fix it. // inherited object is a plain Python type (i.e. not derived from an extension type). Fix it.
ssize_t instance_size = static_cast<ssize_t>(sizeof(instance)); ssize_t instance_size = static_cast<ssize_t>(sizeof(instance));
if (type->tp_basicsize < instance_size) { if (type->tp_basicsize < instance_size) {
type->tp_basicsize = instance_size; type->tp_basicsize = instance_size;
...@@ -511,7 +517,8 @@ extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) { ...@@ -511,7 +517,8 @@ extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) {
/// dynamic_attr: Support for `instance.__dict__ = dict()`. /// dynamic_attr: Support for `instance.__dict__ = dict()`.
extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) { extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) {
if (!PyDict_Check(new_dict)) { if (!PyDict_Check(new_dict)) {
PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'", PyErr_Format(PyExc_TypeError,
"__dict__ must be set to a dictionary, not a '%.200s'",
get_fully_qualified_tp_name(Py_TYPE(new_dict)).c_str()); get_fully_qualified_tp_name(Py_TYPE(new_dict)).c_str());
return -1; return -1;
} }
...@@ -540,15 +547,14 @@ extern "C" inline int pybind11_clear(PyObject *self) { ...@@ -540,15 +547,14 @@ extern "C" inline int pybind11_clear(PyObject *self) {
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) { inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
auto *type = &heap_type->ht_type; auto *type = &heap_type->ht_type;
type->tp_flags |= Py_TPFLAGS_HAVE_GC; type->tp_flags |= Py_TPFLAGS_HAVE_GC;
type->tp_dictoffset = type->tp_basicsize; // place dict at the end type->tp_dictoffset = type->tp_basicsize; // place dict at the end
type->tp_basicsize += (ssize_t)sizeof(PyObject *); // and allocate enough space for it type->tp_basicsize += (ssize_t) sizeof(PyObject *); // and allocate enough space for it
type->tp_traverse = pybind11_traverse; type->tp_traverse = pybind11_traverse;
type->tp_clear = pybind11_clear; type->tp_clear = pybind11_clear;
static PyGetSetDef getset[] = { static PyGetSetDef getset[] = {
{const_cast<char*>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr}, {const_cast<char *>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr} {nullptr, nullptr, nullptr, nullptr, nullptr}};
};
type->tp_getset = getset; type->tp_getset = getset;
} }
...@@ -617,7 +623,7 @@ inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) { ...@@ -617,7 +623,7 @@ inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
/** Create a brand new Python type according to the `type_record` specification. /** Create a brand new Python type according to the `type_record` specification.
Return value: New reference. */ Return value: New reference. */
inline PyObject* make_new_python_type(const type_record &rec) { inline PyObject *make_new_python_type(const type_record &rec) {
auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name)); auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));
auto qualname = name; auto qualname = name;
...@@ -678,7 +684,7 @@ inline PyObject* make_new_python_type(const type_record &rec) { ...@@ -678,7 +684,7 @@ inline PyObject* make_new_python_type(const type_record &rec) {
auto *type = &heap_type->ht_type; auto *type = &heap_type->ht_type;
type->tp_name = full_name; type->tp_name = full_name;
type->tp_doc = tp_doc; type->tp_doc = tp_doc;
type->tp_base = type_incref((PyTypeObject *)base); type->tp_base = type_incref((PyTypeObject *) base);
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance)); type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
if (!bases.empty()) { if (!bases.empty()) {
type->tp_bases = bases.release().ptr(); type->tp_bases = bases.release().ptr();
......
...@@ -15,9 +15,9 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) ...@@ -15,9 +15,9 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
#if !defined(_MSC_VER) #if !defined(_MSC_VER)
# define PYBIND11_DESCR_CONSTEXPR static constexpr # define PYBIND11_DESCR_CONSTEXPR static constexpr
#else #else
# define PYBIND11_DESCR_CONSTEXPR const # define PYBIND11_DESCR_CONSTEXPR const
#endif #endif
/* Concatenate type signatures at compile time */ /* Concatenate type signatures at compile time */
...@@ -27,14 +27,14 @@ struct descr { ...@@ -27,14 +27,14 @@ struct descr {
constexpr descr() = default; constexpr descr() = default;
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence<N>()) { } constexpr descr(char const (&s)[N + 1]) : descr(s, make_index_sequence<N>()) {}
template <size_t... Is> template <size_t... Is>
constexpr descr(char const (&s)[N+1], index_sequence<Is...>) : text{s[Is]..., '\0'} { } constexpr descr(char const (&s)[N + 1], index_sequence<Is...>) : text{s[Is]..., '\0'} {}
template <typename... Chars> template <typename... Chars>
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} { } constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} {}
static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() { static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() {
return {{&typeid(Ts)..., nullptr}}; return {{&typeid(Ts)..., nullptr}};
...@@ -42,81 +42,106 @@ struct descr { ...@@ -42,81 +42,106 @@ struct descr {
}; };
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2> template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2>
constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b, constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a,
index_sequence<Is1...>, index_sequence<Is2...>) { const descr<N2, Ts2...> &b,
index_sequence<Is1...>,
index_sequence<Is2...>) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b); PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b);
return {a.text[Is1]..., b.text[Is2]...}; return {a.text[Is1]..., b.text[Is2]...};
} }
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2> template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b) { constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a,
const descr<N2, Ts2...> &b) {
return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>()); return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>());
} }
template <size_t N> template <size_t N>
constexpr descr<N - 1> const_name(char const(&text)[N]) { return descr<N - 1>(text); } constexpr descr<N - 1> const_name(char const (&text)[N]) {
constexpr descr<0> const_name(char const(&)[1]) { return {}; } return descr<N - 1>(text);
}
constexpr descr<0> const_name(char const (&)[1]) { return {}; }
template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { }; template <size_t Rem, size_t... Digits>
template <size_t...Digits> struct int_to_str<0, Digits...> { struct int_to_str : int_to_str<Rem / 10, Rem % 10, Digits...> {};
template <size_t... Digits>
struct int_to_str<0, Digits...> {
// WARNING: This only works with C++17 or higher. // WARNING: This only works with C++17 or higher.
static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...); static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...);
}; };
// Ternary description (like std::conditional) // Ternary description (like std::conditional)
template <bool B, size_t N1, size_t N2> template <bool B, size_t N1, size_t N2>
constexpr enable_if_t<B, descr<N1 - 1>> const_name(char const(&text1)[N1], char const(&)[N2]) { constexpr enable_if_t<B, descr<N1 - 1>> const_name(char const (&text1)[N1], char const (&)[N2]) {
return const_name(text1); return const_name(text1);
} }
template <bool B, size_t N1, size_t N2> template <bool B, size_t N1, size_t N2>
constexpr enable_if_t<!B, descr<N2 - 1>> const_name(char const(&)[N1], char const(&text2)[N2]) { constexpr enable_if_t<!B, descr<N2 - 1>> const_name(char const (&)[N1], char const (&text2)[N2]) {
return const_name(text2); return const_name(text2);
} }
template <bool B, typename T1, typename T2> template <bool B, typename T1, typename T2>
constexpr enable_if_t<B, T1> const_name(const T1 &d, const T2 &) { return d; } constexpr enable_if_t<B, T1> const_name(const T1 &d, const T2 &) {
return d;
}
template <bool B, typename T1, typename T2> template <bool B, typename T1, typename T2>
constexpr enable_if_t<!B, T2> const_name(const T1 &, const T2 &d) { return d; } constexpr enable_if_t<!B, T2> const_name(const T1 &, const T2 &d) {
return d;
}
template <size_t Size> template <size_t Size>
auto constexpr const_name() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> { auto constexpr const_name() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
return int_to_str<Size / 10, Size % 10>::digits; return int_to_str<Size / 10, Size % 10>::digits;
} }
template <typename Type> constexpr descr<1, Type> const_name() { return {'%'}; } template <typename Type>
constexpr descr<1, Type> const_name() {
return {'%'};
}
// If "_" is defined as a macro, py::detail::_ cannot be provided. // If "_" is defined as a macro, py::detail::_ cannot be provided.
// It is therefore best to use py::detail::const_name universally. // It is therefore best to use py::detail::const_name universally.
// This block is for backward compatibility only. // This block is for backward compatibility only.
// (The const_name code is repeated to avoid introducing a "_" #define ourselves.) // (The const_name code is repeated to avoid introducing a "_" #define ourselves.)
#ifndef _ #ifndef _
#define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY # define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
template <size_t N> template <size_t N>
constexpr descr<N-1> _(char const(&text)[N]) { return const_name<N>(text); } constexpr descr<N - 1> _(char const (&text)[N]) {
return const_name<N>(text);
}
template <bool B, size_t N1, size_t N2> template <bool B, size_t N1, size_t N2>
constexpr enable_if_t<B, descr<N1 - 1>> _(char const(&text1)[N1], char const(&text2)[N2]) { constexpr enable_if_t<B, descr<N1 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {
return const_name<B,N1,N2>(text1, text2); return const_name<B, N1, N2>(text1, text2);
} }
template <bool B, size_t N1, size_t N2> template <bool B, size_t N1, size_t N2>
constexpr enable_if_t<!B, descr<N2 - 1>> _(char const(&text1)[N1], char const(&text2)[N2]) { constexpr enable_if_t<!B, descr<N2 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {
return const_name<B,N1,N2>(text1, text2); return const_name<B, N1, N2>(text1, text2);
} }
template <bool B, typename T1, typename T2> template <bool B, typename T1, typename T2>
constexpr enable_if_t<B, T1> _(const T1 &d1, const T2 &d2) { return const_name<B,T1,T2>(d1, d2); } constexpr enable_if_t<B, T1> _(const T1 &d1, const T2 &d2) {
return const_name<B, T1, T2>(d1, d2);
}
template <bool B, typename T1, typename T2> template <bool B, typename T1, typename T2>
constexpr enable_if_t<!B, T2> _(const T1 &d1, const T2 &d2) { return const_name<B,T1,T2>(d1, d2); } constexpr enable_if_t<!B, T2> _(const T1 &d1, const T2 &d2) {
return const_name<B, T1, T2>(d1, d2);
}
template <size_t Size> template <size_t Size>
auto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> { auto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
return const_name<Size>(); return const_name<Size>();
} }
template <typename Type> constexpr descr<1, Type> _() { return const_name<Type>(); } template <typename Type>
#endif // #ifndef _ constexpr descr<1, Type> _() {
return const_name<Type>();
}
#endif // #ifndef _
constexpr descr<0> concat() { return {}; } constexpr descr<0> concat() { return {}; }
template <size_t N, typename... Ts> template <size_t N, typename... Ts>
constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) { return descr; } constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) {
return descr;
}
template <size_t N, typename... Ts, typename... Args> template <size_t N, typename... Ts, typename... Args>
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#pragma once #pragma once
#include "../pytypes.h" #include "../pytypes.h"
#include <exception> #include <exception>
/// Tracks the `internals` and `type_info` ABI version independent of the main library version. /// Tracks the `internals` and `type_info` ABI version independent of the main library version.
...@@ -136,9 +137,9 @@ template <typename value_type> ...@@ -136,9 +137,9 @@ template <typename value_type>
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>; using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
struct override_hash { struct override_hash {
inline size_t operator()(const std::pair<const PyObject *, const char *>& v) const { inline size_t operator()(const std::pair<const PyObject *, const char *> &v) const {
size_t value = std::hash<const void *>()(v.first); size_t value = std::hash<const void *>()(v.first);
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2); value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value << 6) + (value >> 2);
return value; return value;
} }
}; };
...@@ -151,8 +152,9 @@ struct internals { ...@@ -151,8 +152,9 @@ struct internals {
type_map<type_info *> registered_types_cpp; type_map<type_info *> registered_types_cpp;
// PyTypeObject* -> base type_info(s) // PyTypeObject* -> base type_info(s)
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py; std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py;
std::unordered_multimap<const void *, instance*> registered_instances; // void * -> instance* std::unordered_multimap<const void *, instance *> registered_instances; // void * -> instance*
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash> inactive_override_cache; std::unordered_set<std::pair<const PyObject *, const char *>, override_hash>
inactive_override_cache;
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions; type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients; std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
std::forward_list<ExceptionTranslator> registered_exception_translators; std::forward_list<ExceptionTranslator> registered_exception_translators;
...@@ -198,8 +200,8 @@ struct type_info { ...@@ -198,8 +200,8 @@ struct type_info {
void *(*operator_new)(size_t); void *(*operator_new)(size_t);
void (*init_instance)(instance *, const void *); void (*init_instance)(instance *, const void *);
void (*dealloc)(value_and_holder &v_h); void (*dealloc)(value_and_holder &v_h);
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions; std::vector<PyObject *(*) (PyObject *, PyTypeObject *)> implicit_conversions;
std::vector<std::pair<const std::type_info *, void *(*)(void *)>> implicit_casts; std::vector<std::pair<const std::type_info *, void *(*) (void *)>> implicit_casts;
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions; std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr; buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
void *get_buffer_data = nullptr; void *get_buffer_data = nullptr;
...@@ -219,67 +221,71 @@ struct type_info { ...@@ -219,67 +221,71 @@ struct type_info {
/// On MSVC, debug and release builds are not ABI-compatible! /// On MSVC, debug and release builds are not ABI-compatible!
#if defined(_MSC_VER) && defined(_DEBUG) #if defined(_MSC_VER) && defined(_DEBUG)
# define PYBIND11_BUILD_TYPE "_debug" # define PYBIND11_BUILD_TYPE "_debug"
#else #else
# define PYBIND11_BUILD_TYPE "" # define PYBIND11_BUILD_TYPE ""
#endif #endif
/// Let's assume that different compilers are ABI-incompatible. /// Let's assume that different compilers are ABI-incompatible.
/// A user can manually set this string if they know their /// A user can manually set this string if they know their
/// compiler is compatible. /// compiler is compatible.
#ifndef PYBIND11_COMPILER_TYPE #ifndef PYBIND11_COMPILER_TYPE
# if defined(_MSC_VER) # if defined(_MSC_VER)
# define PYBIND11_COMPILER_TYPE "_msvc" # define PYBIND11_COMPILER_TYPE "_msvc"
# elif defined(__INTEL_COMPILER) # elif defined(__INTEL_COMPILER)
# define PYBIND11_COMPILER_TYPE "_icc" # define PYBIND11_COMPILER_TYPE "_icc"
# elif defined(__clang__) # elif defined(__clang__)
# define PYBIND11_COMPILER_TYPE "_clang" # define PYBIND11_COMPILER_TYPE "_clang"
# elif defined(__PGI) # elif defined(__PGI)
# define PYBIND11_COMPILER_TYPE "_pgi" # define PYBIND11_COMPILER_TYPE "_pgi"
# elif defined(__MINGW32__) # elif defined(__MINGW32__)
# define PYBIND11_COMPILER_TYPE "_mingw" # define PYBIND11_COMPILER_TYPE "_mingw"
# elif defined(__CYGWIN__) # elif defined(__CYGWIN__)
# define PYBIND11_COMPILER_TYPE "_gcc_cygwin" # define PYBIND11_COMPILER_TYPE "_gcc_cygwin"
# elif defined(__GNUC__) # elif defined(__GNUC__)
# define PYBIND11_COMPILER_TYPE "_gcc" # define PYBIND11_COMPILER_TYPE "_gcc"
# else # else
# define PYBIND11_COMPILER_TYPE "_unknown" # define PYBIND11_COMPILER_TYPE "_unknown"
# endif # endif
#endif #endif
/// Also standard libs /// Also standard libs
#ifndef PYBIND11_STDLIB #ifndef PYBIND11_STDLIB
# if defined(_LIBCPP_VERSION) # if defined(_LIBCPP_VERSION)
# define PYBIND11_STDLIB "_libcpp" # define PYBIND11_STDLIB "_libcpp"
# elif defined(__GLIBCXX__) || defined(__GLIBCPP__) # elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
# define PYBIND11_STDLIB "_libstdcpp" # define PYBIND11_STDLIB "_libstdcpp"
# else # else
# define PYBIND11_STDLIB "" # define PYBIND11_STDLIB ""
# endif # endif
#endif #endif
/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility. /// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility.
#ifndef PYBIND11_BUILD_ABI #ifndef PYBIND11_BUILD_ABI
# if defined(__GXX_ABI_VERSION) # if defined(__GXX_ABI_VERSION)
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION) # define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION)
# else # else
# define PYBIND11_BUILD_ABI "" # define PYBIND11_BUILD_ABI ""
# endif # endif
#endif #endif
#ifndef PYBIND11_INTERNALS_KIND #ifndef PYBIND11_INTERNALS_KIND
# if defined(WITH_THREAD) # if defined(WITH_THREAD)
# define PYBIND11_INTERNALS_KIND "" # define PYBIND11_INTERNALS_KIND ""
# else # else
# define PYBIND11_INTERNALS_KIND "_without_thread" # define PYBIND11_INTERNALS_KIND "_without_thread"
# endif # endif
#endif #endif
#define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \ #define PYBIND11_INTERNALS_ID \
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" "__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
PYBIND11_BUILD_TYPE "__"
#define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \ #define PYBIND11_MODULE_LOCAL_ID \
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" "__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
PYBIND11_BUILD_TYPE "__"
/// Each module locally stores a pointer to the `internals` data. The data /// Each module locally stores a pointer to the `internals` data. The data
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`. /// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
...@@ -396,8 +402,12 @@ inline void translate_local_exception(std::exception_ptr p) { ...@@ -396,8 +402,12 @@ inline void translate_local_exception(std::exception_ptr p) {
if (p) { if (p) {
std::rethrow_exception(p); std::rethrow_exception(p);
} }
} catch (error_already_set &e) { e.restore(); return; } catch (error_already_set &e) {
} catch (const builtin_exception &e) { e.set_error(); return; e.restore();
return;
} catch (const builtin_exception &e) {
e.set_error();
return;
} }
} }
#endif #endif
...@@ -412,7 +422,7 @@ PYBIND11_NOINLINE internals &get_internals() { ...@@ -412,7 +422,7 @@ PYBIND11_NOINLINE internals &get_internals() {
// Ensure that the GIL is held since we will need to make Python calls. // Ensure that the GIL is held since we will need to make Python calls.
// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals. // Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
struct gil_scoped_acquire_local { struct gil_scoped_acquire_local {
gil_scoped_acquire_local() : state (PyGILState_Ensure()) {} gil_scoped_acquire_local() : state(PyGILState_Ensure()) {}
~gil_scoped_acquire_local() { PyGILState_Release(state); } ~gil_scoped_acquire_local() { PyGILState_Release(state); }
const PyGILState_STATE state; const PyGILState_STATE state;
} gil; } gil;
...@@ -512,11 +522,10 @@ struct local_internals { ...@@ -512,11 +522,10 @@ struct local_internals {
/// Works like `get_internals`, but for things which are locally registered. /// Works like `get_internals`, but for things which are locally registered.
inline local_internals &get_local_internals() { inline local_internals &get_local_internals() {
static local_internals locals; static local_internals locals;
return locals; return locals;
} }
/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its /// Constructs a std::string with the given arguments, stores it in `internals`, and returns its
/// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only /// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only
/// cleared when the program exits or after interpreter shutdown (when embedding), and so are /// cleared when the program exits or after interpreter shutdown (when embedding), and so are
...@@ -548,7 +557,7 @@ PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) { ...@@ -548,7 +557,7 @@ PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if /// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
/// such entry exists. Otherwise, a new object of default-constructible type `T` is /// such entry exists. Otherwise, a new object of default-constructible type `T` is
/// added to the shared data under the given name and a reference to it is returned. /// added to the shared data under the given name and a reference to it is returned.
template<typename T> template <typename T>
T &get_or_create_shared_data(const std::string &name) { T &get_or_create_shared_data(const std::string &name) {
auto &internals = detail::get_internals(); auto &internals = detail::get_internals();
auto it = internals.shared_data.find(name); auto it = internals.shared_data.find(name);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <cstdlib> #include <cstdlib>
#if defined(__GNUG__) #if defined(__GNUG__)
#include <cxxabi.h> # include <cxxabi.h>
#endif #endif
#include "common.h" #include "common.h"
...@@ -34,8 +34,8 @@ inline void erase_all(std::string &string, const std::string &search) { ...@@ -34,8 +34,8 @@ inline void erase_all(std::string &string, const std::string &search) {
PYBIND11_NOINLINE void clean_type_id(std::string &name) { PYBIND11_NOINLINE void clean_type_id(std::string &name) {
#if defined(__GNUG__) #if defined(__GNUG__)
int status = 0; int status = 0;
std::unique_ptr<char, void (*)(void *)> res { std::unique_ptr<char, void (*)(void *)> res{
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free }; abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free};
if (status == 0) { if (status == 0) {
name = res.get(); name = res.get();
} }
...@@ -49,7 +49,8 @@ PYBIND11_NOINLINE void clean_type_id(std::string &name) { ...@@ -49,7 +49,8 @@ PYBIND11_NOINLINE void clean_type_id(std::string &name) {
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
/// Return a string representation of a C++ type /// Return a string representation of a C++ type
template <typename T> static std::string type_id() { template <typename T>
static std::string type_id() {
std::string name(typeid(T).name()); std::string name(typeid(T).name());
detail::clean_type_id(name); detail::clean_type_id(name);
return name; return name;
......
...@@ -16,21 +16,17 @@ ...@@ -16,21 +16,17 @@
#include <vector> #include <vector>
#if defined(PYPY_VERSION) #if defined(PYPY_VERSION)
# error Embedding the interpreter is not supported with PyPy # error Embedding the interpreter is not supported with PyPy
#endif #endif
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ # define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
extern "C" PyObject *pybind11_init_impl_##name(); \ extern "C" PyObject *pybind11_init_impl_##name(); \
extern "C" PyObject *pybind11_init_impl_##name() { \ extern "C" PyObject *pybind11_init_impl_##name() { return pybind11_init_wrapper_##name(); }
return pybind11_init_wrapper_##name(); \
}
#else #else
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ # define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
extern "C" void pybind11_init_impl_##name(); \ extern "C" void pybind11_init_impl_##name(); \
extern "C" void pybind11_init_impl_##name() { \ extern "C" void pybind11_init_impl_##name() { pybind11_init_wrapper_##name(); }
pybind11_init_wrapper_##name(); \
}
#endif #endif
/** \rst /** \rst
...@@ -72,7 +68,7 @@ PYBIND11_NAMESPACE_BEGIN(detail) ...@@ -72,7 +68,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks. /// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
struct embedded_module { struct embedded_module {
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
using init_t = PyObject *(*)(); using init_t = PyObject *(*) ();
#else #else
using init_t = void (*)(); using init_t = void (*)();
#endif #endif
...@@ -106,10 +102,10 @@ inline wchar_t *widen_chars(const char *safe_arg) { ...@@ -106,10 +102,10 @@ inline wchar_t *widen_chars(const char *safe_arg) {
wchar_t *widened_arg = nullptr; wchar_t *widened_arg = nullptr;
// warning C4996: 'mbstowcs': This function or variable may be unsafe. // warning C4996: 'mbstowcs': This function or variable may be unsafe.
#if defined(_MSC_VER) # if defined(_MSC_VER)
#pragma warning(push) # pragma warning(push)
#pragma warning(disable:4996) # pragma warning(disable : 4996)
#endif # endif
# if defined(HAVE_BROKEN_MBSTOWCS) && HAVE_BROKEN_MBSTOWCS # if defined(HAVE_BROKEN_MBSTOWCS) && HAVE_BROKEN_MBSTOWCS
size_t count = std::strlen(safe_arg); size_t count = std::strlen(safe_arg);
...@@ -121,9 +117,9 @@ inline wchar_t *widen_chars(const char *safe_arg) { ...@@ -121,9 +117,9 @@ inline wchar_t *widen_chars(const char *safe_arg) {
std::mbstowcs(widened_arg, safe_arg, count + 1); std::mbstowcs(widened_arg, safe_arg, count + 1);
} }
#if defined(_MSC_VER) # if defined(_MSC_VER)
#pragma warning(pop) # pragma warning(pop)
#endif # endif
#endif #endif
return widened_arg; return widened_arg;
......
...@@ -11,24 +11,24 @@ ...@@ -11,24 +11,24 @@
#pragma once #pragma once
#include <utility>
#include "pybind11.h" #include "pybind11.h"
#include <utility>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
inline void ensure_builtins_in_globals(object &global) { inline void ensure_builtins_in_globals(object &global) {
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000 #if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
// Running exec and eval on Python 2 and 3 adds `builtins` module under // Running exec and eval on Python 2 and 3 adds `builtins` module under
// `__builtins__` key to globals if not yet present. // `__builtins__` key to globals if not yet present.
// Python 3.8 made PyRun_String behave similarly. Let's also do that for // Python 3.8 made PyRun_String behave similarly. Let's also do that for
// older versions, for consistency. This was missing from PyPy3.8 7.3.7. // older versions, for consistency. This was missing from PyPy3.8 7.3.7.
if (!global.contains("__builtins__")) if (!global.contains("__builtins__"))
global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE); global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
#else #else
(void) global; (void) global;
#endif #endif
} }
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
...@@ -58,10 +58,17 @@ object eval(const str &expr, object global = globals(), object local = object()) ...@@ -58,10 +58,17 @@ object eval(const str &expr, object global = globals(), object local = object())
int start = 0; int start = 0;
switch (mode) { switch (mode) {
case eval_expr: start = Py_eval_input; break; case eval_expr:
case eval_single_statement: start = Py_single_input; break; start = Py_eval_input;
case eval_statements: start = Py_file_input; break; break;
default: pybind11_fail("invalid evaluation mode"); case eval_single_statement:
start = Py_single_input;
break;
case eval_statements:
start = Py_file_input;
break;
default:
pybind11_fail("invalid evaluation mode");
} }
PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr()); PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
...@@ -74,8 +81,7 @@ object eval(const str &expr, object global = globals(), object local = object()) ...@@ -74,8 +81,7 @@ object eval(const str &expr, object global = globals(), object local = object())
template <eval_mode mode = eval_expr, size_t N> template <eval_mode mode = eval_expr, size_t N>
object eval(const char (&s)[N], object global = globals(), object local = object()) { object eval(const char (&s)[N], object global = globals(), object local = object()) {
/* Support raw string literals by removing common leading whitespace */ /* Support raw string literals by removing common leading whitespace */
auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) : str(s);
: str(s);
return eval<mode>(expr, global, local); return eval<mode>(expr, global, local);
} }
...@@ -112,28 +118,34 @@ object eval_file(str fname, object global = globals(), object local = object()) ...@@ -112,28 +118,34 @@ object eval_file(str fname, object global = globals(), object local = object())
int start = 0; int start = 0;
switch (mode) { switch (mode) {
case eval_expr: start = Py_eval_input; break; case eval_expr:
case eval_single_statement: start = Py_single_input; break; start = Py_eval_input;
case eval_statements: start = Py_file_input; break; break;
default: pybind11_fail("invalid evaluation mode"); case eval_single_statement:
start = Py_single_input;
break;
case eval_statements:
start = Py_file_input;
break;
default:
pybind11_fail("invalid evaluation mode");
} }
int closeFile = 1; int closeFile = 1;
std::string fname_str = (std::string) fname; std::string fname_str = (std::string) fname;
#if PY_VERSION_HEX >= 0x03040000 # if PY_VERSION_HEX >= 0x03040000
FILE *f = _Py_fopen_obj(fname.ptr(), "r"); FILE *f = _Py_fopen_obj(fname.ptr(), "r");
#elif PY_VERSION_HEX >= 0x03000000 # elif PY_VERSION_HEX >= 0x03000000
FILE *f = _Py_fopen(fname.ptr(), "r"); FILE *f = _Py_fopen(fname.ptr(), "r");
#else # else
/* No unicode support in open() :( */ /* No unicode support in open() :( */
auto fobj = reinterpret_steal<object>(PyFile_FromString( auto fobj = reinterpret_steal<object>(
const_cast<char *>(fname_str.c_str()), PyFile_FromString(const_cast<char *>(fname_str.c_str()), const_cast<char *>("r")));
const_cast<char*>("r")));
FILE *f = nullptr; FILE *f = nullptr;
if (fobj) if (fobj)
f = PyFile_AsFile(fobj.ptr()); f = PyFile_AsFile(fobj.ptr());
closeFile = 0; closeFile = 0;
#endif # endif
if (!f) { if (!f) {
PyErr_Clear(); PyErr_Clear();
pybind11_fail("File \"" + fname_str + "\" could not be opened!"); pybind11_fail("File \"" + fname_str + "\" could not be opened!");
...@@ -142,20 +154,19 @@ object eval_file(str fname, object global = globals(), object local = object()) ...@@ -142,20 +154,19 @@ object eval_file(str fname, object global = globals(), object local = object())
// In Python2, this should be encoded by getfilesystemencoding. // In Python2, this should be encoded by getfilesystemencoding.
// We don't boher setting it since Python2 is past EOL anyway. // We don't boher setting it since Python2 is past EOL anyway.
// See PR#3233 // See PR#3233
#if PY_VERSION_HEX >= 0x03000000 # if PY_VERSION_HEX >= 0x03000000
if (!global.contains("__file__")) { if (!global.contains("__file__")) {
global["__file__"] = std::move(fname); global["__file__"] = std::move(fname);
} }
#endif # endif
#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION) # if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(), PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(), local.ptr());
local.ptr());
(void) closeFile; (void) closeFile;
#else # else
PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), PyObject *result
local.ptr(), closeFile); = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);
#endif # endif
if (!result) { if (!result) {
throw error_already_set(); throw error_already_set();
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#pragma once #pragma once
#include "pybind11.h" #include "pybind11.h"
#include <functional> #include <functional>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
...@@ -19,7 +20,7 @@ template <typename Return, typename... Args> ...@@ -19,7 +20,7 @@ template <typename Return, typename... Args>
struct type_caster<std::function<Return(Args...)>> { struct type_caster<std::function<Return(Args...)>> {
using type = std::function<Return(Args...)>; using type = std::function<Return(Args...)>;
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>; using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
using function_type = Return (*) (Args...); using function_type = Return (*)(Args...);
public: public:
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
...@@ -76,7 +77,9 @@ public: ...@@ -76,7 +77,9 @@ public:
// This triggers a syntax error under very special conditions (very weird indeed). // This triggers a syntax error under very special conditions (very weird indeed).
explicit explicit
#endif #endif
func_handle(function &&f_) noexcept : f(std::move(f_)) {} func_handle(function &&f_) noexcept
: f(std::move(f_)) {
}
func_handle(const func_handle &f_) { operator=(f_); } func_handle(const func_handle &f_) { operator=(f_); }
func_handle &operator=(const func_handle &f_) { func_handle &operator=(const func_handle &f_) {
gil_scoped_acquire acq; gil_scoped_acquire acq;
...@@ -118,8 +121,10 @@ public: ...@@ -118,8 +121,10 @@ public:
return cpp_function(std::forward<Func>(f_), policy).release(); return cpp_function(std::forward<Func>(f_), policy).release();
} }
PYBIND11_TYPE_CASTER(type, const_name("Callable[[") + concat(make_caster<Args>::name...) + const_name("], ") PYBIND11_TYPE_CASTER(type,
+ make_caster<retval_type>::name + const_name("]")); const_name("Callable[[") + concat(make_caster<Args>::name...)
+ const_name("], ") + make_caster<retval_type>::name
+ const_name("]"));
}; };
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
// forward declarations // forward declarations
...@@ -22,7 +21,6 @@ PyThreadState *get_thread_state_unchecked(); ...@@ -22,7 +21,6 @@ PyThreadState *get_thread_state_unchecked();
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
#if defined(WITH_THREAD) && !defined(PYPY_VERSION) #if defined(WITH_THREAD) && !defined(PYPY_VERSION)
/* The functions below essentially reproduce the PyGILState_* API using a RAII /* The functions below essentially reproduce the PyGILState_* API using a RAII
...@@ -64,11 +62,11 @@ public: ...@@ -64,11 +62,11 @@ public:
if (!tstate) { if (!tstate) {
tstate = PyThreadState_New(internals.istate); tstate = PyThreadState_New(internals.istate);
#if !defined(NDEBUG) # if !defined(NDEBUG)
if (!tstate) { if (!tstate) {
pybind11_fail("scoped_acquire: could not create thread state!"); pybind11_fail("scoped_acquire: could not create thread state!");
} }
#endif # endif
tstate->gilstate_counter = 0; tstate->gilstate_counter = 0;
PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate); PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
} else { } else {
...@@ -82,26 +80,24 @@ public: ...@@ -82,26 +80,24 @@ public:
inc_ref(); inc_ref();
} }
void inc_ref() { void inc_ref() { ++tstate->gilstate_counter; }
++tstate->gilstate_counter;
}
PYBIND11_NOINLINE void dec_ref() { PYBIND11_NOINLINE void dec_ref() {
--tstate->gilstate_counter; --tstate->gilstate_counter;
#if !defined(NDEBUG) # if !defined(NDEBUG)
if (detail::get_thread_state_unchecked() != tstate) { if (detail::get_thread_state_unchecked() != tstate) {
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!"); pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
} }
if (tstate->gilstate_counter < 0) { if (tstate->gilstate_counter < 0) {
pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!"); pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
} }
#endif # endif
if (tstate->gilstate_counter == 0) { if (tstate->gilstate_counter == 0) {
#if !defined(NDEBUG) # if !defined(NDEBUG)
if (!release) { if (!release) {
pybind11_fail("scoped_acquire::dec_ref(): internal error!"); pybind11_fail("scoped_acquire::dec_ref(): internal error!");
} }
#endif # endif
PyThreadState_Clear(tstate); PyThreadState_Clear(tstate);
if (active) { if (active) {
PyThreadState_DeleteCurrent(); PyThreadState_DeleteCurrent();
...@@ -116,9 +112,7 @@ public: ...@@ -116,9 +112,7 @@ public:
/// could be shutting down when this is called, as thread deletion is not /// could be shutting down when this is called, as thread deletion is not
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
/// protect subsequent code. /// protect subsequent code.
PYBIND11_NOINLINE void disarm() { PYBIND11_NOINLINE void disarm() { active = false; }
active = false;
}
PYBIND11_NOINLINE ~gil_scoped_acquire() { PYBIND11_NOINLINE ~gil_scoped_acquire() {
dec_ref(); dec_ref();
...@@ -126,6 +120,7 @@ public: ...@@ -126,6 +120,7 @@ public:
PyEval_SaveThread(); PyEval_SaveThread();
} }
} }
private: private:
PyThreadState *tstate = nullptr; PyThreadState *tstate = nullptr;
bool release = true; bool release = true;
...@@ -154,9 +149,7 @@ public: ...@@ -154,9 +149,7 @@ public:
/// could be shutting down when this is called, as thread deletion is not /// could be shutting down when this is called, as thread deletion is not
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
/// protect subsequent code. /// protect subsequent code.
PYBIND11_NOINLINE void disarm() { PYBIND11_NOINLINE void disarm() { active = false; }
active = false;
}
~gil_scoped_release() { ~gil_scoped_release() {
if (!tstate) { if (!tstate) {
...@@ -173,6 +166,7 @@ public: ...@@ -173,6 +166,7 @@ public:
PYBIND11_TLS_REPLACE_VALUE(key, tstate); PYBIND11_TLS_REPLACE_VALUE(key, tstate);
} }
} }
private: private:
PyThreadState *tstate; PyThreadState *tstate;
bool disassoc; bool disassoc;
...@@ -181,6 +175,7 @@ private: ...@@ -181,6 +175,7 @@ private:
#elif defined(PYPY_VERSION) #elif defined(PYPY_VERSION)
class gil_scoped_acquire { class gil_scoped_acquire {
PyGILState_STATE state; PyGILState_STATE state;
public: public:
gil_scoped_acquire() { state = PyGILState_Ensure(); } gil_scoped_acquire() { state = PyGILState_Ensure(); }
~gil_scoped_acquire() { PyGILState_Release(state); } ~gil_scoped_acquire() { PyGILState_Release(state); }
...@@ -189,6 +184,7 @@ public: ...@@ -189,6 +184,7 @@ public:
class gil_scoped_release { class gil_scoped_release {
PyThreadState *state; PyThreadState *state;
public: public:
gil_scoped_release() { state = PyEval_SaveThread(); } gil_scoped_release() { state = PyEval_SaveThread(); }
~gil_scoped_release() { PyEval_RestoreThread(state); } ~gil_scoped_release() { PyEval_RestoreThread(state); }
......
...@@ -58,31 +58,23 @@ private: ...@@ -58,31 +58,23 @@ private:
size_t utf8_remainder() const { size_t utf8_remainder() const {
const auto rbase = std::reverse_iterator<char *>(pbase()); const auto rbase = std::reverse_iterator<char *>(pbase());
const auto rpptr = std::reverse_iterator<char *>(pptr()); const auto rpptr = std::reverse_iterator<char *>(pptr());
auto is_ascii = [](char c) { auto is_ascii = [](char c) { return (static_cast<unsigned char>(c) & 0x80) == 0x00; };
return (static_cast<unsigned char>(c) & 0x80) == 0x00; auto is_leading = [](char c) { return (static_cast<unsigned char>(c) & 0xC0) == 0xC0; };
}; auto is_leading_2b = [](char c) { return static_cast<unsigned char>(c) <= 0xDF; };
auto is_leading = [](char c) { auto is_leading_3b = [](char c) { return static_cast<unsigned char>(c) <= 0xEF; };
return (static_cast<unsigned char>(c) & 0xC0) == 0xC0;
};
auto is_leading_2b = [](char c) {
return static_cast<unsigned char>(c) <= 0xDF;
};
auto is_leading_3b = [](char c) {
return static_cast<unsigned char>(c) <= 0xEF;
};
// If the last character is ASCII, there are no incomplete code points // If the last character is ASCII, there are no incomplete code points
if (is_ascii(*rpptr)) { if (is_ascii(*rpptr)) {
return 0; return 0;
} }
// Otherwise, work back from the end of the buffer and find the first // Otherwise, work back from the end of the buffer and find the first
// UTF-8 leading byte // UTF-8 leading byte
const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase; const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase;
const auto leading = std::find_if(rpptr, rpend, is_leading); const auto leading = std::find_if(rpptr, rpend, is_leading);
if (leading == rbase) { if (leading == rbase) {
return 0; return 0;
} }
const auto dist = static_cast<size_t>(leading - rpptr); const auto dist = static_cast<size_t>(leading - rpptr);
size_t remainder = 0; size_t remainder = 0;
if (dist == 0) { if (dist == 0) {
remainder = 1; // 1-byte code point is impossible remainder = 1; // 1-byte code point is impossible
...@@ -103,7 +95,7 @@ private: ...@@ -103,7 +95,7 @@ private:
if (pbase() != pptr()) { // If buffer is not empty if (pbase() != pptr()) { // If buffer is not empty
gil_scoped_acquire tmp; gil_scoped_acquire tmp;
// This subtraction cannot be negative, so dropping the sign. // This subtraction cannot be negative, so dropping the sign.
auto size = static_cast<size_t>(pptr() - pbase()); auto size = static_cast<size_t>(pptr() - pbase());
size_t remainder = utf8_remainder(); size_t remainder = utf8_remainder();
if (size > remainder) { if (size > remainder) {
...@@ -122,9 +114,7 @@ private: ...@@ -122,9 +114,7 @@ private:
return 0; return 0;
} }
int sync() override { int sync() override { return _sync(); }
return _sync();
}
public: public:
explicit pythonbuf(const object &pyostream, size_t buffer_size = 1024) explicit pythonbuf(const object &pyostream, size_t buffer_size = 1024)
...@@ -133,17 +123,14 @@ public: ...@@ -133,17 +123,14 @@ public:
setp(d_buffer.get(), d_buffer.get() + buf_size - 1); setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
} }
pythonbuf(pythonbuf&&) = default; pythonbuf(pythonbuf &&) = default;
/// Sync before destroy /// Sync before destroy
~pythonbuf() override { ~pythonbuf() override { _sync(); }
_sync();
}
}; };
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
/** \rst /** \rst
This a move-only guard that redirects output. This a move-only guard that redirects output.
...@@ -183,9 +170,7 @@ public: ...@@ -183,9 +170,7 @@ public:
old = costream.rdbuf(&buffer); old = costream.rdbuf(&buffer);
} }
~scoped_ostream_redirect() { ~scoped_ostream_redirect() { costream.rdbuf(old); }
costream.rdbuf(old);
}
scoped_ostream_redirect(const scoped_ostream_redirect &) = delete; scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
scoped_ostream_redirect(scoped_ostream_redirect &&other) = default; scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
...@@ -193,7 +178,6 @@ public: ...@@ -193,7 +178,6 @@ public:
scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete; scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
}; };
/** \rst /** \rst
Like `scoped_ostream_redirect`, but redirects cerr by default. This class Like `scoped_ostream_redirect`, but redirects cerr by default. This class
is provided primary to make ``py::call_guard`` easier to make. is provided primary to make ``py::call_guard`` easier to make.
...@@ -213,7 +197,6 @@ public: ...@@ -213,7 +197,6 @@ public:
: scoped_ostream_redirect(costream, pyostream) {} : scoped_ostream_redirect(costream, pyostream) {}
}; };
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
// Class to redirect output as a context manager. C++ backend. // Class to redirect output as a context manager. C++ backend.
......
...@@ -15,44 +15,54 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) ...@@ -15,44 +15,54 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
class options { class options {
public: public:
// Default RAII constructor, which leaves settings as they currently are. // Default RAII constructor, which leaves settings as they currently are.
options() : previous_state(global_state()) {} options() : previous_state(global_state()) {}
// Class is non-copyable. // Class is non-copyable.
options(const options&) = delete; options(const options &) = delete;
options& operator=(const options&) = delete; options &operator=(const options &) = delete;
// Destructor, which restores settings that were in effect before. // Destructor, which restores settings that were in effect before.
~options() { ~options() { global_state() = previous_state; }
global_state() = previous_state;
}
// Setter methods (affect the global state): // Setter methods (affect the global state):
options& disable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = false; return *this; } options &disable_user_defined_docstrings() & {
global_state().show_user_defined_docstrings = false;
return *this;
}
options& enable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = true; return *this; } options &enable_user_defined_docstrings() & {
global_state().show_user_defined_docstrings = true;
return *this;
}
options& disable_function_signatures() & { global_state().show_function_signatures = false; return *this; } options &disable_function_signatures() & {
global_state().show_function_signatures = false;
return *this;
}
options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; } options &enable_function_signatures() & {
global_state().show_function_signatures = true;
return *this;
}
// Getter methods (return the global state): // Getter methods (return the global state):
static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; } static bool show_user_defined_docstrings() {
return global_state().show_user_defined_docstrings;
}
static bool show_function_signatures() { return global_state().show_function_signatures; } static bool show_function_signatures() { return global_state().show_function_signatures; }
// This type is not meant to be allocated on the heap. // This type is not meant to be allocated on the heap.
void* operator new(size_t) = delete; void *operator new(size_t) = delete;
private: private:
struct state { struct state {
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings. bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
bool show_function_signatures = true; //< Include auto-generated function signatures bool show_function_signatures = true; //< Include auto-generated function signatures
// in docstrings. // in docstrings.
}; };
static state &global_state() { static state &global_state() {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -4,21 +4,20 @@ ...@@ -4,21 +4,20 @@
#pragma once #pragma once
#include "../cast.h"
#include "../pybind11.h" #include "../pybind11.h"
#include "../pytypes.h"
#include "../detail/common.h" #include "../detail/common.h"
#include "../detail/descr.h" #include "../detail/descr.h"
#include "../cast.h"
#include "../pytypes.h"
#include <string> #include <string>
#ifdef __has_include #ifdef __has_include
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \ # if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
PY_VERSION_HEX >= 0x03060000 PY_VERSION_HEX >= 0x03060000
# include <filesystem> # include <filesystem>
# define PYBIND11_HAS_FILESYSTEM 1 # define PYBIND11_HAS_FILESYSTEM 1
# endif # endif
#endif #endif
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL) #if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
...@@ -30,28 +29,29 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) ...@@ -30,28 +29,29 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
#if defined(PYBIND11_HAS_FILESYSTEM) #if defined(PYBIND11_HAS_FILESYSTEM)
template<typename T> struct path_caster { template <typename T>
struct path_caster {
private: private:
static PyObject* unicode_from_fs_native(const std::string& w) { static PyObject *unicode_from_fs_native(const std::string &w) {
#if !defined(PYPY_VERSION) # if !defined(PYPY_VERSION)
return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size())); return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
#else # else
// PyPy mistakenly declares the first parameter as non-const. // PyPy mistakenly declares the first parameter as non-const.
return PyUnicode_DecodeFSDefaultAndSize( return PyUnicode_DecodeFSDefaultAndSize(const_cast<char *>(w.c_str()), ssize_t(w.size()));
const_cast<char*>(w.c_str()), ssize_t(w.size())); # endif
#endif
} }
static PyObject* unicode_from_fs_native(const std::wstring& w) { static PyObject *unicode_from_fs_native(const std::wstring &w) {
return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size())); return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
} }
public: public:
static handle cast(const T& path, return_value_policy, handle) { static handle cast(const T &path, return_value_policy, handle) {
if (auto py_str = unicode_from_fs_native(path.native())) { if (auto py_str = unicode_from_fs_native(path.native())) {
return module_::import("pathlib").attr("Path")(reinterpret_steal<object>(py_str)) return module_::import("pathlib")
.release(); .attr("Path")(reinterpret_steal<object>(py_str))
.release();
} }
return nullptr; return nullptr;
} }
...@@ -60,12 +60,12 @@ public: ...@@ -60,12 +60,12 @@ public:
// PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of // PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
// calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy // calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
// issue #3168) so we do it ourselves instead. // issue #3168) so we do it ourselves instead.
PyObject* buf = PyOS_FSPath(handle.ptr()); PyObject *buf = PyOS_FSPath(handle.ptr());
if (!buf) { if (!buf) {
PyErr_Clear(); PyErr_Clear();
return false; return false;
} }
PyObject* native = nullptr; PyObject *native = nullptr;
if constexpr (std::is_same_v<typename T::value_type, char>) { if constexpr (std::is_same_v<typename T::value_type, char>) {
if (PyUnicode_FSConverter(buf, &native) != 0) { if (PyUnicode_FSConverter(buf, &native) != 0) {
if (auto *c_str = PyBytes_AsString(native)) { if (auto *c_str = PyBytes_AsString(native)) {
...@@ -78,7 +78,7 @@ public: ...@@ -78,7 +78,7 @@ public:
if (PyUnicode_FSDecoder(buf, &native) != 0) { if (PyUnicode_FSDecoder(buf, &native) != 0) {
if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) { if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
// AsWideCharString returns a new string that must be free'd. // AsWideCharString returns a new string that must be free'd.
value = c_str; // Copies the string. value = c_str; // Copies the string.
PyMem_Free(c_str); PyMem_Free(c_str);
} }
} }
...@@ -95,8 +95,8 @@ public: ...@@ -95,8 +95,8 @@ public:
PYBIND11_TYPE_CASTER(T, const_name("os.PathLike")); PYBIND11_TYPE_CASTER(T, const_name("os.PathLike"));
}; };
template<> struct type_caster<std::filesystem::path> template <>
: public path_caster<std::filesystem::path> {}; struct type_caster<std::filesystem::path> : public path_caster<std::filesystem::path> {};
#endif // PYBIND11_HAS_FILESYSTEM #endif // PYBIND11_HAS_FILESYSTEM
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
#include <cstdint> #include <cstdint>
// This file mimics a DSO that makes pybind11 calls but does not define a // This file mimics a DSO that makes pybind11 calls but does not define a
...@@ -25,34 +26,25 @@ void gil_acquire() { py::gil_scoped_acquire gil; } ...@@ -25,34 +26,25 @@ void gil_acquire() { py::gil_scoped_acquire gil; }
constexpr char kModuleName[] = "cross_module_gil_utils"; constexpr char kModuleName[] = "cross_module_gil_utils";
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
struct PyModuleDef moduledef = { struct PyModuleDef moduledef
PyModuleDef_HEAD_INIT, = {PyModuleDef_HEAD_INIT, kModuleName, NULL, 0, NULL, NULL, NULL, NULL, NULL};
kModuleName,
NULL,
0,
NULL,
NULL,
NULL,
NULL,
NULL
};
#else #else
PyMethodDef module_methods[] = { PyMethodDef module_methods[] = {{NULL, NULL, 0, NULL}};
{NULL, NULL, 0, NULL}
};
#endif #endif
} // namespace } // namespace
extern "C" PYBIND11_EXPORT extern "C" PYBIND11_EXPORT
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
PyObject* PyInit_cross_module_gil_utils() PyObject *
PyInit_cross_module_gil_utils()
#else #else
void initcross_module_gil_utils() void
initcross_module_gil_utils()
#endif #endif
{ {
PyObject* m = PyObject *m =
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
PyModule_Create(&moduledef); PyModule_Create(&moduledef);
#else #else
...@@ -60,11 +52,10 @@ void initcross_module_gil_utils() ...@@ -60,11 +52,10 @@ void initcross_module_gil_utils()
#endif #endif
if (m != NULL) { if (m != NULL) {
static_assert( static_assert(sizeof(&gil_acquire) == sizeof(void *),
sizeof(&gil_acquire) == sizeof(void*), "Function pointer must have the same size as void*");
"Function pointer must have the same size as void*"); PyModule_AddObject(
PyModule_AddObject(m, "gil_acquire_funcaddr", m, "gil_acquire_funcaddr", PyLong_FromVoidPtr(reinterpret_cast<void *>(&gil_acquire)));
PyLong_FromVoidPtr(reinterpret_cast<void*>(&gil_acquire)));
} }
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
......
#pragma once #pragma once
#include <utility>
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <utility>
/// Simple class used to test py::local: /// Simple class used to test py::local:
template <int> class LocalBase { template <int>
class LocalBase {
public: public:
explicit LocalBase(int i) : i(i) { } explicit LocalBase(int i) : i(i) {}
int i = -1; int i = -1;
}; };
...@@ -35,12 +36,12 @@ using NonLocalVec2 = std::vector<NonLocal2>; ...@@ -35,12 +36,12 @@ using NonLocalVec2 = std::vector<NonLocal2>;
using NonLocalMap = std::unordered_map<std::string, NonLocalType>; using NonLocalMap = std::unordered_map<std::string, NonLocalType>;
using NonLocalMap2 = std::unordered_map<std::string, uint8_t>; using NonLocalMap2 = std::unordered_map<std::string, uint8_t>;
// Exception that will be caught via the module local translator. // Exception that will be caught via the module local translator.
class LocalException : public std::exception { class LocalException : public std::exception {
public: public:
explicit LocalException(const char * m) : message{m} {} explicit LocalException(const char *m) : message{m} {}
const char * what() const noexcept override {return message.c_str();} const char *what() const noexcept override { return message.c_str(); }
private: private:
std::string message = ""; std::string message = "";
}; };
...@@ -48,8 +49,9 @@ private: ...@@ -48,8 +49,9 @@ private:
// Exception that will be registered with register_local_exception_translator // Exception that will be registered with register_local_exception_translator
class LocalSimpleException : public std::exception { class LocalSimpleException : public std::exception {
public: public:
explicit LocalSimpleException(const char * m) : message{m} {} explicit LocalSimpleException(const char *m) : message{m} {}
const char * what() const noexcept override {return message.c_str();} const char *what() const noexcept override { return message.c_str(); }
private: private:
std::string message = ""; std::string message = "";
}; };
...@@ -58,17 +60,16 @@ PYBIND11_MAKE_OPAQUE(LocalVec); ...@@ -58,17 +60,16 @@ PYBIND11_MAKE_OPAQUE(LocalVec);
PYBIND11_MAKE_OPAQUE(LocalVec2); PYBIND11_MAKE_OPAQUE(LocalVec2);
PYBIND11_MAKE_OPAQUE(LocalMap); PYBIND11_MAKE_OPAQUE(LocalMap);
PYBIND11_MAKE_OPAQUE(NonLocalVec); PYBIND11_MAKE_OPAQUE(NonLocalVec);
//PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2 // PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2
PYBIND11_MAKE_OPAQUE(NonLocalMap); PYBIND11_MAKE_OPAQUE(NonLocalMap);
PYBIND11_MAKE_OPAQUE(NonLocalMap2); PYBIND11_MAKE_OPAQUE(NonLocalMap2);
// Simple bindings (used with the above): // Simple bindings (used with the above):
template <typename T, int Adjust = 0, typename... Args> template <typename T, int Adjust = 0, typename... Args>
py::class_<T> bind_local(Args && ...args) { py::class_<T> bind_local(Args &&...args) {
return py::class_<T>(std::forward<Args>(args)...) return py::class_<T>(std::forward<Args>(args)...).def(py::init<int>()).def("get", [](T &i) {
.def(py::init<int>()) return i.i + Adjust;
.def("get", [](T &i) { return i.i + Adjust; }); });
}; };
// Simulate a foreign library base class (to match the example in the docs): // Simulate a foreign library base class (to match the example in the docs):
...@@ -81,5 +82,11 @@ public: ...@@ -81,5 +82,11 @@ public:
}; };
} // namespace pets } // namespace pets
struct MixGL { int i; explicit MixGL(int i) : i{i} {} }; struct MixGL {
struct MixGL2 { int i; explicit MixGL2(int i) : i{i} {} }; int i;
explicit MixGL(int i) : i{i} {}
};
struct MixGL2 {
int i;
explicit MixGL2(int i) : i{i} {}
};
#if !defined(__OBJECT_H) #if !defined(__OBJECT_H)
#define __OBJECT_H # define __OBJECT_H
#include <atomic> # include "constructor_stats.h"
#include "constructor_stats.h"
# include <atomic>
/// Reference counted object base class /// Reference counted object base class
class Object { class Object {
...@@ -35,13 +36,15 @@ public: ...@@ -35,13 +36,15 @@ public:
} }
virtual std::string toString() const = 0; virtual std::string toString() const = 0;
protected: protected:
/** \brief Virtual protected deconstructor. /** \brief Virtual protected deconstructor.
* (Will only be called by \ref ref) * (Will only be called by \ref ref)
*/ */
virtual ~Object() { print_destroyed(this); } virtual ~Object() { print_destroyed(this); }
private: private:
mutable std::atomic<int> m_refCount { 0 }; mutable std::atomic<int> m_refCount{0};
}; };
// Tag class used to track constructions of ref objects. When we track constructors, below, we // Tag class used to track constructions of ref objects. When we track constructors, below, we
...@@ -60,10 +63,14 @@ class ref_tag {}; ...@@ -60,10 +63,14 @@ class ref_tag {};
* *
* \ingroup libcore * \ingroup libcore
*/ */
template <typename T> class ref { template <typename T>
class ref {
public: public:
/// Create a nullptr reference /// Create a nullptr reference
ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); } ref() : m_ptr(nullptr) {
print_default_created(this);
track_default_created((ref_tag *) this);
}
/// Construct a reference from a pointer /// Construct a reference from a pointer
explicit ref(T *ptr) : m_ptr(ptr) { explicit ref(T *ptr) : m_ptr(ptr) {
...@@ -71,8 +78,8 @@ public: ...@@ -71,8 +78,8 @@ public:
((Object *) m_ptr)->incRef(); ((Object *) m_ptr)->incRef();
} }
print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer"); print_created(this, "from pointer", m_ptr);
track_created((ref_tag *) this, "from pointer");
} }
/// Copy constructor /// Copy constructor
...@@ -81,14 +88,16 @@ public: ...@@ -81,14 +88,16 @@ public:
((Object *) m_ptr)->incRef(); ((Object *) m_ptr)->incRef();
} }
print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this); print_copy_created(this, "with pointer", m_ptr);
track_copy_created((ref_tag *) this);
} }
/// Move constructor /// Move constructor
ref(ref &&r) noexcept : m_ptr(r.m_ptr) { ref(ref &&r) noexcept : m_ptr(r.m_ptr) {
r.m_ptr = nullptr; r.m_ptr = nullptr;
print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this); print_move_created(this, "with pointer", m_ptr);
track_move_created((ref_tag *) this);
} }
/// Destroy this reference /// Destroy this reference
...@@ -97,12 +106,14 @@ public: ...@@ -97,12 +106,14 @@ public:
((Object *) m_ptr)->decRef(); ((Object *) m_ptr)->decRef();
} }
print_destroyed(this); track_destroyed((ref_tag*) this); print_destroyed(this);
track_destroyed((ref_tag *) this);
} }
/// Move another reference into the current one /// Move another reference into the current one
ref &operator=(ref &&r) noexcept { ref &operator=(ref &&r) noexcept {
print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this); print_move_assigned(this, "pointer", r.m_ptr);
track_move_assigned((ref_tag *) this);
if (*this == r) { if (*this == r) {
return *this; return *this;
...@@ -116,7 +127,7 @@ public: ...@@ -116,7 +127,7 @@ public:
} }
/// Overwrite this reference with another reference /// Overwrite this reference with another reference
ref& operator=(const ref& r) { ref &operator=(const ref &r) {
if (this == &r) { if (this == &r) {
return *this; return *this;
} }
...@@ -137,8 +148,9 @@ public: ...@@ -137,8 +148,9 @@ public:
} }
/// Overwrite this reference with a pointer to another object /// Overwrite this reference with a pointer to another object
ref& operator=(T *ptr) { ref &operator=(T *ptr) {
print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer"); print_values(this, "assigned pointer");
track_values((ref_tag *) this, "assigned pointer");
if (m_ptr == ptr) { if (m_ptr == ptr) {
return *this; return *this;
...@@ -160,31 +172,32 @@ public: ...@@ -160,31 +172,32 @@ public:
bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; } bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
/// Compare this reference with a pointer /// Compare this reference with a pointer
bool operator==(const T* ptr) const { return m_ptr == ptr; } bool operator==(const T *ptr) const { return m_ptr == ptr; }
/// Compare this reference with a pointer /// Compare this reference with a pointer
bool operator!=(const T* ptr) const { return m_ptr != ptr; } bool operator!=(const T *ptr) const { return m_ptr != ptr; }
/// Access the object referenced by this reference /// Access the object referenced by this reference
T* operator->() { return m_ptr; } T *operator->() { return m_ptr; }
/// Access the object referenced by this reference /// Access the object referenced by this reference
const T* operator->() const { return m_ptr; } const T *operator->() const { return m_ptr; }
/// Return a C++ reference to the referenced object /// Return a C++ reference to the referenced object
T& operator*() { return *m_ptr; } T &operator*() { return *m_ptr; }
/// Return a const C++ reference to the referenced object /// Return a const C++ reference to the referenced object
const T& operator*() const { return *m_ptr; } const T &operator*() const { return *m_ptr; }
/// Return a pointer to the referenced object /// Return a pointer to the referenced object
explicit operator T* () { return m_ptr; } explicit operator T *() { return m_ptr; }
/// Return a const pointer to the referenced object /// Return a const pointer to the referenced object
T* get_ptr() { return m_ptr; } T *get_ptr() { return m_ptr; }
/// Return a pointer to the referenced object /// Return a pointer to the referenced object
const T* get_ptr() const { return m_ptr; } const T *get_ptr() const { return m_ptr; }
private: private:
T *m_ptr; T *m_ptr;
}; };
......
...@@ -7,12 +7,12 @@ ...@@ -7,12 +7,12 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h" #include <pybind11/stl_bind.h>
#include "local_bindings.h" #include "local_bindings.h"
#include "pybind11_tests.h"
#include "test_exceptions.h" #include "test_exceptions.h"
#include <pybind11/stl_bind.h>
#include <numeric> #include <numeric>
#include <utility> #include <utility>
...@@ -30,39 +30,45 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) { ...@@ -30,39 +30,45 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
// test_exceptions.py // test_exceptions.py
py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException"); py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException");
m.def("raise_runtime_error", []() { PyErr_SetString(PyExc_RuntimeError, "My runtime error"); throw py::error_already_set(); }); m.def("raise_runtime_error", []() {
m.def("raise_value_error", []() { PyErr_SetString(PyExc_ValueError, "My value error"); throw py::error_already_set(); }); PyErr_SetString(PyExc_RuntimeError, "My runtime error");
throw py::error_already_set();
});
m.def("raise_value_error", []() {
PyErr_SetString(PyExc_ValueError, "My value error");
throw py::error_already_set();
});
m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); }); m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); });
m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); }); m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); });
m.def("throw_stop_iteration", []() { throw py::stop_iteration(); }); m.def("throw_stop_iteration", []() { throw py::stop_iteration(); });
m.def("throw_local_error", []() { throw LocalException("just local"); }); m.def("throw_local_error", []() { throw LocalException("just local"); });
m.def("throw_local_simple_error", []() { throw LocalSimpleException("external mod"); }); m.def("throw_local_simple_error", []() { throw LocalSimpleException("external mod"); });
py::register_exception_translator([](std::exception_ptr p) { py::register_exception_translator([](std::exception_ptr p) {
try { try {
if (p) { if (p) {
std::rethrow_exception(p); std::rethrow_exception(p);
} }
} catch (const shared_exception &e) { } catch (const shared_exception &e) {
PyErr_SetString(PyExc_KeyError, e.what()); PyErr_SetString(PyExc_KeyError, e.what());
} }
}); });
// translate the local exception into a key error but only in this module // translate the local exception into a key error but only in this module
py::register_local_exception_translator([](std::exception_ptr p) { py::register_local_exception_translator([](std::exception_ptr p) {
try { try {
if (p) { if (p) {
std::rethrow_exception(p); std::rethrow_exception(p);
} }
} catch (const LocalException &e) { } catch (const LocalException &e) {
PyErr_SetString(PyExc_KeyError, e.what()); PyErr_SetString(PyExc_KeyError, e.what());
} }
}); });
// test_local_bindings.py // test_local_bindings.py
// Local to both: // Local to both:
bind_local<LocalType, 1>(m, "LocalType", py::module_local()) bind_local<LocalType, 1>(m, "LocalType", py::module_local()).def("get2", [](LocalType &t) {
.def("get2", [](LocalType &t) { return t.i + 2; }) return t.i + 2;
; });
// Can only be called with our python type: // Can only be called with our python type:
m.def("local_value", [](LocalType &l) { return l.i; }); m.def("local_value", [](LocalType &l) { return l.i; });
...@@ -70,9 +76,7 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) { ...@@ -70,9 +76,7 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
// test_nonlocal_failure // test_nonlocal_failure
// This registration will fail (global registration when LocalFail is already registered // This registration will fail (global registration when LocalFail is already registered
// globally in the main test module): // globally in the main test module):
m.def("register_nonlocal", [m]() { m.def("register_nonlocal", [m]() { bind_local<NonLocalType, 0>(m, "NonLocalType"); });
bind_local<NonLocalType, 0>(m, "NonLocalType");
});
// test_stl_bind_local // test_stl_bind_local
// stl_bind.h binders defaults to py::module_local if the types are local or converting: // stl_bind.h binders defaults to py::module_local if the types are local or converting:
...@@ -82,27 +86,21 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) { ...@@ -82,27 +86,21 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
// test_stl_bind_global // test_stl_bind_global
// and global if the type (or one of the types, for the map) is global (so these will fail, // and global if the type (or one of the types, for the map) is global (so these will fail,
// assuming pybind11_tests is already loaded): // assuming pybind11_tests is already loaded):
m.def("register_nonlocal_vec", [m]() { m.def("register_nonlocal_vec", [m]() { py::bind_vector<NonLocalVec>(m, "NonLocalVec"); });
py::bind_vector<NonLocalVec>(m, "NonLocalVec"); m.def("register_nonlocal_map", [m]() { py::bind_map<NonLocalMap>(m, "NonLocalMap"); });
});
m.def("register_nonlocal_map", [m]() {
py::bind_map<NonLocalMap>(m, "NonLocalMap");
});
// The default can, however, be overridden to global using `py::module_local()` or // The default can, however, be overridden to global using `py::module_local()` or
// `py::module_local(false)`. // `py::module_local(false)`.
// Explicitly made local: // Explicitly made local:
py::bind_vector<NonLocalVec2>(m, "NonLocalVec2", py::module_local()); py::bind_vector<NonLocalVec2>(m, "NonLocalVec2", py::module_local());
// Explicitly made global (and so will fail to bind): // Explicitly made global (and so will fail to bind):
m.def("register_nonlocal_map2", [m]() { m.def("register_nonlocal_map2",
py::bind_map<NonLocalMap2>(m, "NonLocalMap2", py::module_local(false)); [m]() { py::bind_map<NonLocalMap2>(m, "NonLocalMap2", py::module_local(false)); });
});
// test_mixed_local_global // test_mixed_local_global
// We try this both with the global type registered first and vice versa (the order shouldn't // We try this both with the global type registered first and vice versa (the order shouldn't
// matter). // matter).
m.def("register_mixed_global_local", [m]() { m.def("register_mixed_global_local",
bind_local<MixedGlobalLocal, 200>(m, "MixedGlobalLocal", py::module_local()); [m]() { bind_local<MixedGlobalLocal, 200>(m, "MixedGlobalLocal", py::module_local()); });
});
m.def("register_mixed_local_global", [m]() { m.def("register_mixed_local_global", [m]() {
bind_local<MixedLocalGlobal, 2000>(m, "MixedLocalGlobal", py::module_local(false)); bind_local<MixedLocalGlobal, 2000>(m, "MixedLocalGlobal", py::module_local(false));
}); });
...@@ -110,14 +108,14 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) { ...@@ -110,14 +108,14 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); }); m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });
// test_internal_locals_differ // test_internal_locals_differ
m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::get_local_internals().registered_types_cpp; }); m.def("local_cpp_types_addr",
[]() { return (uintptr_t) &py::detail::get_local_internals().registered_types_cpp; });
// test_stl_caster_vs_stl_bind // test_stl_caster_vs_stl_bind
py::bind_vector<std::vector<int>>(m, "VectorInt"); py::bind_vector<std::vector<int>>(m, "VectorInt");
m.def("load_vector_via_binding", [](std::vector<int> &v) { m.def("load_vector_via_binding",
return std::accumulate(v.begin(), v.end(), 0); [](std::vector<int> &v) { return std::accumulate(v.begin(), v.end(), 0); });
});
// test_cross_module_calls // test_cross_module_calls
m.def("return_self", [](LocalVec *v) { return v; }); m.def("return_self", [](LocalVec *v) { return v; });
...@@ -127,11 +125,9 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) { ...@@ -127,11 +125,9 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
public: public:
explicit Dog(std::string name) : Pet(std::move(name)) {} explicit Dog(std::string name) : Pet(std::move(name)) {}
}; };
py::class_<pets::Pet>(m, "Pet", py::module_local()) py::class_<pets::Pet>(m, "Pet", py::module_local()).def("name", &pets::Pet::name);
.def("name", &pets::Pet::name);
// Binding for local extending class: // Binding for local extending class:
py::class_<Dog, pets::Pet>(m, "Dog") py::class_<Dog, pets::Pet>(m, "Dog").def(py::init<std::string>());
.def(py::init<std::string>());
m.def("pet_name", [](pets::Pet &p) { return p.name(); }); m.def("pet_name", [](pets::Pet &p) { return p.name(); });
py::class_<MixGL>(m, "MixGL", py::module_local()).def(py::init<int>()); py::class_<MixGL>(m, "MixGL", py::module_local()).def(py::init<int>());
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
*/ */
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include "constructor_stats.h" #include "constructor_stats.h"
#include <functional> #include <functional>
...@@ -31,9 +32,7 @@ std::list<std::function<void(py::module_ &)>> &initializers() { ...@@ -31,9 +32,7 @@ std::list<std::function<void(py::module_ &)>> &initializers() {
return inits; return inits;
} }
test_initializer::test_initializer(Initializer init) { test_initializer::test_initializer(Initializer init) { initializers().emplace_back(init); }
initializers().emplace_back(init);
}
test_initializer::test_initializer(const char *submodule_name, Initializer init) { test_initializer::test_initializer(const char *submodule_name, Initializer init) {
initializers().emplace_back([=](py::module_ &parent) { initializers().emplace_back([=](py::module_ &parent) {
...@@ -51,15 +50,16 @@ void bind_ConstructorStats(py::module_ &m) { ...@@ -51,15 +50,16 @@ void bind_ConstructorStats(py::module_ &m) {
.def_readwrite("move_assignments", &ConstructorStats::move_assignments) .def_readwrite("move_assignments", &ConstructorStats::move_assignments)
.def_readwrite("copy_constructions", &ConstructorStats::copy_constructions) .def_readwrite("copy_constructions", &ConstructorStats::copy_constructions)
.def_readwrite("move_constructions", &ConstructorStats::move_constructions) .def_readwrite("move_constructions", &ConstructorStats::move_constructions)
.def_static("get", (ConstructorStats &(*)(py::object)) &ConstructorStats::get, py::return_value_policy::reference_internal) .def_static("get",
(ConstructorStats & (*) (py::object)) & ConstructorStats::get,
py::return_value_policy::reference_internal)
// Not exactly ConstructorStats, but related: expose the internal pybind number of registered instances // Not exactly ConstructorStats, but related: expose the internal pybind number of
// to allow instance cleanup checks (invokes a GC first) // registered instances to allow instance cleanup checks (invokes a GC first)
.def_static("detail_reg_inst", []() { .def_static("detail_reg_inst", []() {
ConstructorStats::gc(); ConstructorStats::gc();
return py::detail::get_internals().registered_instances.size(); return py::detail::get_internals().registered_instances.size();
}) });
;
} }
PYBIND11_MODULE(pybind11_tests, m) { PYBIND11_MODULE(pybind11_tests, m) {
...@@ -79,12 +79,12 @@ PYBIND11_MODULE(pybind11_tests, m) { ...@@ -79,12 +79,12 @@ PYBIND11_MODULE(pybind11_tests, m) {
.def("get_value", &UserType::value, "Get value using a method") .def("get_value", &UserType::value, "Get value using a method")
.def("set_value", &UserType::set, "Set value using a method") .def("set_value", &UserType::set, "Set value using a method")
.def_property("value", &UserType::value, &UserType::set, "Get/set value using a property") .def_property("value", &UserType::value, &UserType::set, "Get/set value using a property")
.def("__repr__", [](const UserType& u) { return "UserType({})"_s.format(u.value()); }); .def("__repr__", [](const UserType &u) { return "UserType({})"_s.format(u.value()); });
py::class_<IncType, UserType>(m, "IncType") py::class_<IncType, UserType>(m, "IncType")
.def(py::init<>()) .def(py::init<>())
.def(py::init<int>()) .def(py::init<int>())
.def("__repr__", [](const IncType& u) { return "IncType({})"_s.format(u.value()); }); .def("__repr__", [](const IncType &u) { return "IncType({})"_s.format(u.value()); });
for (const auto &initializer : initializers()) { for (const auto &initializer : initializers()) {
initializer(m); initializer(m);
......
#pragma once #pragma once
#include <pybind11/pybind11.h>
#include <pybind11/eval.h> #include <pybind11/eval.h>
#include <pybind11/pybind11.h>
#if defined(_MSC_VER) && _MSC_VER < 1910 #if defined(_MSC_VER) && _MSC_VER < 1910
// We get some really long type names here which causes MSVC 2015 to emit warnings // We get some really long type names here which causes MSVC 2015 to emit warnings
# pragma warning(disable : 4503) // NOLINT: warning C4503: decorated name length exceeded, name was truncated # pragma warning( \
disable : 4503) // NOLINT: warning C4503: decorated name length exceeded, name was truncated
#endif #endif
namespace py = pybind11; namespace py = pybind11;
...@@ -25,13 +26,13 @@ public: ...@@ -25,13 +26,13 @@ public:
void test_submodule_##name(py::module_ &(variable)) void test_submodule_##name(py::module_ &(variable))
/// Dummy type which is not exported anywhere -- something to trigger a conversion error /// Dummy type which is not exported anywhere -- something to trigger a conversion error
struct UnregisteredType { }; struct UnregisteredType {};
/// A user-defined type which is exported and can be used by any test /// A user-defined type which is exported and can be used by any test
class UserType { class UserType {
public: public:
UserType() = default; UserType() = default;
explicit UserType(int i) : i(i) { } explicit UserType(int i) : i(i) {}
int value() const { return i; } int value() const { return i; }
void set(int set) { i = set; } void set(int set) { i = set; }
...@@ -45,7 +46,7 @@ class IncType : public UserType { ...@@ -45,7 +46,7 @@ class IncType : public UserType {
public: public:
using UserType::UserType; using UserType::UserType;
IncType() = default; IncType() = default;
IncType(const IncType &other) : IncType(other.value() + 1) { } IncType(const IncType &other) : IncType(other.value() + 1) {}
IncType(IncType &&) = delete; IncType(IncType &&) = delete;
IncType &operator=(const IncType &) = delete; IncType &operator=(const IncType &) = delete;
IncType &operator=(IncType &&) = delete; IncType &operator=(IncType &&) = delete;
...@@ -57,16 +58,21 @@ union IntFloat { ...@@ -57,16 +58,21 @@ union IntFloat {
float f; float f;
}; };
/// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast context. /// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast
/// Used to test recursive casters (e.g. std::tuple, stl containers). /// context. Used to test recursive casters (e.g. std::tuple, stl containers).
struct RValueCaster {}; struct RValueCaster {};
PYBIND11_NAMESPACE_BEGIN(pybind11) PYBIND11_NAMESPACE_BEGIN(pybind11)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
template<> class type_caster<RValueCaster> { template <>
class type_caster<RValueCaster> {
public: public:
PYBIND11_TYPE_CASTER(RValueCaster, const_name("RValueCaster")); PYBIND11_TYPE_CASTER(RValueCaster, const_name("RValueCaster"));
static handle cast(RValueCaster &&, return_value_policy, handle) { return py::str("rvalue").release(); } static handle cast(RValueCaster &&, return_value_policy, handle) {
static handle cast(const RValueCaster &, return_value_policy, handle) { return py::str("lvalue").release(); } return py::str("rvalue").release();
}
static handle cast(const RValueCaster &, return_value_policy, handle) {
return py::str("lvalue").release();
}
}; };
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(pybind11) PYBIND11_NAMESPACE_END(pybind11)
...@@ -80,5 +86,6 @@ void ignoreOldStyleInitWarnings(F &&body) { ...@@ -80,5 +86,6 @@ void ignoreOldStyleInitWarnings(F &&body) {
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.filterwarnings("ignore", message=message, category=FutureWarning) warnings.filterwarnings("ignore", message=message, category=FutureWarning)
body() body()
)", py::dict(py::arg("body") = py::cpp_function(body))); )",
py::dict(py::arg("body") = py::cpp_function(body)));
} }
...@@ -11,12 +11,11 @@ ...@@ -11,12 +11,11 @@
TEST_SUBMODULE(async_module, m) { TEST_SUBMODULE(async_module, m) {
struct DoesNotSupportAsync {}; struct DoesNotSupportAsync {};
py::class_<DoesNotSupportAsync>(m, "DoesNotSupportAsync") py::class_<DoesNotSupportAsync>(m, "DoesNotSupportAsync").def(py::init<>());
.def(py::init<>());
struct SupportsAsync {}; struct SupportsAsync {};
py::class_<SupportsAsync>(m, "SupportsAsync") py::class_<SupportsAsync>(m, "SupportsAsync")
.def(py::init<>()) .def(py::init<>())
.def("__await__", [](const SupportsAsync& self) -> py::object { .def("__await__", [](const SupportsAsync &self) -> py::object {
static_cast<void>(self); static_cast<void>(self);
py::object loop = py::module_::import("asyncio.events").attr("get_event_loop")(); py::object loop = py::module_::import("asyncio.events").attr("get_event_loop")();
py::object f = loop.attr("create_future")(); py::object f = loop.attr("create_future")();
......
...@@ -7,10 +7,11 @@ ...@@ -7,10 +7,11 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include "constructor_stats.h"
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include "constructor_stats.h"
#include "pybind11_tests.h"
TEST_SUBMODULE(buffers, m) { TEST_SUBMODULE(buffers, m) {
// test_from_python / test_to_python: // test_from_python / test_to_python:
class Matrix { class Matrix {
...@@ -23,7 +24,8 @@ TEST_SUBMODULE(buffers, m) { ...@@ -23,7 +24,8 @@ TEST_SUBMODULE(buffers, m) {
} }
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) { Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); print_copy_created(this,
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
m_data = new float[(size_t) (m_rows * m_cols)]; m_data = new float[(size_t) (m_rows * m_cols)];
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols)); memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
...@@ -37,7 +39,8 @@ TEST_SUBMODULE(buffers, m) { ...@@ -37,7 +39,8 @@ TEST_SUBMODULE(buffers, m) {
} }
~Matrix() { ~Matrix() {
print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); print_destroyed(this,
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
delete[] m_data; delete[] m_data;
} }
...@@ -56,27 +59,33 @@ TEST_SUBMODULE(buffers, m) { ...@@ -56,27 +59,33 @@ TEST_SUBMODULE(buffers, m) {
} }
Matrix &operator=(Matrix &&s) noexcept { Matrix &operator=(Matrix &&s) noexcept {
print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); print_move_assigned(this,
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
if (&s != this) { if (&s != this) {
delete[] m_data; delete[] m_data;
m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data; m_rows = s.m_rows;
s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr; m_cols = s.m_cols;
m_data = s.m_data;
s.m_rows = 0;
s.m_cols = 0;
s.m_data = nullptr;
} }
return *this; return *this;
} }
float operator()(py::ssize_t i, py::ssize_t j) const { float operator()(py::ssize_t i, py::ssize_t j) const {
return m_data[(size_t) (i*m_cols + j)]; return m_data[(size_t) (i * m_cols + j)];
} }
float &operator()(py::ssize_t i, py::ssize_t j) { float &operator()(py::ssize_t i, py::ssize_t j) {
return m_data[(size_t) (i*m_cols + j)]; return m_data[(size_t) (i * m_cols + j)];
} }
float *data() { return m_data; } float *data() { return m_data; }
py::ssize_t rows() const { return m_rows; } py::ssize_t rows() const { return m_rows; }
py::ssize_t cols() const { return m_cols; } py::ssize_t cols() const { return m_cols; }
private: private:
py::ssize_t m_rows; py::ssize_t m_rows;
py::ssize_t m_cols; py::ssize_t m_cols;
...@@ -117,11 +126,10 @@ TEST_SUBMODULE(buffers, m) { ...@@ -117,11 +126,10 @@ TEST_SUBMODULE(buffers, m) {
/// Provide buffer access /// Provide buffer access
.def_buffer([](Matrix &m) -> py::buffer_info { .def_buffer([](Matrix &m) -> py::buffer_info {
return py::buffer_info( return py::buffer_info(
m.data(), /* Pointer to buffer */ m.data(), /* Pointer to buffer */
{ m.rows(), m.cols() }, /* Buffer dimensions */ {m.rows(), m.cols()}, /* Buffer dimensions */
{ sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */ {sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */
sizeof(float) } sizeof(float)});
);
}); });
// test_inherited_protocol // test_inherited_protocol
...@@ -130,9 +138,7 @@ TEST_SUBMODULE(buffers, m) { ...@@ -130,9 +138,7 @@ TEST_SUBMODULE(buffers, m) {
explicit SquareMatrix(py::ssize_t n) : Matrix(n, n) {} explicit SquareMatrix(py::ssize_t n) : Matrix(n, n) {}
}; };
// Derived classes inherit the buffer protocol and the buffer access function // Derived classes inherit the buffer protocol and the buffer access function
py::class_<SquareMatrix, Matrix>(m, "SquareMatrix") py::class_<SquareMatrix, Matrix>(m, "SquareMatrix").def(py::init<py::ssize_t>());
.def(py::init<py::ssize_t>());
// test_pointer_to_member_fn // test_pointer_to_member_fn
// Tests that passing a pointer to member to the base class works in // Tests that passing a pointer to member to the base class works in
...@@ -141,8 +147,8 @@ TEST_SUBMODULE(buffers, m) { ...@@ -141,8 +147,8 @@ TEST_SUBMODULE(buffers, m) {
int32_t value = 0; int32_t value = 0;
py::buffer_info get_buffer_info() { py::buffer_info get_buffer_info() {
return py::buffer_info(&value, sizeof(value), return py::buffer_info(
py::format_descriptor<int32_t>::format(), 1); &value, sizeof(value), py::format_descriptor<int32_t>::format(), 1);
} }
}; };
py::class_<Buffer>(m, "Buffer", py::buffer_protocol()) py::class_<Buffer>(m, "Buffer", py::buffer_protocol())
...@@ -150,7 +156,6 @@ TEST_SUBMODULE(buffers, m) { ...@@ -150,7 +156,6 @@ TEST_SUBMODULE(buffers, m) {
.def_readwrite("value", &Buffer::value) .def_readwrite("value", &Buffer::value)
.def_buffer(&Buffer::get_buffer_info); .def_buffer(&Buffer::get_buffer_info);
class ConstBuffer { class ConstBuffer {
std::unique_ptr<int32_t> value; std::unique_ptr<int32_t> value;
...@@ -159,8 +164,8 @@ TEST_SUBMODULE(buffers, m) { ...@@ -159,8 +164,8 @@ TEST_SUBMODULE(buffers, m) {
void set_value(int32_t v) { *value = v; } void set_value(int32_t v) { *value = v; }
py::buffer_info get_buffer_info() const { py::buffer_info get_buffer_info() const {
return py::buffer_info(value.get(), sizeof(*value), return py::buffer_info(
py::format_descriptor<int32_t>::format(), 1); value.get(), sizeof(*value), py::format_descriptor<int32_t>::format(), 1);
} }
ConstBuffer() : value(new int32_t{0}) {} ConstBuffer() : value(new int32_t{0}) {}
...@@ -170,7 +175,7 @@ TEST_SUBMODULE(buffers, m) { ...@@ -170,7 +175,7 @@ TEST_SUBMODULE(buffers, m) {
.def_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value) .def_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value)
.def_buffer(&ConstBuffer::get_buffer_info); .def_buffer(&ConstBuffer::get_buffer_info);
struct DerivedBuffer : public Buffer { }; struct DerivedBuffer : public Buffer {};
py::class_<DerivedBuffer>(m, "DerivedBuffer", py::buffer_protocol()) py::class_<DerivedBuffer>(m, "DerivedBuffer", py::buffer_protocol())
.def(py::init<>()) .def(py::init<>())
.def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value) .def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value)
...@@ -180,9 +185,7 @@ TEST_SUBMODULE(buffers, m) { ...@@ -180,9 +185,7 @@ TEST_SUBMODULE(buffers, m) {
const uint8_t value = 0; const uint8_t value = 0;
explicit BufferReadOnly(uint8_t value) : value(value) {} explicit BufferReadOnly(uint8_t value) : value(value) {}
py::buffer_info get_buffer_info() { py::buffer_info get_buffer_info() { return py::buffer_info(&value, 1); }
return py::buffer_info(&value, 1);
}
}; };
py::class_<BufferReadOnly>(m, "BufferReadOnly", py::buffer_protocol()) py::class_<BufferReadOnly>(m, "BufferReadOnly", py::buffer_protocol())
.def(py::init<uint8_t>()) .def(py::init<uint8_t>())
...@@ -192,9 +195,7 @@ TEST_SUBMODULE(buffers, m) { ...@@ -192,9 +195,7 @@ TEST_SUBMODULE(buffers, m) {
uint8_t value = 0; uint8_t value = 0;
bool readonly = false; bool readonly = false;
py::buffer_info get_buffer_info() { py::buffer_info get_buffer_info() { return py::buffer_info(&value, 1, readonly); }
return py::buffer_info(&value, 1, readonly);
}
}; };
py::class_<BufferReadOnlySelect>(m, "BufferReadOnlySelect", py::buffer_protocol()) py::class_<BufferReadOnlySelect>(m, "BufferReadOnlySelect", py::buffer_protocol())
.def(py::init<>()) .def(py::init<>())
...@@ -213,9 +214,11 @@ TEST_SUBMODULE(buffers, m) { ...@@ -213,9 +214,11 @@ TEST_SUBMODULE(buffers, m) {
.def_readonly("strides", &py::buffer_info::strides) .def_readonly("strides", &py::buffer_info::strides)
.def_readonly("readonly", &py::buffer_info::readonly) .def_readonly("readonly", &py::buffer_info::readonly)
.def("__repr__", [](py::handle self) { .def("__repr__", [](py::handle self) {
return py::str("itemsize={0.itemsize!r}, size={0.size!r}, format={0.format!r}, ndim={0.ndim!r}, shape={0.shape!r}, strides={0.strides!r}, readonly={0.readonly!r}").format(self); return py::str("itemsize={0.itemsize!r}, size={0.size!r}, format={0.format!r}, "
}) "ndim={0.ndim!r}, shape={0.shape!r}, strides={0.strides!r}, "
; "readonly={0.readonly!r}")
.format(self);
});
m.def("get_buffer_info", [](const py::buffer &buffer) { return buffer.request(); }); m.def("get_buffer_info", [](const py::buffer &buffer) { return buffer.request(); });
} }
...@@ -40,18 +40,17 @@ TEST_SUBMODULE(call_policies, m) { ...@@ -40,18 +40,17 @@ TEST_SUBMODULE(call_policies, m) {
Child(Child &&) = default; Child(Child &&) = default;
~Child() { py::print("Releasing child."); } ~Child() { py::print("Releasing child."); }
}; };
py::class_<Child>(m, "Child") py::class_<Child>(m, "Child").def(py::init<>());
.def(py::init<>());
class Parent { class Parent {
public: public:
Parent() { py::print("Allocating parent."); } Parent() { py::print("Allocating parent."); }
Parent(const Parent& parent) = default; Parent(const Parent &parent) = default;
~Parent() { py::print("Releasing parent."); } ~Parent() { py::print("Releasing parent."); }
void addChild(Child *) { } void addChild(Child *) {}
Child *returnChild() { return new Child(); } Child *returnChild() { return new Child(); }
Child *returnNullChild() { return nullptr; } Child *returnNullChild() { return nullptr; }
static Child *staticFunction(Parent*) { return new Child(); } static Child *staticFunction(Parent *) { return new Child(); }
}; };
py::class_<Parent>(m, "Parent") py::class_<Parent>(m, "Parent")
.def(py::init<>()) .def(py::init<>())
...@@ -62,11 +61,12 @@ TEST_SUBMODULE(call_policies, m) { ...@@ -62,11 +61,12 @@ TEST_SUBMODULE(call_policies, m) {
.def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>()) .def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>())
.def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>()) .def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>())
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>()) .def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>())
.def_static( .def_static("staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>());
"staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>());
m.def("free_function", [](Parent*, Child*) {}, py::keep_alive<1, 2>()); m.def(
m.def("invalid_arg_index", []{}, py::keep_alive<0, 1>()); "free_function", [](Parent *, Child *) {}, py::keep_alive<1, 2>());
m.def(
"invalid_arg_index", [] {}, py::keep_alive<0, 1>());
#if !defined(PYPY_VERSION) #if !defined(PYPY_VERSION)
// test_alive_gc // test_alive_gc
...@@ -74,21 +74,28 @@ TEST_SUBMODULE(call_policies, m) { ...@@ -74,21 +74,28 @@ TEST_SUBMODULE(call_policies, m) {
public: public:
using Parent::Parent; using Parent::Parent;
}; };
py::class_<ParentGC, Parent>(m, "ParentGC", py::dynamic_attr()) py::class_<ParentGC, Parent>(m, "ParentGC", py::dynamic_attr()).def(py::init<>());
.def(py::init<>());
#endif #endif
// test_call_guard // test_call_guard
m.def("unguarded_call", &CustomGuard::report_status); m.def("unguarded_call", &CustomGuard::report_status);
m.def("guarded_call", &CustomGuard::report_status, py::call_guard<CustomGuard>()); m.def("guarded_call", &CustomGuard::report_status, py::call_guard<CustomGuard>());
m.def("multiple_guards_correct_order", []() { m.def(
return CustomGuard::report_status() + std::string(" & ") + DependentGuard::report_status(); "multiple_guards_correct_order",
}, py::call_guard<CustomGuard, DependentGuard>()); []() {
return CustomGuard::report_status() + std::string(" & ")
m.def("multiple_guards_wrong_order", []() { + DependentGuard::report_status();
return DependentGuard::report_status() + std::string(" & ") + CustomGuard::report_status(); },
}, py::call_guard<DependentGuard, CustomGuard>()); py::call_guard<CustomGuard, DependentGuard>());
m.def(
"multiple_guards_wrong_order",
[]() {
return DependentGuard::report_status() + std::string(" & ")
+ CustomGuard::report_status();
},
py::call_guard<DependentGuard, CustomGuard>());
#if defined(WITH_THREAD) && !defined(PYPY_VERSION) #if defined(WITH_THREAD) && !defined(PYPY_VERSION)
// `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well, // `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well,
......
...@@ -7,11 +7,12 @@ ...@@ -7,11 +7,12 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include "constructor_stats.h"
#include <pybind11/functional.h> #include <pybind11/functional.h>
#include <thread>
#include "constructor_stats.h"
#include "pybind11_tests.h"
#include <thread>
int dummy_function(int i) { return i + 1; } int dummy_function(int i) { return i + 1; }
...@@ -20,11 +21,12 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -20,11 +21,12 @@ TEST_SUBMODULE(callbacks, m) {
m.def("test_callback1", [](const py::object &func) { return func(); }); m.def("test_callback1", [](const py::object &func) { return func(); });
m.def("test_callback2", [](const py::object &func) { return func("Hello", 'x', true, 5); }); m.def("test_callback2", [](const py::object &func) { return func("Hello", 'x', true, 5); });
m.def("test_callback3", [](const std::function<int(int)> &func) { m.def("test_callback3", [](const std::function<int(int)> &func) {
return "func(43) = " + std::to_string(func(43)); }); return "func(43) = " + std::to_string(func(43));
m.def("test_callback4", []() -> std::function<int(int)> { return [](int i) { return i+1; }; });
m.def("test_callback5", []() {
return py::cpp_function([](int i) { return i+1; }, py::arg("number"));
}); });
m.def("test_callback4",
[]() -> std::function<int(int)> { return [](int i) { return i + 1; }; });
m.def("test_callback5",
[]() { return py::cpp_function([](int i) { return i + 1; }, py::arg("number")); });
// test_keyword_args_and_generalized_unpacking // test_keyword_args_and_generalized_unpacking
m.def("test_tuple_unpacking", [](const py::function &f) { m.def("test_tuple_unpacking", [](const py::function &f) {
...@@ -34,9 +36,9 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -34,9 +36,9 @@ TEST_SUBMODULE(callbacks, m) {
}); });
m.def("test_dict_unpacking", [](const py::function &f) { m.def("test_dict_unpacking", [](const py::function &f) {
auto d1 = py::dict("key"_a="value", "a"_a=1); auto d1 = py::dict("key"_a = "value", "a"_a = 1);
auto d2 = py::dict(); auto d2 = py::dict();
auto d3 = py::dict("b"_a=2); auto d3 = py::dict("b"_a = 2);
return f("positional", 1, **d1, **d2, **d3); return f("positional", 1, **d1, **d2, **d3);
}); });
...@@ -44,32 +46,40 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -44,32 +46,40 @@ TEST_SUBMODULE(callbacks, m) {
m.def("test_unpacking_and_keywords1", [](const py::function &f) { m.def("test_unpacking_and_keywords1", [](const py::function &f) {
auto args = py::make_tuple(2); auto args = py::make_tuple(2);
auto kwargs = py::dict("d"_a=4); auto kwargs = py::dict("d"_a = 4);
return f(1, *args, "c"_a=3, **kwargs); return f(1, *args, "c"_a = 3, **kwargs);
}); });
m.def("test_unpacking_and_keywords2", [](const py::function &f) { m.def("test_unpacking_and_keywords2", [](const py::function &f) {
auto kwargs1 = py::dict("a"_a=1); auto kwargs1 = py::dict("a"_a = 1);
auto kwargs2 = py::dict("c"_a=3, "d"_a=4); auto kwargs2 = py::dict("c"_a = 3, "d"_a = 4);
return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5, return f("positional",
"key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5); *py::make_tuple(1),
2,
*py::make_tuple(3, 4),
5,
"key"_a = "value",
**kwargs1,
"b"_a = 2,
**kwargs2,
"e"_a = 5);
}); });
m.def("test_unpacking_error1", [](const py::function &f) { m.def("test_unpacking_error1", [](const py::function &f) {
auto kwargs = py::dict("x"_a=3); auto kwargs = py::dict("x"_a = 3);
return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword return f("x"_a = 1, "y"_a = 2, **kwargs); // duplicate ** after keyword
}); });
m.def("test_unpacking_error2", [](const py::function &f) { m.def("test_unpacking_error2", [](const py::function &f) {
auto kwargs = py::dict("x"_a=3); auto kwargs = py::dict("x"_a = 3);
return f(**kwargs, "x"_a=1); // duplicate keyword after ** return f(**kwargs, "x"_a = 1); // duplicate keyword after **
}); });
m.def("test_arg_conversion_error1", m.def("test_arg_conversion_error1",
[](const py::function &f) { f(234, UnregisteredType(), "kw"_a = 567); }); [](const py::function &f) { f(234, UnregisteredType(), "kw"_a = 567); });
m.def("test_arg_conversion_error2", [](const py::function &f) { m.def("test_arg_conversion_error2", [](const py::function &f) {
f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567); f(234, "expected_name"_a = UnregisteredType(), "kw"_a = 567);
}); });
// test_lambda_closure_cleanup // test_lambda_closure_cleanup
...@@ -158,7 +168,6 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -158,7 +168,6 @@ TEST_SUBMODULE(callbacks, m) {
return "matches dummy_function: eval(1) = " + std::to_string(r); return "matches dummy_function: eval(1) = " + std::to_string(r);
} }
return "argument does NOT match dummy_function. This should never happen!"; return "argument does NOT match dummy_function. This should never happen!";
}); });
class AbstractBase { class AbstractBase {
...@@ -190,7 +199,7 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -190,7 +199,7 @@ TEST_SUBMODULE(callbacks, m) {
// test_movable_object // test_movable_object
m.def("callback_with_movable", [](const std::function<void(MovableObject &)> &f) { m.def("callback_with_movable", [](const std::function<void(MovableObject &)> &f) {
auto x = MovableObject(); auto x = MovableObject();
f(x); // lvalue reference shouldn't move out object f(x); // lvalue reference shouldn't move out object
return x.valid; // must still return `true` return x.valid; // must still return `true`
}); });
...@@ -202,9 +211,10 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -202,9 +211,10 @@ TEST_SUBMODULE(callbacks, m) {
// This checks that builtin functions can be passed as callbacks // This checks that builtin functions can be passed as callbacks
// rather than throwing RuntimeError due to trying to extract as capsule // rather than throwing RuntimeError due to trying to extract as capsule
m.def("test_sum_builtin", [](const std::function<double(py::iterable)> &sum_builtin, const py::iterable &i) { m.def("test_sum_builtin",
return sum_builtin(i); [](const std::function<double(py::iterable)> &sum_builtin, const py::iterable &i) {
}); return sum_builtin(i);
});
// test async Python callbacks // test async Python callbacks
using callback_f = std::function<void(int)>; using callback_f = std::function<void(int)>;
......
...@@ -8,21 +8,20 @@ ...@@ -8,21 +8,20 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include <pybind11/chrono.h> #include <pybind11/chrono.h>
#include "pybind11_tests.h"
#include <chrono> #include <chrono>
struct different_resolutions { struct different_resolutions {
using time_point_h = std::chrono::time_point< using time_point_h = std::chrono::time_point<std::chrono::system_clock, std::chrono::hours>;
std::chrono::system_clock, std::chrono::hours>; using time_point_m = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
using time_point_m = std::chrono::time_point< using time_point_s = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
std::chrono::system_clock, std::chrono::minutes>; using time_point_ms
using time_point_s = std::chrono::time_point< = std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>;
std::chrono::system_clock, std::chrono::seconds>; using time_point_us
using time_point_ms = std::chrono::time_point< = std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>;
std::chrono::system_clock, std::chrono::milliseconds>;
using time_point_us = std::chrono::time_point<
std::chrono::system_clock, std::chrono::microseconds>;
time_point_h timestamp_h; time_point_h timestamp_h;
time_point_m timestamp_m; time_point_m timestamp_m;
time_point_s timestamp_s; time_point_s timestamp_s;
...@@ -65,12 +64,11 @@ TEST_SUBMODULE(chrono, m) { ...@@ -65,12 +64,11 @@ TEST_SUBMODULE(chrono, m) {
// Roundtrip a duration in microseconds from a float argument // Roundtrip a duration in microseconds from a float argument
m.def("test_chrono7", [](std::chrono::microseconds t) { return t; }); m.def("test_chrono7", [](std::chrono::microseconds t) { return t; });
// Float durations (issue #719) // Float durations (issue #719)
m.def("test_chrono_float_diff", [](std::chrono::duration<float> a, std::chrono::duration<float> b) { m.def("test_chrono_float_diff",
return a - b; }); [](std::chrono::duration<float> a, std::chrono::duration<float> b) { return a - b; });
m.def("test_nano_timepoint", [](timestamp start, timespan delta) -> timestamp { m.def("test_nano_timepoint",
return start + delta; [](timestamp start, timespan delta) -> timestamp { return start + delta; });
});
// Test different resolutions // Test different resolutions
py::class_<different_resolutions>(m, "different_resolutions") py::class_<different_resolutions>(m, "different_resolutions")
...@@ -79,6 +77,5 @@ TEST_SUBMODULE(chrono, m) { ...@@ -79,6 +77,5 @@ TEST_SUBMODULE(chrono, m) {
.def_readwrite("timestamp_m", &different_resolutions::timestamp_m) .def_readwrite("timestamp_m", &different_resolutions::timestamp_m)
.def_readwrite("timestamp_s", &different_resolutions::timestamp_s) .def_readwrite("timestamp_s", &different_resolutions::timestamp_s)
.def_readwrite("timestamp_ms", &different_resolutions::timestamp_ms) .def_readwrite("timestamp_ms", &different_resolutions::timestamp_ms)
.def_readwrite("timestamp_us", &different_resolutions::timestamp_us) .def_readwrite("timestamp_us", &different_resolutions::timestamp_us);
;
} }
...@@ -12,20 +12,14 @@ ...@@ -12,20 +12,14 @@
enum MyEnum { EFirstEntry = 1, ESecondEntry }; enum MyEnum { EFirstEntry = 1, ESecondEntry };
std::string test_function1() { std::string test_function1() { return "test_function()"; }
return "test_function()";
}
std::string test_function2(MyEnum k) { std::string test_function2(MyEnum k) { return "test_function(enum=" + std::to_string(k) + ")"; }
return "test_function(enum=" + std::to_string(k) + ")";
}
std::string test_function3(int i) { std::string test_function3(int i) { return "test_function(" + std::to_string(i) + ")"; }
return "test_function(" + std::to_string(i) + ")";
}
py::str test_function4() { return "test_function()"; } py::str test_function4() { return "test_function()"; }
py::str test_function4(char *) { return "test_function(char *)"; } py::str test_function4(char *) { return "test_function(char *)"; }
py::str test_function4(int, float) { return "test_function(int, float)"; } py::str test_function4(int, float) { return "test_function(int, float)"; }
py::str test_function4(float, int) { return "test_function(float, int)"; } py::str test_function4(float, int) { return "test_function(float, int)"; }
...@@ -44,50 +38,50 @@ std::string print_bytes(const py::bytes &bytes) { ...@@ -44,50 +38,50 @@ std::string print_bytes(const py::bytes &bytes) {
return ret; return ret;
} }
// Test that we properly handle C++17 exception specifiers (which are part of the function signature // Test that we properly handle C++17 exception specifiers (which are part of the function
// in C++17). These should all still work before C++17, but don't affect the function signature. // signature in C++17). These should all still work before C++17, but don't affect the function
// signature.
namespace test_exc_sp { namespace test_exc_sp {
// [workaround(intel)] Unable to use noexcept instead of noexcept(true) // [workaround(intel)] Unable to use noexcept instead of noexcept(true)
// Make the f1 test basically the same as the f2 test in C++17 mode for the Intel compiler as // Make the f1 test basically the same as the f2 test in C++17 mode for the Intel compiler as
// it fails to compile with a plain noexcept (tested with icc (ICC) 2021.1 Beta 20200827). // it fails to compile with a plain noexcept (tested with icc (ICC) 2021.1 Beta 20200827).
#if defined(__INTEL_COMPILER) && defined(PYBIND11_CPP17) #if defined(__INTEL_COMPILER) && defined(PYBIND11_CPP17)
int f1(int x) noexcept(true) { return x+1; } int f1(int x) noexcept(true) { return x + 1; }
#else #else
int f1(int x) noexcept { return x+1; } int f1(int x) noexcept { return x + 1; }
#endif #endif
int f2(int x) noexcept(true) { return x+2; } int f2(int x) noexcept(true) { return x + 2; }
int f3(int x) noexcept(false) { return x+3; } int f3(int x) noexcept(false) { return x + 3; }
#if defined(__GNUG__) && !defined(__INTEL_COMPILER) #if defined(__GNUG__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated" # pragma GCC diagnostic ignored "-Wdeprecated"
#endif #endif
// NOLINTNEXTLINE(modernize-use-noexcept) // NOLINTNEXTLINE(modernize-use-noexcept)
int f4(int x) throw() { return x+4; } // Deprecated equivalent to noexcept(true) int f4(int x) throw() { return x + 4; } // Deprecated equivalent to noexcept(true)
#if defined(__GNUG__) && !defined(__INTEL_COMPILER) #if defined(__GNUG__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
struct C { struct C {
int m1(int x) noexcept { return x-1; } int m1(int x) noexcept { return x - 1; }
int m2(int x) const noexcept { return x-2; } int m2(int x) const noexcept { return x - 2; }
int m3(int x) noexcept(true) { return x-3; } int m3(int x) noexcept(true) { return x - 3; }
int m4(int x) const noexcept(true) { return x-4; } int m4(int x) const noexcept(true) { return x - 4; }
int m5(int x) noexcept(false) { return x-5; } int m5(int x) noexcept(false) { return x - 5; }
int m6(int x) const noexcept(false) { return x-6; } int m6(int x) const noexcept(false) { return x - 6; }
#if defined(__GNUG__) && !defined(__INTEL_COMPILER) #if defined(__GNUG__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated" # pragma GCC diagnostic ignored "-Wdeprecated"
#endif #endif
// NOLINTNEXTLINE(modernize-use-noexcept) // NOLINTNEXTLINE(modernize-use-noexcept)
int m7(int x) throw() { return x - 7; } int m7(int x) throw() { return x - 7; }
// NOLINTNEXTLINE(modernize-use-noexcept) // NOLINTNEXTLINE(modernize-use-noexcept)
int m8(int x) const throw() { return x - 8; } int m8(int x) const throw() { return x - 8; }
#if defined(__GNUG__) && !defined(__INTEL_COMPILER) #if defined(__GNUG__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
}; };
} // namespace test_exc_sp } // namespace test_exc_sp
TEST_SUBMODULE(constants_and_functions, m) { TEST_SUBMODULE(constants_and_functions, m) {
// test_constants // test_constants
m.attr("some_constant") = py::int_(14); m.attr("some_constant") = py::int_(14);
...@@ -129,8 +123,7 @@ TEST_SUBMODULE(constants_and_functions, m) { ...@@ -129,8 +123,7 @@ TEST_SUBMODULE(constants_and_functions, m) {
.def("m5", &C::m5) .def("m5", &C::m5)
.def("m6", &C::m6) .def("m6", &C::m6)
.def("m7", &C::m7) .def("m7", &C::m7)
.def("m8", &C::m8) .def("m8", &C::m8);
;
m.def("f1", f1); m.def("f1", f1);
m.def("f2", f2); m.def("f2", f2);
#if defined(__INTEL_COMPILER) #if defined(__INTEL_COMPILER)
...@@ -150,8 +143,12 @@ TEST_SUBMODULE(constants_and_functions, m) { ...@@ -150,8 +143,12 @@ TEST_SUBMODULE(constants_and_functions, m) {
uint64_t zeros[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; uint64_t zeros[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
}; };
m.def("register_large_capture_with_invalid_arguments", [](py::module_ m) { m.def("register_large_capture_with_invalid_arguments", [](py::module_ m) {
LargeCapture capture; // VS 2015's MSVC is acting up if we create the array here LargeCapture capture; // VS 2015's MSVC is acting up if we create the array here
m.def("should_raise", [capture](int) { return capture.zeros[9] + 33; }, py::kw_only(), py::arg()); m.def(
"should_raise",
[capture](int) { return capture.zeros[9] + 33; },
py::kw_only(),
py::arg());
}); });
m.def("register_with_raising_repr", [](py::module_ m, const py::object &default_value) { m.def("register_with_raising_repr", [](py::module_ m, const py::object &default_value) {
m.def( m.def(
......
...@@ -7,16 +7,23 @@ ...@@ -7,16 +7,23 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include "constructor_stats.h" #include "constructor_stats.h"
#include "pybind11_tests.h"
// py::arg/py::arg_v testing: these arguments just record their argument when invoked // py::arg/py::arg_v testing: these arguments just record their argument when invoked
class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; }; class ArgInspector1 {
class ArgInspector2 { public: std::string arg = "(default arg inspector 2)"; }; public:
class ArgAlwaysConverts { }; std::string arg = "(default arg inspector 1)";
namespace pybind11 { namespace detail { };
template <> struct type_caster<ArgInspector1> { class ArgInspector2 {
public:
std::string arg = "(default arg inspector 2)";
};
class ArgAlwaysConverts {};
namespace pybind11 {
namespace detail {
template <>
struct type_caster<ArgInspector1> {
public: public:
// Classic // Classic
#ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY #ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
...@@ -26,9 +33,10 @@ public: ...@@ -26,9 +33,10 @@ public:
#endif #endif
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
value.arg = "loading ArgInspector1 argument " + value.arg = "loading ArgInspector1 argument " + std::string(convert ? "WITH" : "WITHOUT")
std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. " + " conversion allowed. "
"Argument value = " + (std::string) str(src); "Argument value = "
+ (std::string) str(src);
return true; return true;
} }
...@@ -36,14 +44,16 @@ public: ...@@ -36,14 +44,16 @@ public:
return str(src.arg).release(); return str(src.arg).release();
} }
}; };
template <> struct type_caster<ArgInspector2> { template <>
struct type_caster<ArgInspector2> {
public: public:
PYBIND11_TYPE_CASTER(ArgInspector2, const_name("ArgInspector2")); PYBIND11_TYPE_CASTER(ArgInspector2, const_name("ArgInspector2"));
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
value.arg = "loading ArgInspector2 argument " + value.arg = "loading ArgInspector2 argument " + std::string(convert ? "WITH" : "WITHOUT")
std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. " + " conversion allowed. "
"Argument value = " + (std::string) str(src); "Argument value = "
+ (std::string) str(src);
return true; return true;
} }
...@@ -51,13 +61,12 @@ public: ...@@ -51,13 +61,12 @@ public:
return str(src.arg).release(); return str(src.arg).release();
} }
}; };
template <> struct type_caster<ArgAlwaysConverts> { template <>
struct type_caster<ArgAlwaysConverts> {
public: public:
PYBIND11_TYPE_CASTER(ArgAlwaysConverts, const_name("ArgAlwaysConverts")); PYBIND11_TYPE_CASTER(ArgAlwaysConverts, const_name("ArgAlwaysConverts"));
bool load(handle, bool convert) { bool load(handle, bool convert) { return convert; }
return convert;
}
static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) { static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) {
return py::none().release(); return py::none().release();
...@@ -73,14 +82,19 @@ public: ...@@ -73,14 +82,19 @@ public:
~DestructionTester() { print_destroyed(this); } ~DestructionTester() { print_destroyed(this); }
DestructionTester(const DestructionTester &) { print_copy_created(this); } DestructionTester(const DestructionTester &) { print_copy_created(this); }
DestructionTester(DestructionTester &&) noexcept { print_move_created(this); } DestructionTester(DestructionTester &&) noexcept { print_move_created(this); }
DestructionTester &operator=(const DestructionTester &) { print_copy_assigned(this); return *this; } DestructionTester &operator=(const DestructionTester &) {
print_copy_assigned(this);
return *this;
}
DestructionTester &operator=(DestructionTester &&) noexcept { DestructionTester &operator=(DestructionTester &&) noexcept {
print_move_assigned(this); print_move_assigned(this);
return *this; return *this;
} }
}; };
namespace pybind11 { namespace detail { namespace pybind11 {
template <> struct type_caster<DestructionTester> { namespace detail {
template <>
struct type_caster<DestructionTester> {
PYBIND11_TYPE_CASTER(DestructionTester, const_name("DestructionTester")); PYBIND11_TYPE_CASTER(DestructionTester, const_name("DestructionTester"));
bool load(handle, bool) { return true; } bool load(handle, bool) { return true; }
...@@ -115,9 +129,14 @@ TEST_SUBMODULE(custom_type_casters, m) { ...@@ -115,9 +129,14 @@ TEST_SUBMODULE(custom_type_casters, m) {
py::class_<ArgInspector>(m, "ArgInspector") py::class_<ArgInspector>(m, "ArgInspector")
.def(py::init<>()) .def(py::init<>())
.def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts()) .def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts())
.def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert()=13, "d"_a=ArgInspector2(), py::arg() = ArgAlwaysConverts()) .def("g",
.def_static("h", &ArgInspector::h, py::arg{}.noconvert(), py::arg() = ArgAlwaysConverts()) &ArgInspector::g,
; "a"_a.noconvert(),
"b"_a,
"c"_a.noconvert() = 13,
"d"_a = ArgInspector2(),
py::arg() = ArgAlwaysConverts())
.def_static("h", &ArgInspector::h, py::arg{}.noconvert(), py::arg() = ArgAlwaysConverts());
m.def( m.def(
"arg_inspect_func", "arg_inspect_func",
[](const ArgInspector2 &a, const ArgInspector1 &b, ArgAlwaysConverts) { [](const ArgInspector2 &a, const ArgInspector1 &b, ArgAlwaysConverts) {
...@@ -127,20 +146,33 @@ TEST_SUBMODULE(custom_type_casters, m) { ...@@ -127,20 +146,33 @@ TEST_SUBMODULE(custom_type_casters, m) {
py::arg_v(nullptr, ArgInspector1()).noconvert(true), py::arg_v(nullptr, ArgInspector1()).noconvert(true),
py::arg() = ArgAlwaysConverts()); py::arg() = ArgAlwaysConverts());
m.def("floats_preferred", [](double f) { return 0.5 * f; }, "f"_a); m.def(
m.def("floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert()); "floats_preferred", [](double f) { return 0.5 * f; }, "f"_a);
m.def("ints_preferred", [](int i) { return i / 2; }, "i"_a); m.def(
m.def("ints_only", [](int i) { return i / 2; }, "i"_a.noconvert()); "floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert());
m.def(
"ints_preferred", [](int i) { return i / 2; }, "i"_a);
m.def(
"ints_only", [](int i) { return i / 2; }, "i"_a.noconvert());
// test_custom_caster_destruction // test_custom_caster_destruction
// Test that `take_ownership` works on types with a custom type caster when given a pointer // Test that `take_ownership` works on types with a custom type caster when given a pointer
// default policy: don't take ownership: // default policy: don't take ownership:
m.def("custom_caster_no_destroy", []() { static auto *dt = new DestructionTester(); return dt; }); m.def("custom_caster_no_destroy", []() {
static auto *dt = new DestructionTester();
return dt;
});
m.def("custom_caster_destroy", []() { return new DestructionTester(); }, m.def(
py::return_value_policy::take_ownership); // Takes ownership: destroy when finished "custom_caster_destroy",
m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); }, []() { return new DestructionTester(); },
py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction) py::return_value_policy::take_ownership); // Takes ownership: destroy when finished
m.def("destruction_tester_cstats", &ConstructorStats::get<DestructionTester>, py::return_value_policy::reference); m.def(
"custom_caster_destroy_const",
[]() -> const DestructionTester * { return new DestructionTester(); },
py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction)
m.def("destruction_tester_cstats",
&ConstructorStats::get<DestructionTester>,
py::return_value_policy::reference);
} }
...@@ -15,35 +15,52 @@ TEST_SUBMODULE(docstring_options, m) { ...@@ -15,35 +15,52 @@ TEST_SUBMODULE(docstring_options, m) {
py::options options; py::options options;
options.disable_function_signatures(); options.disable_function_signatures();
m.def("test_function1", [](int, int) {}, py::arg("a"), py::arg("b")); m.def(
m.def("test_function2", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); "test_function1", [](int, int) {}, py::arg("a"), py::arg("b"));
m.def(
m.def("test_overloaded1", [](int) {}, py::arg("i"), "Overload docstring"); "test_function2", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
m.def("test_overloaded1", [](double) {}, py::arg("d"));
m.def(
m.def("test_overloaded2", [](int) {}, py::arg("i"), "overload docstring 1"); "test_overloaded1", [](int) {}, py::arg("i"), "Overload docstring");
m.def("test_overloaded2", [](double) {}, py::arg("d"), "overload docstring 2"); m.def(
"test_overloaded1", [](double) {}, py::arg("d"));
m.def("test_overloaded3", [](int) {}, py::arg("i"));
m.def("test_overloaded3", [](double) {}, py::arg("d"), "Overload docstr"); m.def(
"test_overloaded2", [](int) {}, py::arg("i"), "overload docstring 1");
m.def(
"test_overloaded2", [](double) {}, py::arg("d"), "overload docstring 2");
m.def(
"test_overloaded3", [](int) {}, py::arg("i"));
m.def(
"test_overloaded3", [](double) {}, py::arg("d"), "Overload docstr");
options.enable_function_signatures(); options.enable_function_signatures();
m.def("test_function3", [](int, int) {}, py::arg("a"), py::arg("b")); m.def(
m.def("test_function4", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); "test_function3", [](int, int) {}, py::arg("a"), py::arg("b"));
m.def(
"test_function4", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
options.disable_function_signatures().disable_user_defined_docstrings(); options.disable_function_signatures().disable_user_defined_docstrings();
m.def("test_function5", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); m.def(
"test_function5", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
{ {
py::options nested_options; py::options nested_options;
nested_options.enable_user_defined_docstrings(); nested_options.enable_user_defined_docstrings();
m.def("test_function6", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); m.def(
"test_function6",
[](int, int) {},
py::arg("a"),
py::arg("b"),
"A custom docstring");
} }
} }
m.def("test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); m.def(
"test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
{ {
py::options options; py::options options;
...@@ -63,7 +80,9 @@ TEST_SUBMODULE(docstring_options, m) { ...@@ -63,7 +80,9 @@ TEST_SUBMODULE(docstring_options, m) {
int getValue() const { return value; } int getValue() const { return value; }
}; };
py::class_<DocstringTestFoo>(m, "DocstringTestFoo", "This is a class docstring") py::class_<DocstringTestFoo>(m, "DocstringTestFoo", "This is a class docstring")
.def_property("value_prop", &DocstringTestFoo::getValue, &DocstringTestFoo::setValue, "This is a property docstring") .def_property("value_prop",
; &DocstringTestFoo::getValue,
&DocstringTestFoo::setValue,
"This is a property docstring");
} }
} }
...@@ -4,14 +4,14 @@ ...@@ -4,14 +4,14 @@
#include <pybind11/embed.h> #include <pybind11/embed.h>
#ifdef _MSC_VER #ifdef _MSC_VER
// Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to catch // Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to
// 2.0.1; this should be fixed in the next catch release after 2.0.1). // catch 2.0.1; this should be fixed in the next catch release after 2.0.1).
# pragma warning(disable: 4996) # pragma warning(disable : 4996)
#endif #endif
// Catch uses _ internally, which breaks gettext style defines // Catch uses _ internally, which breaks gettext style defines
#ifdef _ #ifdef _
#undef _ # undef _
#endif #endif
#define CATCH_CONFIG_RUNNER #define CATCH_CONFIG_RUNNER
......
...@@ -13,11 +13,8 @@ PYBIND11_MODULE(external_module, m) { ...@@ -13,11 +13,8 @@ PYBIND11_MODULE(external_module, m) {
int v; int v;
}; };
py::class_<A>(m, "A") py::class_<A>(m, "A").def(py::init<int>()).def_readwrite("value", &A::v);
.def(py::init<int>())
.def_readwrite("value", &A::v);
m.def("internals_at", []() { m.def("internals_at",
return reinterpret_cast<uintptr_t>(&py::detail::get_internals()); []() { return reinterpret_cast<uintptr_t>(&py::detail::get_internals()); });
});
} }
#include <pybind11/embed.h> #include <pybind11/embed.h>
#ifdef _MSC_VER #ifdef _MSC_VER
// Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to catch // Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to
// 2.0.1; this should be fixed in the next catch release after 2.0.1). // catch 2.0.1; this should be fixed in the next catch release after 2.0.1).
# pragma warning(disable: 4996) # pragma warning(disable : 4996)
#endif #endif
#include <catch.hpp> #include <catch.hpp>
#include <cstdlib> #include <cstdlib>
#include <fstream> #include <fstream>
#include <functional> #include <functional>
...@@ -62,14 +61,14 @@ PYBIND11_EMBEDDED_MODULE(widget_module, m) { ...@@ -62,14 +61,14 @@ PYBIND11_EMBEDDED_MODULE(widget_module, m) {
} }
PYBIND11_EMBEDDED_MODULE(trampoline_module, m) { PYBIND11_EMBEDDED_MODULE(trampoline_module, m) {
py::class_<test_override_cache_helper, test_override_cache_helper_trampoline, std::shared_ptr<test_override_cache_helper>>(m, "test_override_cache_helper") py::class_<test_override_cache_helper,
test_override_cache_helper_trampoline,
std::shared_ptr<test_override_cache_helper>>(m, "test_override_cache_helper")
.def(py::init_alias<>()) .def(py::init_alias<>())
.def("func", &test_override_cache_helper::func); .def("func", &test_override_cache_helper::func);
} }
PYBIND11_EMBEDDED_MODULE(throw_exception, ) { PYBIND11_EMBEDDED_MODULE(throw_exception, ) { throw std::runtime_error("C++ Error"); }
throw std::runtime_error("C++ Error");
}
PYBIND11_EMBEDDED_MODULE(throw_error_already_set, ) { PYBIND11_EMBEDDED_MODULE(throw_error_already_set, ) {
auto d = py::dict(); auto d = py::dict();
...@@ -80,11 +79,13 @@ TEST_CASE("Pass classes and data between modules defined in C++ and Python") { ...@@ -80,11 +79,13 @@ TEST_CASE("Pass classes and data between modules defined in C++ and Python") {
auto module_ = py::module_::import("test_interpreter"); auto module_ = py::module_::import("test_interpreter");
REQUIRE(py::hasattr(module_, "DerivedWidget")); REQUIRE(py::hasattr(module_, "DerivedWidget"));
auto locals = py::dict("hello"_a="Hello, World!", "x"_a=5, **module_.attr("__dict__")); auto locals = py::dict("hello"_a = "Hello, World!", "x"_a = 5, **module_.attr("__dict__"));
py::exec(R"( py::exec(R"(
widget = DerivedWidget("{} - {}".format(hello, x)) widget = DerivedWidget("{} - {}".format(hello, x))
message = widget.the_message message = widget.the_message
)", py::globals(), locals); )",
py::globals(),
locals);
REQUIRE(locals["message"].cast<std::string>() == "Hello, World! - 5"); REQUIRE(locals["message"].cast<std::string>() == "Hello, World! - 5");
auto py_widget = module_.attr("DerivedWidget")("The question"); auto py_widget = module_.attr("DerivedWidget")("The question");
...@@ -124,20 +125,21 @@ TEST_CASE("Override cache") { ...@@ -124,20 +125,21 @@ TEST_CASE("Override cache") {
TEST_CASE("Import error handling") { TEST_CASE("Import error handling") {
REQUIRE_NOTHROW(py::module_::import("widget_module")); REQUIRE_NOTHROW(py::module_::import("widget_module"));
REQUIRE_THROWS_WITH(py::module_::import("throw_exception"), REQUIRE_THROWS_WITH(py::module_::import("throw_exception"), "ImportError: C++ Error");
"ImportError: C++ Error");
#if PY_VERSION_HEX >= 0x03030000 #if PY_VERSION_HEX >= 0x03030000
REQUIRE_THROWS_WITH(py::module_::import("throw_error_already_set"), REQUIRE_THROWS_WITH(py::module_::import("throw_error_already_set"),
Catch::Contains("ImportError: initialization failed")); Catch::Contains("ImportError: initialization failed"));
auto locals = py::dict("is_keyerror"_a=false, "message"_a="not set"); auto locals = py::dict("is_keyerror"_a = false, "message"_a = "not set");
py::exec(R"( py::exec(R"(
try: try:
import throw_error_already_set import throw_error_already_set
except ImportError as e: except ImportError as e:
is_keyerror = type(e.__cause__) == KeyError is_keyerror = type(e.__cause__) == KeyError
message = str(e.__cause__) message = str(e.__cause__)
)", py::globals(), locals); )",
py::globals(),
locals);
REQUIRE(locals["is_keyerror"].cast<bool>() == true); REQUIRE(locals["is_keyerror"].cast<bool>() == true);
REQUIRE(locals["message"].cast<std::string>() == "'missing'"); REQUIRE(locals["message"].cast<std::string>() == "'missing'");
#else #else
...@@ -179,11 +181,12 @@ TEST_CASE("Restart the interpreter") { ...@@ -179,11 +181,12 @@ TEST_CASE("Restart the interpreter") {
REQUIRE(py::module_::import("widget_module").attr("add")(1, 2).cast<int>() == 3); REQUIRE(py::module_::import("widget_module").attr("add")(1, 2).cast<int>() == 3);
REQUIRE(has_pybind11_internals_builtin()); REQUIRE(has_pybind11_internals_builtin());
REQUIRE(has_pybind11_internals_static()); REQUIRE(has_pybind11_internals_static());
REQUIRE(py::module_::import("external_module").attr("A")(123).attr("value").cast<int>() == 123); REQUIRE(py::module_::import("external_module").attr("A")(123).attr("value").cast<int>()
== 123);
// local and foreign module internals should point to the same internals: // local and foreign module internals should point to the same internals:
REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp()) == REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp())
py::module_::import("external_module").attr("internals_at")().cast<uintptr_t>()); == py::module_::import("external_module").attr("internals_at")().cast<uintptr_t>());
// Restart the interpreter. // Restart the interpreter.
py::finalize_interpreter(); py::finalize_interpreter();
...@@ -198,16 +201,19 @@ TEST_CASE("Restart the interpreter") { ...@@ -198,16 +201,19 @@ TEST_CASE("Restart the interpreter") {
pybind11::detail::get_internals(); pybind11::detail::get_internals();
REQUIRE(has_pybind11_internals_builtin()); REQUIRE(has_pybind11_internals_builtin());
REQUIRE(has_pybind11_internals_static()); REQUIRE(has_pybind11_internals_static());
REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp()) == REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp())
py::module_::import("external_module").attr("internals_at")().cast<uintptr_t>()); == py::module_::import("external_module").attr("internals_at")().cast<uintptr_t>());
// Make sure that an interpreter with no get_internals() created until finalize still gets the // Make sure that an interpreter with no get_internals() created until finalize still gets the
// internals destroyed // internals destroyed
py::finalize_interpreter(); py::finalize_interpreter();
py::initialize_interpreter(); py::initialize_interpreter();
bool ran = false; bool ran = false;
py::module_::import("__main__").attr("internals_destroy_test") = py::module_::import("__main__").attr("internals_destroy_test")
py::capsule(&ran, [](void *ran) { py::detail::get_internals(); *static_cast<bool *>(ran) = true; }); = py::capsule(&ran, [](void *ran) {
py::detail::get_internals();
*static_cast<bool *>(ran) = true;
});
REQUIRE_FALSE(has_pybind11_internals_builtin()); REQUIRE_FALSE(has_pybind11_internals_builtin());
REQUIRE_FALSE(has_pybind11_internals_static()); REQUIRE_FALSE(has_pybind11_internals_static());
REQUIRE_FALSE(ran); REQUIRE_FALSE(ran);
...@@ -281,7 +287,7 @@ TEST_CASE("Threads") { ...@@ -281,7 +287,7 @@ TEST_CASE("Threads") {
REQUIRE_FALSE(has_pybind11_internals_static()); REQUIRE_FALSE(has_pybind11_internals_static());
constexpr auto num_threads = 10; constexpr auto num_threads = 10;
auto locals = py::dict("count"_a=0); auto locals = py::dict("count"_a = 0);
{ {
py::gil_scoped_release gil_release{}; py::gil_scoped_release gil_release{};
...@@ -322,9 +328,8 @@ TEST_CASE("Reload module from file") { ...@@ -322,9 +328,8 @@ TEST_CASE("Reload module from file") {
bool dont_write_bytecode = sys.attr("dont_write_bytecode").cast<bool>(); bool dont_write_bytecode = sys.attr("dont_write_bytecode").cast<bool>();
sys.attr("dont_write_bytecode") = true; sys.attr("dont_write_bytecode") = true;
// Reset the value at scope exit // Reset the value at scope exit
scope_exit reset_dont_write_bytecode([&]() { scope_exit reset_dont_write_bytecode(
sys.attr("dont_write_bytecode") = dont_write_bytecode; [&]() { sys.attr("dont_write_bytecode") = dont_write_bytecode; });
});
std::string module_name = "test_module_reload"; std::string module_name = "test_module_reload";
std::string module_file = module_name + ".py"; std::string module_file = module_name + ".py";
...@@ -335,9 +340,7 @@ TEST_CASE("Reload module from file") { ...@@ -335,9 +340,7 @@ TEST_CASE("Reload module from file") {
test_module << " return 1\n"; test_module << " return 1\n";
test_module.close(); test_module.close();
// Delete the file at scope exit // Delete the file at scope exit
scope_exit delete_module_file([&]() { scope_exit delete_module_file([&]() { std::remove(module_file.c_str()); });
std::remove(module_file.c_str());
});
// Import the module from file // Import the module from file
auto module_ = py::module_::import(module_name.c_str()); auto module_ = py::module_::import(module_name.c_str());
......
...@@ -11,11 +11,7 @@ ...@@ -11,11 +11,7 @@
TEST_SUBMODULE(enums, m) { TEST_SUBMODULE(enums, m) {
// test_unscoped_enum // test_unscoped_enum
enum UnscopedEnum { enum UnscopedEnum { EOne = 1, ETwo, EThree };
EOne = 1,
ETwo,
EThree
};
py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration") py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration")
.value("EOne", EOne, "Docstring for EOne") .value("EOne", EOne, "Docstring for EOne")
.value("ETwo", ETwo, "Docstring for ETwo") .value("ETwo", ETwo, "Docstring for ETwo")
...@@ -23,10 +19,7 @@ TEST_SUBMODULE(enums, m) { ...@@ -23,10 +19,7 @@ TEST_SUBMODULE(enums, m) {
.export_values(); .export_values();
// test_scoped_enum // test_scoped_enum
enum class ScopedEnum { enum class ScopedEnum { Two = 2, Three };
Two = 2,
Three
};
py::enum_<ScopedEnum>(m, "ScopedEnum", py::arithmetic()) py::enum_<ScopedEnum>(m, "ScopedEnum", py::arithmetic())
.value("Two", ScopedEnum::Two) .value("Two", ScopedEnum::Two)
.value("Three", ScopedEnum::Three); .value("Three", ScopedEnum::Three);
...@@ -36,11 +29,7 @@ TEST_SUBMODULE(enums, m) { ...@@ -36,11 +29,7 @@ TEST_SUBMODULE(enums, m) {
}); });
// test_binary_operators // test_binary_operators
enum Flags { enum Flags { Read = 4, Write = 2, Execute = 1 };
Read = 4,
Write = 2,
Execute = 1
};
py::enum_<Flags>(m, "Flags", py::arithmetic()) py::enum_<Flags>(m, "Flags", py::arithmetic())
.value("Read", Flags::Read) .value("Read", Flags::Read)
.value("Write", Flags::Write) .value("Write", Flags::Write)
...@@ -50,14 +39,9 @@ TEST_SUBMODULE(enums, m) { ...@@ -50,14 +39,9 @@ TEST_SUBMODULE(enums, m) {
// test_implicit_conversion // test_implicit_conversion
class ClassWithUnscopedEnum { class ClassWithUnscopedEnum {
public: public:
enum EMode { enum EMode { EFirstMode = 1, ESecondMode };
EFirstMode = 1,
ESecondMode static EMode test_function(EMode mode) { return mode; }
};
static EMode test_function(EMode mode) {
return mode;
}
}; };
py::class_<ClassWithUnscopedEnum> exenum_class(m, "ClassWithUnscopedEnum"); py::class_<ClassWithUnscopedEnum> exenum_class(m, "ClassWithUnscopedEnum");
exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function); exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function);
...@@ -67,19 +51,17 @@ TEST_SUBMODULE(enums, m) { ...@@ -67,19 +51,17 @@ TEST_SUBMODULE(enums, m) {
.export_values(); .export_values();
// test_enum_to_int // test_enum_to_int
m.def("test_enum_to_int", [](int) { }); m.def("test_enum_to_int", [](int) {});
m.def("test_enum_to_uint", [](uint32_t) { }); m.def("test_enum_to_uint", [](uint32_t) {});
m.def("test_enum_to_long_long", [](long long) { }); m.def("test_enum_to_long_long", [](long long) {});
// test_duplicate_enum_name // test_duplicate_enum_name
enum SimpleEnum enum SimpleEnum { ONE, TWO, THREE };
{
ONE, TWO, THREE
};
m.def("register_bad_enum", [m]() { m.def("register_bad_enum", [m]() {
py::enum_<SimpleEnum>(m, "SimpleEnum") py::enum_<SimpleEnum>(m, "SimpleEnum")
.value("ONE", SimpleEnum::ONE) //NOTE: all value function calls are called with the same first parameter value .value("ONE", SimpleEnum::ONE) // NOTE: all value function calls are called with the
// same first parameter value
.value("ONE", SimpleEnum::TWO) .value("ONE", SimpleEnum::TWO)
.value("ONE", SimpleEnum::THREE) .value("ONE", SimpleEnum::THREE)
.export_values(); .export_values();
...@@ -90,33 +72,36 @@ TEST_SUBMODULE(enums, m) { ...@@ -90,33 +72,36 @@ TEST_SUBMODULE(enums, m) {
enum class ScopedShortEnum : short {}; enum class ScopedShortEnum : short {};
enum class ScopedLongEnum : long {}; enum class ScopedLongEnum : long {};
enum UnscopedUInt64Enum : std::uint64_t {}; enum UnscopedUInt64Enum : std::uint64_t {};
static_assert(py::detail::all_of< static_assert(
std::is_same<py::enum_<UnscopedUCharEnum>::Scalar, unsigned char>, py::detail::all_of<
std::is_same<py::enum_<ScopedShortEnum>::Scalar, short>, std::is_same<py::enum_<UnscopedUCharEnum>::Scalar, unsigned char>,
std::is_same<py::enum_<ScopedLongEnum>::Scalar, long>, std::is_same<py::enum_<ScopedShortEnum>::Scalar, short>,
std::is_same<py::enum_<UnscopedUInt64Enum>::Scalar, std::uint64_t> std::is_same<py::enum_<ScopedLongEnum>::Scalar, long>,
>::value, "Error during the deduction of enum's scalar type with normal integer underlying"); std::is_same<py::enum_<UnscopedUInt64Enum>::Scalar, std::uint64_t>>::value,
"Error during the deduction of enum's scalar type with normal integer underlying");
// test_enum_scalar_with_char_underlying // test_enum_scalar_with_char_underlying
enum class ScopedCharEnum : char { Zero, Positive }; enum class ScopedCharEnum : char { Zero, Positive };
enum class ScopedWCharEnum : wchar_t { Zero, Positive }; enum class ScopedWCharEnum : wchar_t { Zero, Positive };
enum class ScopedChar32Enum : char32_t { Zero, Positive }; enum class ScopedChar32Enum : char32_t { Zero, Positive };
enum class ScopedChar16Enum : char16_t { Zero, Positive }; enum class ScopedChar16Enum : char16_t { Zero, Positive };
// test the scalar of char type enums according to chapter 'Character types' // test the scalar of char type enums according to chapter 'Character types'
// from https://en.cppreference.com/w/cpp/language/types // from https://en.cppreference.com/w/cpp/language/types
static_assert(py::detail::any_of<
std::is_same<py::enum_<ScopedCharEnum>::Scalar, signed char>, // e.g. gcc on x86
std::is_same<py::enum_<ScopedCharEnum>::Scalar, unsigned char> // e.g. arm linux
>::value, "char should be cast to either signed char or unsigned char");
static_assert( static_assert(
sizeof(py::enum_<ScopedWCharEnum>::Scalar) == 2 || py::detail::any_of<
sizeof(py::enum_<ScopedWCharEnum>::Scalar) == 4 std::is_same<py::enum_<ScopedCharEnum>::Scalar, signed char>, // e.g. gcc on x86
, "wchar_t should be either 16 bits (Windows) or 32 (everywhere else)"); std::is_same<py::enum_<ScopedCharEnum>::Scalar, unsigned char> // e.g. arm linux
static_assert(py::detail::all_of< >::value,
std::is_same<py::enum_<ScopedChar32Enum>::Scalar, std::uint_least32_t>, "char should be cast to either signed char or unsigned char");
std::is_same<py::enum_<ScopedChar16Enum>::Scalar, std::uint_least16_t> static_assert(sizeof(py::enum_<ScopedWCharEnum>::Scalar) == 2
>::value, "char32_t, char16_t (and char8_t)'s size, signedness, and alignment is determined"); || sizeof(py::enum_<ScopedWCharEnum>::Scalar) == 4,
"wchar_t should be either 16 bits (Windows) or 32 (everywhere else)");
static_assert(
py::detail::all_of<
std::is_same<py::enum_<ScopedChar32Enum>::Scalar, std::uint_least32_t>,
std::is_same<py::enum_<ScopedChar16Enum>::Scalar, std::uint_least16_t>>::value,
"char32_t, char16_t (and char8_t)'s size, signedness, and alignment is determined");
#if defined(PYBIND11_HAS_U8STRING) #if defined(PYBIND11_HAS_U8STRING)
enum class ScopedChar8Enum : char8_t { Zero, Positive }; enum class ScopedChar8Enum : char8_t { Zero, Positive };
static_assert(std::is_same<py::enum_<ScopedChar8Enum>::Scalar, unsigned char>::value); static_assert(std::is_same<py::enum_<ScopedChar8Enum>::Scalar, unsigned char>::value);
......
...@@ -7,10 +7,10 @@ ...@@ -7,10 +7,10 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include <pybind11/eval.h> #include <pybind11/eval.h>
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <utility> #include <utility>
TEST_SUBMODULE(eval_, m) { TEST_SUBMODULE(eval_, m) {
...@@ -20,16 +20,13 @@ TEST_SUBMODULE(eval_, m) { ...@@ -20,16 +20,13 @@ TEST_SUBMODULE(eval_, m) {
m.def("test_eval_statements", [global]() { m.def("test_eval_statements", [global]() {
auto local = py::dict(); auto local = py::dict();
local["call_test"] = py::cpp_function([&]() -> int { local["call_test"] = py::cpp_function([&]() -> int { return 42; });
return 42;
});
// Regular string literal // Regular string literal
py::exec( py::exec("message = 'Hello World!'\n"
"message = 'Hello World!'\n" "x = call_test()",
"x = call_test()", global,
global, local local);
);
// Multi-line raw string literal // Multi-line raw string literal
py::exec(R"( py::exec(R"(
...@@ -37,8 +34,9 @@ TEST_SUBMODULE(eval_, m) { ...@@ -37,8 +34,9 @@ TEST_SUBMODULE(eval_, m) {
print(message) print(message)
else: else:
raise RuntimeError raise RuntimeError
)", global, local )",
); global,
local);
auto x = local["x"].cast<int>(); auto x = local["x"].cast<int>();
return x == 42; return x == 42;
...@@ -53,9 +51,7 @@ TEST_SUBMODULE(eval_, m) { ...@@ -53,9 +51,7 @@ TEST_SUBMODULE(eval_, m) {
m.def("test_eval_single_statement", []() { m.def("test_eval_single_statement", []() {
auto local = py::dict(); auto local = py::dict();
local["call_test"] = py::cpp_function([&]() -> int { local["call_test"] = py::cpp_function([&]() -> int { return 42; });
return 42;
});
auto result = py::eval<py::eval_single_statement>("x = call_test()", py::dict(), local); auto result = py::eval<py::eval_single_statement>("x = call_test()", py::dict(), local);
auto x = local["x"].cast<int>(); auto x = local["x"].cast<int>();
...@@ -114,7 +110,9 @@ TEST_SUBMODULE(eval_, m) { ...@@ -114,7 +110,9 @@ TEST_SUBMODULE(eval_, m) {
def func_local(): def func_local():
return local_value return local_value
)", global, local); )",
global,
local);
return std::make_pair(global, local); return std::make_pair(global, local);
}); });
} }
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
#include "test_exceptions.h" #include "test_exceptions.h"
#include "local_bindings.h" #include "local_bindings.h"
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <exception> #include <exception>
#include <stdexcept> #include <stdexcept>
#include <utility> #include <utility>
...@@ -18,8 +18,9 @@ ...@@ -18,8 +18,9 @@
// A type that should be raised as an exception in Python // A type that should be raised as an exception in Python
class MyException : public std::exception { class MyException : public std::exception {
public: public:
explicit MyException(const char * m) : message{m} {} explicit MyException(const char *m) : message{m} {}
const char * what() const noexcept override {return message.c_str();} const char *what() const noexcept override { return message.c_str(); }
private: private:
std::string message = ""; std::string message = "";
}; };
...@@ -27,8 +28,9 @@ private: ...@@ -27,8 +28,9 @@ private:
// A type that should be translated to a standard Python exception // A type that should be translated to a standard Python exception
class MyException2 : public std::exception { class MyException2 : public std::exception {
public: public:
explicit MyException2(const char * m) : message{m} {} explicit MyException2(const char *m) : message{m} {}
const char * what() const noexcept override {return message.c_str();} const char *what() const noexcept override { return message.c_str(); }
private: private:
std::string message = ""; std::string message = "";
}; };
...@@ -36,13 +38,13 @@ private: ...@@ -36,13 +38,13 @@ private:
// A type that is not derived from std::exception (and is thus unknown) // A type that is not derived from std::exception (and is thus unknown)
class MyException3 { class MyException3 {
public: public:
explicit MyException3(const char * m) : message{m} {} explicit MyException3(const char *m) : message{m} {}
virtual const char * what() const noexcept {return message.c_str();} virtual const char *what() const noexcept { return message.c_str(); }
// Rule of 5 BEGIN: to preempt compiler warnings. // Rule of 5 BEGIN: to preempt compiler warnings.
MyException3(const MyException3&) = default; MyException3(const MyException3 &) = default;
MyException3(MyException3&&) = default; MyException3(MyException3 &&) = default;
MyException3& operator=(const MyException3&) = default; MyException3 &operator=(const MyException3 &) = default;
MyException3& operator=(MyException3&&) = default; MyException3 &operator=(MyException3 &&) = default;
virtual ~MyException3() = default; virtual ~MyException3() = default;
// Rule of 5 END. // Rule of 5 END.
private: private:
...@@ -53,13 +55,13 @@ private: ...@@ -53,13 +55,13 @@ private:
// and delegated to its exception translator // and delegated to its exception translator
class MyException4 : public std::exception { class MyException4 : public std::exception {
public: public:
explicit MyException4(const char * m) : message{m} {} explicit MyException4(const char *m) : message{m} {}
const char * what() const noexcept override {return message.c_str();} const char *what() const noexcept override { return message.c_str(); }
private: private:
std::string message = ""; std::string message = "";
}; };
// Like the above, but declared via the helper function // Like the above, but declared via the helper function
class MyException5 : public std::logic_error { class MyException5 : public std::logic_error {
public: public:
...@@ -71,17 +73,16 @@ class MyException5_1 : public MyException5 { ...@@ -71,17 +73,16 @@ class MyException5_1 : public MyException5 {
using MyException5::MyException5; using MyException5::MyException5;
}; };
// Exception that will be caught via the module local translator. // Exception that will be caught via the module local translator.
class MyException6 : public std::exception { class MyException6 : public std::exception {
public: public:
explicit MyException6(const char * m) : message{m} {} explicit MyException6(const char *m) : message{m} {}
const char * what() const noexcept override {return message.c_str();} const char *what() const noexcept override { return message.c_str(); }
private: private:
std::string message = ""; std::string message = "";
}; };
struct PythonCallInDestructor { struct PythonCallInDestructor {
explicit PythonCallInDestructor(const py::dict &d) : d(d) {} explicit PythonCallInDestructor(const py::dict &d) : d(d) {}
~PythonCallInDestructor() { d["good"] = true; } ~PythonCallInDestructor() { d["good"] = true; }
...@@ -89,8 +90,6 @@ struct PythonCallInDestructor { ...@@ -89,8 +90,6 @@ struct PythonCallInDestructor {
py::dict d; py::dict d;
}; };
struct PythonAlreadySetInDestructor { struct PythonAlreadySetInDestructor {
explicit PythonAlreadySetInDestructor(const py::str &s) : s(s) {} explicit PythonAlreadySetInDestructor(const py::str &s) : s(s) {}
~PythonAlreadySetInDestructor() { ~PythonAlreadySetInDestructor() {
...@@ -98,8 +97,7 @@ struct PythonAlreadySetInDestructor { ...@@ -98,8 +97,7 @@ struct PythonAlreadySetInDestructor {
try { try {
// Assign to a py::object to force read access of nonexistent dict entry // Assign to a py::object to force read access of nonexistent dict entry
py::object o = foo["bar"]; py::object o = foo["bar"];
} } catch (py::error_already_set &ex) {
catch (py::error_already_set& ex) {
ex.discard_as_unraisable(s); ex.discard_as_unraisable(s);
} }
} }
...@@ -108,9 +106,8 @@ struct PythonAlreadySetInDestructor { ...@@ -108,9 +106,8 @@ struct PythonAlreadySetInDestructor {
}; };
TEST_SUBMODULE(exceptions, m) { TEST_SUBMODULE(exceptions, m) {
m.def("throw_std_exception", []() { m.def("throw_std_exception",
throw std::runtime_error("This exception was intentionally thrown."); []() { throw std::runtime_error("This exception was intentionally thrown."); });
});
// make a new custom exception and use it as a translation target // make a new custom exception and use it as a translation target
static py::exception<MyException> ex(m, "MyException"); static py::exception<MyException> ex(m, "MyException");
...@@ -157,26 +154,30 @@ TEST_SUBMODULE(exceptions, m) { ...@@ -157,26 +154,30 @@ TEST_SUBMODULE(exceptions, m) {
// A slightly more complicated one that declares MyException5_1 as a subclass of MyException5 // A slightly more complicated one that declares MyException5_1 as a subclass of MyException5
py::register_exception<MyException5_1>(m, "MyException5_1", ex5.ptr()); py::register_exception<MyException5_1>(m, "MyException5_1", ex5.ptr());
//py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException") // py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException")
py::register_local_exception_translator([](std::exception_ptr p) { py::register_local_exception_translator([](std::exception_ptr p) {
try { try {
if (p) { if (p) {
std::rethrow_exception(p); std::rethrow_exception(p);
} }
} catch (const MyException6 &e) { } catch (const MyException6 &e) {
PyErr_SetString(PyExc_RuntimeError, e.what()); PyErr_SetString(PyExc_RuntimeError, e.what());
} }
}); });
m.def("throws1", []() { throw MyException("this error should go to a custom type"); }); m.def("throws1", []() { throw MyException("this error should go to a custom type"); });
m.def("throws2", []() { throw MyException2("this error should go to a standard Python exception"); }); m.def("throws2",
[]() { throw MyException2("this error should go to a standard Python exception"); });
m.def("throws3", []() { throw MyException3("this error cannot be translated"); }); m.def("throws3", []() { throw MyException3("this error cannot be translated"); });
m.def("throws4", []() { throw MyException4("this error is rethrown"); }); m.def("throws4", []() { throw MyException4("this error is rethrown"); });
m.def("throws5", []() { throw MyException5("this is a helper-defined translated exception"); }); m.def("throws5",
[]() { throw MyException5("this is a helper-defined translated exception"); });
m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); }); m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); });
m.def("throws6", []() { throw MyException6("MyException6 only handled in this module"); }); m.def("throws6", []() { throw MyException6("MyException6 only handled in this module"); });
m.def("throws_logic_error", []() { throw std::logic_error("this error should fall through to the standard handler"); }); m.def("throws_logic_error", []() {
throw std::logic_error("this error should fall through to the standard handler");
});
m.def("throws_overflow_error", []() { throw std::overflow_error(""); }); m.def("throws_overflow_error", []() { throw std::overflow_error(""); });
m.def("throws_local_error", []() { throw LocalException("never caught"); }); m.def("throws_local_error", []() { throw LocalException("never caught"); });
m.def("throws_local_simple_error", []() { throw LocalSimpleException("this mod"); }); m.def("throws_local_simple_error", []() { throw LocalSimpleException("this mod"); });
...@@ -185,8 +186,7 @@ TEST_SUBMODULE(exceptions, m) { ...@@ -185,8 +186,7 @@ TEST_SUBMODULE(exceptions, m) {
try { try {
// Assign to a py::object to force read access of nonexistent dict entry // Assign to a py::object to force read access of nonexistent dict entry
py::object o = foo["bar"]; py::object o = foo["bar"];
} } catch (py::error_already_set &ex) {
catch (py::error_already_set& ex) {
if (!ex.matches(PyExc_KeyError)) { if (!ex.matches(PyExc_KeyError)) {
throw; throw;
} }
...@@ -199,8 +199,7 @@ TEST_SUBMODULE(exceptions, m) { ...@@ -199,8 +199,7 @@ TEST_SUBMODULE(exceptions, m) {
try { try {
// Assign to a py::object to force read access of nonexistent dict entry // Assign to a py::object to force read access of nonexistent dict entry
py::object o = foo["bar"]; py::object o = foo["bar"];
} } catch (py::error_already_set &ex) {
catch (py::error_already_set &ex) {
if (!ex.matches(PyExc_Exception)) { if (!ex.matches(PyExc_Exception)) {
throw; throw;
} }
...@@ -212,8 +211,7 @@ TEST_SUBMODULE(exceptions, m) { ...@@ -212,8 +211,7 @@ TEST_SUBMODULE(exceptions, m) {
try { try {
// On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError // On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError
py::module_::import("nonexistent"); py::module_::import("nonexistent");
} } catch (py::error_already_set &ex) {
catch (py::error_already_set &ex) {
if (!ex.matches(PyExc_ImportError)) { if (!ex.matches(PyExc_ImportError)) {
throw; throw;
} }
...@@ -228,10 +226,9 @@ TEST_SUBMODULE(exceptions, m) { ...@@ -228,10 +226,9 @@ TEST_SUBMODULE(exceptions, m) {
} }
try { try {
throw py::error_already_set(); throw py::error_already_set();
} catch (const std::runtime_error& e) { } catch (const std::runtime_error &e) {
if ((err && e.what() != std::string("ValueError: foo")) || if ((err && e.what() != std::string("ValueError: foo"))
(!err && e.what() != std::string("Unknown internal error occurred"))) || (!err && e.what() != std::string("Unknown internal error occurred"))) {
{
PyErr_Clear(); PyErr_Clear();
throw std::runtime_error("error message mismatch"); throw std::runtime_error("error message mismatch");
} }
...@@ -249,7 +246,7 @@ TEST_SUBMODULE(exceptions, m) { ...@@ -249,7 +246,7 @@ TEST_SUBMODULE(exceptions, m) {
PythonCallInDestructor set_dict_in_destructor(d); PythonCallInDestructor set_dict_in_destructor(d);
PyErr_SetString(PyExc_ValueError, "foo"); PyErr_SetString(PyExc_ValueError, "foo");
throw py::error_already_set(); throw py::error_already_set();
} catch (const py::error_already_set&) { } catch (const py::error_already_set &) {
retval = true; retval = true;
} }
return retval; return retval;
...@@ -275,7 +272,7 @@ TEST_SUBMODULE(exceptions, m) { ...@@ -275,7 +272,7 @@ TEST_SUBMODULE(exceptions, m) {
}); });
// Test repr that cannot be displayed // Test repr that cannot be displayed
m.def("simple_bool_passthrough", [](bool x) {return x;}); m.def("simple_bool_passthrough", [](bool x) { return x; });
m.def("throw_should_be_translated_to_key_error", []() { throw shared_exception(); }); m.def("throw_should_be_translated_to_key_error", []() { throw shared_exception(); });
...@@ -291,7 +288,7 @@ TEST_SUBMODULE(exceptions, m) { ...@@ -291,7 +288,7 @@ TEST_SUBMODULE(exceptions, m) {
try { try {
PyErr_SetString(PyExc_ValueError, "inner"); PyErr_SetString(PyExc_ValueError, "inner");
throw py::error_already_set(); throw py::error_already_set();
} catch (py::error_already_set& e) { } catch (py::error_already_set &e) {
py::raise_from(e, PyExc_ValueError, "outer"); py::raise_from(e, PyExc_ValueError, "outer");
throw py::error_already_set(); throw py::error_already_set();
} }
......
#pragma once #pragma once
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <stdexcept> #include <stdexcept>
// shared exceptions for cross_module_tests // shared exceptions for cross_module_tests
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "constructor_stats.h" #include "constructor_stats.h"
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <cmath> #include <cmath>
#include <new> #include <new>
#include <utility> #include <utility>
...@@ -87,6 +88,7 @@ class TestFactory6 { ...@@ -87,6 +88,7 @@ class TestFactory6 {
protected: protected:
int value; int value;
bool alias = false; bool alias = false;
public: public:
explicit TestFactory6(int i) : value{i} { print_created(this, i); } explicit TestFactory6(int i) : value{i} { print_created(this, i); }
TestFactory6(TestFactory6 &&f) noexcept { TestFactory6(TestFactory6 &&f) noexcept {
...@@ -133,6 +135,7 @@ class TestFactory7 { ...@@ -133,6 +135,7 @@ class TestFactory7 {
protected: protected:
int value; int value;
bool alias = false; bool alias = false;
public: public:
explicit TestFactory7(int i) : value{i} { print_created(this, i); } explicit TestFactory7(int i) : value{i} { print_created(this, i); }
TestFactory7(TestFactory7 &&f) noexcept { TestFactory7(TestFactory7 &&f) noexcept {
...@@ -166,14 +169,15 @@ public: ...@@ -166,14 +169,15 @@ public:
int get() override { PYBIND11_OVERRIDE(int, TestFactory7, get, /*no args*/); } int get() override { PYBIND11_OVERRIDE(int, TestFactory7, get, /*no args*/); }
}; };
class TestFactoryHelper { class TestFactoryHelper {
public: public:
// Non-movable, non-copyable type: // Non-movable, non-copyable type:
// Return via pointer: // Return via pointer:
static TestFactory1 *construct1() { return new TestFactory1(); } static TestFactory1 *construct1() { return new TestFactory1(); }
// Holder: // Holder:
static std::unique_ptr<TestFactory1> construct1(int a) { return std::unique_ptr<TestFactory1>(new TestFactory1(a)); } static std::unique_ptr<TestFactory1> construct1(int a) {
return std::unique_ptr<TestFactory1>(new TestFactory1(a));
}
// pointer again // pointer again
static TestFactory1 *construct1_string(std::string a) { static TestFactory1 *construct1_string(std::string a) {
return new TestFactory1(std::move(a)); return new TestFactory1(std::move(a));
...@@ -183,7 +187,9 @@ public: ...@@ -183,7 +187,9 @@ public:
// pointer: // pointer:
static TestFactory2 *construct2() { return new TestFactory2(); } static TestFactory2 *construct2() { return new TestFactory2(); }
// holder: // holder:
static std::unique_ptr<TestFactory2> construct2(int a) { return std::unique_ptr<TestFactory2>(new TestFactory2(a)); } static std::unique_ptr<TestFactory2> construct2(int a) {
return std::unique_ptr<TestFactory2>(new TestFactory2(a));
}
// by value moving: // by value moving:
static TestFactory2 construct2(std::string a) { return TestFactory2(std::move(a)); } static TestFactory2 construct2(std::string a) { return TestFactory2(std::move(a)); }
...@@ -191,16 +197,18 @@ public: ...@@ -191,16 +197,18 @@ public:
// pointer: // pointer:
static TestFactory3 *construct3() { return new TestFactory3(); } static TestFactory3 *construct3() { return new TestFactory3(); }
// holder: // holder:
static std::shared_ptr<TestFactory3> construct3(int a) { return std::shared_ptr<TestFactory3>(new TestFactory3(a)); } static std::shared_ptr<TestFactory3> construct3(int a) {
return std::shared_ptr<TestFactory3>(new TestFactory3(a));
}
}; };
TEST_SUBMODULE(factory_constructors, m) { TEST_SUBMODULE(factory_constructors, m) {
// Define various trivial types to allow simpler overload resolution: // Define various trivial types to allow simpler overload resolution:
py::module_ m_tag = m.def_submodule("tag"); py::module_ m_tag = m.def_submodule("tag");
#define MAKE_TAG_TYPE(Name) \ #define MAKE_TAG_TYPE(Name) \
struct Name##_tag {}; \ struct Name##_tag {}; \
py::class_<Name##_tag>(m_tag, #Name "_tag").def(py::init<>()); \ py::class_<Name##_tag>(m_tag, #Name "_tag").def(py::init<>()); \
m_tag.attr(#Name) = py::cast(Name##_tag{}) m_tag.attr(#Name) = py::cast(Name##_tag{})
MAKE_TAG_TYPE(pointer); MAKE_TAG_TYPE(pointer);
MAKE_TAG_TYPE(unique_ptr); MAKE_TAG_TYPE(unique_ptr);
...@@ -223,9 +231,9 @@ TEST_SUBMODULE(factory_constructors, m) { ...@@ -223,9 +231,9 @@ TEST_SUBMODULE(factory_constructors, m) {
.def(py::init([](unique_ptr_tag, int v) { return TestFactoryHelper::construct1(v); })) .def(py::init([](unique_ptr_tag, int v) { return TestFactoryHelper::construct1(v); }))
.def(py::init(&TestFactoryHelper::construct1_string)) // raw function pointer .def(py::init(&TestFactoryHelper::construct1_string)) // raw function pointer
.def(py::init([](pointer_tag) { return TestFactoryHelper::construct1(); })) .def(py::init([](pointer_tag) { return TestFactoryHelper::construct1(); }))
.def(py::init([](py::handle, int v, py::handle) { return TestFactoryHelper::construct1(v); })) .def(py::init(
.def_readwrite("value", &TestFactory1::value) [](py::handle, int v, py::handle) { return TestFactoryHelper::construct1(v); }))
; .def_readwrite("value", &TestFactory1::value);
py::class_<TestFactory2>(m, "TestFactory2") py::class_<TestFactory2>(m, "TestFactory2")
.def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); })) .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); }))
.def(py::init([](unique_ptr_tag, std::string v) { .def(py::init([](unique_ptr_tag, std::string v) {
...@@ -236,7 +244,10 @@ TEST_SUBMODULE(factory_constructors, m) { ...@@ -236,7 +244,10 @@ TEST_SUBMODULE(factory_constructors, m) {
// Stateful & reused: // Stateful & reused:
int c = 1; int c = 1;
auto c4a = [c](pointer_tag, TF4_tag, int a) { (void) c; return new TestFactory4(a);}; auto c4a = [c](pointer_tag, TF4_tag, int a) {
(void) c;
return new TestFactory4(a);
};
// test_init_factory_basic, test_init_factory_casting // test_init_factory_basic, test_init_factory_casting
py::class_<TestFactory3, std::shared_ptr<TestFactory3>> pyTestFactory3(m, "TestFactory3"); py::class_<TestFactory3, std::shared_ptr<TestFactory3>> pyTestFactory3(m, "TestFactory3");
...@@ -253,16 +264,17 @@ TEST_SUBMODULE(factory_constructors, m) { ...@@ -253,16 +264,17 @@ TEST_SUBMODULE(factory_constructors, m) {
.def(py::init(c4a)) // derived ptr .def(py::init(c4a)) // derived ptr
.def(py::init([](pointer_tag, TF5_tag, int a) { return new TestFactory5(a); })) .def(py::init([](pointer_tag, TF5_tag, int a) { return new TestFactory5(a); }))
// derived shared ptr: // derived shared ptr:
.def(py::init([](shared_ptr_tag, TF4_tag, int a) { return std::make_shared<TestFactory4>(a); })) .def(py::init(
.def(py::init([](shared_ptr_tag, TF5_tag, int a) { return std::make_shared<TestFactory5>(a); })) [](shared_ptr_tag, TF4_tag, int a) { return std::make_shared<TestFactory4>(a); }))
.def(py::init(
[](shared_ptr_tag, TF5_tag, int a) { return std::make_shared<TestFactory5>(a); }))
// Returns nullptr: // Returns nullptr:
.def(py::init([](null_ptr_tag) { return (TestFactory3 *) nullptr; })) .def(py::init([](null_ptr_tag) { return (TestFactory3 *) nullptr; }))
.def(py::init([](null_unique_ptr_tag) { return std::unique_ptr<TestFactory3>(); })) .def(py::init([](null_unique_ptr_tag) { return std::unique_ptr<TestFactory3>(); }))
.def(py::init([](null_shared_ptr_tag) { return std::shared_ptr<TestFactory3>(); })) .def(py::init([](null_shared_ptr_tag) { return std::shared_ptr<TestFactory3>(); }))
.def_readwrite("value", &TestFactory3::value) .def_readwrite("value", &TestFactory3::value);
;
// test_init_factory_casting // test_init_factory_casting
py::class_<TestFactory4, TestFactory3, std::shared_ptr<TestFactory4>>(m, "TestFactory4") py::class_<TestFactory4, TestFactory3, std::shared_ptr<TestFactory4>>(m, "TestFactory4")
...@@ -346,9 +358,7 @@ TEST_SUBMODULE(factory_constructors, m) { ...@@ -346,9 +358,7 @@ TEST_SUBMODULE(factory_constructors, m) {
py::class_<NoPlacementNew>(m, "NoPlacementNew") py::class_<NoPlacementNew>(m, "NoPlacementNew")
.def(py::init<int>()) .def(py::init<int>())
.def(py::init([]() { return new NoPlacementNew(100); })) .def(py::init([]() { return new NoPlacementNew(100); }))
.def_readwrite("i", &NoPlacementNew::i) .def_readwrite("i", &NoPlacementNew::i);
;
// test_reallocations // test_reallocations
// Class that has verbose operator_new/operator_delete calls // Class that has verbose operator_new/operator_delete calls
...@@ -358,23 +368,36 @@ TEST_SUBMODULE(factory_constructors, m) { ...@@ -358,23 +368,36 @@ TEST_SUBMODULE(factory_constructors, m) {
explicit NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); } explicit NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); }
~NoisyAlloc() { py::print("~NoisyAlloc()"); } ~NoisyAlloc() { py::print("~NoisyAlloc()"); }
static void *operator new(size_t s) { py::print("noisy new"); return ::operator new(s); } static void *operator new(size_t s) {
static void *operator new(size_t, void *p) { py::print("noisy placement new"); return p; } py::print("noisy new");
static void operator delete(void *p, size_t) { py::print("noisy delete"); ::operator delete(p); } return ::operator new(s);
}
static void *operator new(size_t, void *p) {
py::print("noisy placement new");
return p;
}
static void operator delete(void *p, size_t) {
py::print("noisy delete");
::operator delete(p);
}
static void operator delete(void *, void *) { py::print("noisy placement delete"); } static void operator delete(void *, void *) { py::print("noisy placement delete"); }
#if defined(_MSC_VER) && _MSC_VER < 1910 #if defined(_MSC_VER) && _MSC_VER < 1910
// MSVC 2015 bug: the above "noisy delete" isn't invoked (fixed in MSVC 2017) // MSVC 2015 bug: the above "noisy delete" isn't invoked (fixed in MSVC 2017)
static void operator delete(void *p) { py::print("noisy delete"); ::operator delete(p); } static void operator delete(void *p) {
py::print("noisy delete");
::operator delete(p);
}
#endif #endif
}; };
py::class_<NoisyAlloc> pyNoisyAlloc(m, "NoisyAlloc"); py::class_<NoisyAlloc> pyNoisyAlloc(m, "NoisyAlloc");
// Since these overloads have the same number of arguments, the dispatcher will try each of // Since these overloads have the same number of arguments, the dispatcher will try each of
// them until the arguments convert. Thus we can get a pre-allocation here when passing a // them until the arguments convert. Thus we can get a pre-allocation here when passing a
// single non-integer: // single non-integer:
ignoreOldStyleInitWarnings([&pyNoisyAlloc]() { ignoreOldStyleInitWarnings([&pyNoisyAlloc]() {
pyNoisyAlloc.def("__init__", [](NoisyAlloc *a, int i) { new (a) NoisyAlloc(i); }); // Regular constructor, runs first, requires preallocation pyNoisyAlloc.def("__init__", [](NoisyAlloc *a, int i) {
new (a) NoisyAlloc(i);
}); // Regular constructor, runs first, requires preallocation
}); });
pyNoisyAlloc.def(py::init([](double d) { return new NoisyAlloc(d); })); pyNoisyAlloc.def(py::init([](double d) { return new NoisyAlloc(d); }));
...@@ -385,7 +408,8 @@ TEST_SUBMODULE(factory_constructors, m) { ...@@ -385,7 +408,8 @@ TEST_SUBMODULE(factory_constructors, m) {
pyNoisyAlloc.def(py::init([](double d, int) { return NoisyAlloc(d); })); pyNoisyAlloc.def(py::init([](double d, int) { return NoisyAlloc(d); }));
// Old-style placement new init; requires preallocation // Old-style placement new init; requires preallocation
ignoreOldStyleInitWarnings([&pyNoisyAlloc]() { ignoreOldStyleInitWarnings([&pyNoisyAlloc]() {
pyNoisyAlloc.def("__init__", [](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); }); pyNoisyAlloc.def("__init__",
[](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); });
}); });
// Requires deallocation of previous overload preallocated value: // Requires deallocation of previous overload preallocated value:
pyNoisyAlloc.def(py::init([](int i, double) { return new NoisyAlloc(i); })); pyNoisyAlloc.def(py::init([](int i, double) { return new NoisyAlloc(i); }));
...@@ -395,7 +419,8 @@ TEST_SUBMODULE(factory_constructors, m) { ...@@ -395,7 +419,8 @@ TEST_SUBMODULE(factory_constructors, m) {
"__init__", [](NoisyAlloc &a, int i, const std::string &) { new (&a) NoisyAlloc(i); }); "__init__", [](NoisyAlloc &a, int i, const std::string &) { new (&a) NoisyAlloc(i); });
}); });
// static_assert testing (the following def's should all fail with appropriate compilation errors): // static_assert testing (the following def's should all fail with appropriate compilation
// errors):
#if 0 #if 0
struct BadF1Base {}; struct BadF1Base {};
struct BadF1 : BadF1Base {}; struct BadF1 : BadF1Base {};
......
...@@ -7,43 +7,41 @@ ...@@ -7,43 +7,41 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include <pybind11/functional.h> #include <pybind11/functional.h>
#include "pybind11_tests.h"
class VirtClass { class VirtClass {
public: public:
virtual ~VirtClass() = default; virtual ~VirtClass() = default;
VirtClass() = default; VirtClass() = default;
VirtClass(const VirtClass&) = delete; VirtClass(const VirtClass &) = delete;
virtual void virtual_func() {} virtual void virtual_func() {}
virtual void pure_virtual_func() = 0; virtual void pure_virtual_func() = 0;
}; };
class PyVirtClass : public VirtClass { class PyVirtClass : public VirtClass {
void virtual_func() override { void virtual_func() override { PYBIND11_OVERRIDE(void, VirtClass, virtual_func, ); }
PYBIND11_OVERRIDE(void, VirtClass, virtual_func,);
}
void pure_virtual_func() override { void pure_virtual_func() override {
PYBIND11_OVERRIDE_PURE(void, VirtClass, pure_virtual_func,); PYBIND11_OVERRIDE_PURE(void, VirtClass, pure_virtual_func, );
} }
}; };
TEST_SUBMODULE(gil_scoped, m) { TEST_SUBMODULE(gil_scoped, m) {
py::class_<VirtClass, PyVirtClass>(m, "VirtClass") py::class_<VirtClass, PyVirtClass>(m, "VirtClass")
.def(py::init<>()) .def(py::init<>())
.def("virtual_func", &VirtClass::virtual_func) .def("virtual_func", &VirtClass::virtual_func)
.def("pure_virtual_func", &VirtClass::pure_virtual_func); .def("pure_virtual_func", &VirtClass::pure_virtual_func);
m.def("test_callback_py_obj", [](py::object &func) { func(); }); m.def("test_callback_py_obj", [](py::object &func) { func(); });
m.def("test_callback_std_func", [](const std::function<void()> &func) { func(); }); m.def("test_callback_std_func", [](const std::function<void()> &func) { func(); });
m.def("test_callback_virtual_func", [](VirtClass &virt) { virt.virtual_func(); }); m.def("test_callback_virtual_func", [](VirtClass &virt) { virt.virtual_func(); });
m.def("test_callback_pure_virtual_func", [](VirtClass &virt) { virt.pure_virtual_func(); }); m.def("test_callback_pure_virtual_func", [](VirtClass &virt) { virt.pure_virtual_func(); });
m.def("test_cross_module_gil", []() { m.def("test_cross_module_gil", []() {
auto cm = py::module_::import("cross_module_gil_utils"); auto cm = py::module_::import("cross_module_gil_utils");
auto gil_acquire auto gil_acquire = reinterpret_cast<void (*)()>(
= reinterpret_cast<void (*)()>(PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr())); PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr()));
py::gil_scoped_release gil_release; py::gil_scoped_release gil_release;
gil_acquire(); gil_acquire();
}); });
} }
...@@ -7,12 +7,14 @@ ...@@ -7,12 +7,14 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#if defined(_MSC_VER) && _MSC_VER < 1910 // VS 2015's MSVC #if defined(_MSC_VER) && _MSC_VER < 1910 // VS 2015's MSVC
# pragma warning(disable: 4702) // unreachable code in system header (xatomic.h(382)) # pragma warning(disable : 4702) // unreachable code in system header (xatomic.h(382))
#endif #endif
#include <pybind11/iostream.h> #include <pybind11/iostream.h>
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <atomic> #include <atomic>
#include <iostream> #include <iostream>
#include <mutex> #include <mutex>
...@@ -51,13 +53,12 @@ struct TestThread { ...@@ -51,13 +53,12 @@ struct TestThread {
std::cout << "x" << std::flush; std::cout << "x" << std::flush;
} }
std::this_thread::sleep_for(std::chrono::microseconds(50)); std::this_thread::sleep_for(std::chrono::microseconds(50));
} }; }
};
t_ = new std::thread(std::move(thread_f)); t_ = new std::thread(std::move(thread_f));
} }
~TestThread() { ~TestThread() { delete t_; }
delete t_;
}
void stop() { stop_ = true; } void stop() { stop_ = true; }
...@@ -75,7 +76,6 @@ struct TestThread { ...@@ -75,7 +76,6 @@ struct TestThread {
std::atomic<bool> stop_; std::atomic<bool> stop_;
}; };
TEST_SUBMODULE(iostream, m) { TEST_SUBMODULE(iostream, m) {
add_ostream_redirect(m); add_ostream_redirect(m);
...@@ -92,9 +92,11 @@ TEST_SUBMODULE(iostream, m) { ...@@ -92,9 +92,11 @@ TEST_SUBMODULE(iostream, m) {
std::cout << msg << std::flush; std::cout << msg << std::flush;
}); });
m.def("guard_output", &noisy_function, m.def("guard_output",
py::call_guard<py::scoped_ostream_redirect>(), &noisy_function,
py::arg("msg"), py::arg("flush")=true); py::call_guard<py::scoped_ostream_redirect>(),
py::arg("msg"),
py::arg("flush") = true);
m.def("captured_err", [](const std::string &msg) { m.def("captured_err", [](const std::string &msg) {
py::scoped_ostream_redirect redir(std::cerr, py::module_::import("sys").attr("stderr")); py::scoped_ostream_redirect redir(std::cerr, py::module_::import("sys").attr("stderr"));
...@@ -103,9 +105,11 @@ TEST_SUBMODULE(iostream, m) { ...@@ -103,9 +105,11 @@ TEST_SUBMODULE(iostream, m) {
m.def("noisy_function", &noisy_function, py::arg("msg"), py::arg("flush") = true); m.def("noisy_function", &noisy_function, py::arg("msg"), py::arg("flush") = true);
m.def("dual_guard", &noisy_funct_dual, m.def("dual_guard",
py::call_guard<py::scoped_ostream_redirect, py::scoped_estream_redirect>(), &noisy_funct_dual,
py::arg("msg"), py::arg("emsg")); py::call_guard<py::scoped_ostream_redirect, py::scoped_estream_redirect>(),
py::arg("msg"),
py::arg("emsg"));
m.def("raw_output", [](const std::string &msg) { std::cout << msg << std::flush; }); m.def("raw_output", [](const std::string &msg) { std::cout << msg << std::flush; });
......
...@@ -8,12 +8,12 @@ ...@@ -8,12 +8,12 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include "local_bindings.h"
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include <pybind11/stl_bind.h> #include <pybind11/stl_bind.h>
#include "local_bindings.h"
#include "pybind11_tests.h"
#include <numeric> #include <numeric>
#include <utility> #include <utility>
...@@ -24,9 +24,9 @@ TEST_SUBMODULE(local_bindings, m) { ...@@ -24,9 +24,9 @@ TEST_SUBMODULE(local_bindings, m) {
// test_local_bindings // test_local_bindings
// Register a class with py::module_local: // Register a class with py::module_local:
bind_local<LocalType, -1>(m, "LocalType", py::module_local()) bind_local<LocalType, -1>(m, "LocalType", py::module_local()).def("get3", [](LocalType &t) {
.def("get3", [](LocalType &t) { return t.i + 3; }) return t.i + 3;
; });
m.def("local_value", [](LocalType &l) { return l.i; }); m.def("local_value", [](LocalType &l) { return l.i; });
...@@ -35,14 +35,14 @@ TEST_SUBMODULE(local_bindings, m) { ...@@ -35,14 +35,14 @@ TEST_SUBMODULE(local_bindings, m) {
// one, in pybind11_cross_module_tests.cpp, is designed to fail): // one, in pybind11_cross_module_tests.cpp, is designed to fail):
bind_local<NonLocalType, 0>(m, "NonLocalType") bind_local<NonLocalType, 0>(m, "NonLocalType")
.def(py::init<int>()) .def(py::init<int>())
.def("get", [](LocalType &i) { return i.i; }) .def("get", [](LocalType &i) { return i.i; });
;
// test_duplicate_local // test_duplicate_local
// py::module_local declarations should be visible across compilation units that get linked together; // py::module_local declarations should be visible across compilation units that get linked
// this tries to register a duplicate local. It depends on a definition in test_class.cpp and // together; this tries to register a duplicate local. It depends on a definition in
// should raise a runtime error from the duplicate definition attempt. If test_class isn't // test_class.cpp and should raise a runtime error from the duplicate definition attempt. If
// available it *also* throws a runtime error (with "test_class not enabled" as value). // test_class isn't available it *also* throws a runtime error (with "test_class not enabled"
// as value).
m.def("register_local_external", [m]() { m.def("register_local_external", [m]() {
auto main = py::module_::import("pybind11_tests"); auto main = py::module_::import("pybind11_tests");
if (py::hasattr(main, "class_")) { if (py::hasattr(main, "class_")) {
...@@ -79,12 +79,12 @@ TEST_SUBMODULE(local_bindings, m) { ...@@ -79,12 +79,12 @@ TEST_SUBMODULE(local_bindings, m) {
m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); }); m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });
// test_internal_locals_differ // test_internal_locals_differ
m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::get_local_internals().registered_types_cpp; }); m.def("local_cpp_types_addr",
[]() { return (uintptr_t) &py::detail::get_local_internals().registered_types_cpp; });
// test_stl_caster_vs_stl_bind // test_stl_caster_vs_stl_bind
m.def("load_vector_via_caster", [](std::vector<int> v) { m.def("load_vector_via_caster",
return std::accumulate(v.begin(), v.end(), 0); [](std::vector<int> v) { return std::accumulate(v.begin(), v.end(), 0); });
});
// test_cross_module_calls // test_cross_module_calls
m.def("return_self", [](LocalVec *v) { return v; }); m.def("return_self", [](LocalVec *v) { return v; });
...@@ -94,11 +94,9 @@ TEST_SUBMODULE(local_bindings, m) { ...@@ -94,11 +94,9 @@ TEST_SUBMODULE(local_bindings, m) {
public: public:
explicit Cat(std::string name) : Pet(std::move(name)) {} explicit Cat(std::string name) : Pet(std::move(name)) {}
}; };
py::class_<pets::Pet>(m, "Pet", py::module_local()) py::class_<pets::Pet>(m, "Pet", py::module_local()).def("get_name", &pets::Pet::name);
.def("get_name", &pets::Pet::name);
// Binding for local extending class: // Binding for local extending class:
py::class_<Cat, pets::Pet>(m, "Cat") py::class_<Cat, pets::Pet>(m, "Cat").def(py::init<std::string>());
.def(py::init<std::string>());
m.def("pet_name", [](pets::Pet &p) { return p.name(); }); m.def("pet_name", [](pets::Pet &p) { return p.name(); });
py::class_<MixGL>(m, "MixGL").def(py::init<int>()); py::class_<MixGL>(m, "MixGL").def(py::init<int>());
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include "constructor_stats.h" #include "constructor_stats.h"
#include "pybind11_tests.h"
TEST_SUBMODULE(modules, m) { TEST_SUBMODULE(modules, m) {
// test_nested_modules // test_nested_modules
...@@ -22,23 +22,30 @@ TEST_SUBMODULE(modules, m) { ...@@ -22,23 +22,30 @@ TEST_SUBMODULE(modules, m) {
public: public:
explicit A(int v) : v(v) { print_created(this, v); } explicit A(int v) : v(v) { print_created(this, v); }
~A() { print_destroyed(this); } ~A() { print_destroyed(this); }
A(const A&) { print_copy_created(this); } A(const A &) { print_copy_created(this); }
A& operator=(const A &copy) { print_copy_assigned(this); v = copy.v; return *this; } A &operator=(const A &copy) {
print_copy_assigned(this);
v = copy.v;
return *this;
}
std::string toString() const { return "A[" + std::to_string(v) + "]"; } std::string toString() const { return "A[" + std::to_string(v) + "]"; }
private: private:
int v; int v;
}; };
py::class_<A>(m_sub, "A") py::class_<A>(m_sub, "A").def(py::init<int>()).def("__repr__", &A::toString);
.def(py::init<int>())
.def("__repr__", &A::toString);
class B { class B {
public: public:
B() { print_default_created(this); } B() { print_default_created(this); }
~B() { print_destroyed(this); } ~B() { print_destroyed(this); }
B(const B&) { print_copy_created(this); } B(const B &) { print_copy_created(this); }
B& operator=(const B &copy) { print_copy_assigned(this); a1 = copy.a1; a2 = copy.a2; return *this; } B &operator=(const B &copy) {
print_copy_assigned(this);
a1 = copy.a1;
a2 = copy.a2;
return *this;
}
A &get_a1() { return a1; } A &get_a1() { return a1; }
A &get_a2() { return a2; } A &get_a2() { return a2; }
...@@ -47,10 +54,16 @@ TEST_SUBMODULE(modules, m) { ...@@ -47,10 +54,16 @@ TEST_SUBMODULE(modules, m) {
}; };
py::class_<B>(m_sub, "B") py::class_<B>(m_sub, "B")
.def(py::init<>()) .def(py::init<>())
.def("get_a1", &B::get_a1, "Return the internal A 1", py::return_value_policy::reference_internal) .def("get_a1",
.def("get_a2", &B::get_a2, "Return the internal A 2", py::return_value_policy::reference_internal) &B::get_a1,
.def_readwrite("a1", &B::a1) // def_readonly uses an internal "Return the internal A 1",
// reference return policy by default py::return_value_policy::reference_internal)
.def("get_a2",
&B::get_a2,
"Return the internal A 2",
py::return_value_policy::reference_internal)
.def_readwrite("a1", &B::a1) // def_readonly uses an internal
// reference return policy by default
.def_readwrite("a2", &B::a2); .def_readwrite("a2", &B::a2);
// This is intentionally "py::module" to verify it still can be used in place of "py::module_" // This is intentionally "py::module" to verify it still can be used in place of "py::module_"
...@@ -59,13 +72,14 @@ TEST_SUBMODULE(modules, m) { ...@@ -59,13 +72,14 @@ TEST_SUBMODULE(modules, m) {
// test_duplicate_registration // test_duplicate_registration
// Registering two things with the same name // Registering two things with the same name
m.def("duplicate_registration", []() { m.def("duplicate_registration", []() {
class Dupe1 { }; class Dupe1 {};
class Dupe2 { }; class Dupe2 {};
class Dupe3 { }; class Dupe3 {};
class DupeException { }; class DupeException {};
// Go ahead and leak, until we have a non-leaking py::module_ constructor // Go ahead and leak, until we have a non-leaking py::module_ constructor
auto dm = py::module_::create_extension_module("dummy", nullptr, new py::module_::module_def); auto dm
= py::module_::create_extension_module("dummy", nullptr, new py::module_::module_def);
auto failures = py::list(); auto failures = py::list();
py::class_<Dupe1>(dm, "Dupe1"); py::class_<Dupe1>(dm, "Dupe1");
...@@ -76,27 +90,33 @@ TEST_SUBMODULE(modules, m) { ...@@ -76,27 +90,33 @@ TEST_SUBMODULE(modules, m) {
try { try {
py::class_<Dupe1>(dm, "Dupe1"); py::class_<Dupe1>(dm, "Dupe1");
failures.append("Dupe1 class"); failures.append("Dupe1 class");
} catch (std::runtime_error &) {} } catch (std::runtime_error &) {
}
try { try {
dm.def("Dupe1", []() { return Dupe1(); }); dm.def("Dupe1", []() { return Dupe1(); });
failures.append("Dupe1 function"); failures.append("Dupe1 function");
} catch (std::runtime_error &) {} } catch (std::runtime_error &) {
}
try { try {
py::class_<Dupe3>(dm, "dupe1_factory"); py::class_<Dupe3>(dm, "dupe1_factory");
failures.append("dupe1_factory"); failures.append("dupe1_factory");
} catch (std::runtime_error &) {} } catch (std::runtime_error &) {
}
try { try {
py::exception<Dupe3>(dm, "Dupe2"); py::exception<Dupe3>(dm, "Dupe2");
failures.append("Dupe2"); failures.append("Dupe2");
} catch (std::runtime_error &) {} } catch (std::runtime_error &) {
}
try { try {
dm.def("DupeException", []() { return 30; }); dm.def("DupeException", []() { return 30; });
failures.append("DupeException1"); failures.append("DupeException1");
} catch (std::runtime_error &) {} } catch (std::runtime_error &) {
}
try { try {
py::class_<DupeException>(dm, "DupeException"); py::class_<DupeException>(dm, "DupeException");
failures.append("DupeException2"); failures.append("DupeException2");
} catch (std::runtime_error &) {} } catch (std::runtime_error &) {
}
return failures; return failures;
}); });
......
...@@ -8,14 +8,15 @@ ...@@ -8,14 +8,15 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include "constructor_stats.h" #include "constructor_stats.h"
#include "pybind11_tests.h"
namespace { namespace {
// Many bases for testing that multiple inheritance from many classes (i.e. requiring extra // Many bases for testing that multiple inheritance from many classes (i.e. requiring extra
// space for holder constructed flags) works. // space for holder constructed flags) works.
template <int N> struct BaseN { template <int N>
struct BaseN {
explicit BaseN(int i) : i(i) {} explicit BaseN(int i) : i(i) {}
int i; int i;
}; };
...@@ -57,13 +58,23 @@ struct Base2a { ...@@ -57,13 +58,23 @@ struct Base2a {
int i; int i;
}; };
struct Base12a : Base1a, Base2a { struct Base12a : Base1a, Base2a {
Base12a(int i, int j) : Base1a(i), Base2a(j) { } Base12a(int i, int j) : Base1a(i), Base2a(j) {}
}; };
// test_mi_unaligned_base // test_mi_unaligned_base
// test_mi_base_return // test_mi_base_return
struct I801B1 { int a = 1; I801B1() = default; I801B1(const I801B1 &) = default; virtual ~I801B1() = default; }; struct I801B1 {
struct I801B2 { int b = 2; I801B2() = default; I801B2(const I801B2 &) = default; virtual ~I801B2() = default; }; int a = 1;
I801B1() = default;
I801B1(const I801B1 &) = default;
virtual ~I801B1() = default;
};
struct I801B2 {
int b = 2;
I801B2() = default;
I801B2(const I801B2 &) = default;
virtual ~I801B2() = default;
};
struct I801C : I801B1, I801B2 {}; struct I801C : I801B1, I801B2 {};
struct I801D : I801C {}; // Indirect MI struct I801D : I801C {}; // Indirect MI
...@@ -82,8 +93,7 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -82,8 +93,7 @@ TEST_SUBMODULE(multiple_inheritance, m) {
int i; int i;
}; };
py::class_<Base1> b1(m, "Base1"); py::class_<Base1> b1(m, "Base1");
b1.def(py::init<int>()) b1.def(py::init<int>()).def("foo", &Base1::foo);
.def("foo", &Base1::foo);
struct Base2 { struct Base2 {
explicit Base2(int i) : i(i) {} explicit Base2(int i) : i(i) {}
...@@ -91,42 +101,49 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -91,42 +101,49 @@ TEST_SUBMODULE(multiple_inheritance, m) {
int i; int i;
}; };
py::class_<Base2> b2(m, "Base2"); py::class_<Base2> b2(m, "Base2");
b2.def(py::init<int>()) b2.def(py::init<int>()).def("bar", &Base2::bar);
.def("bar", &Base2::bar);
// test_multiple_inheritance_cpp // test_multiple_inheritance_cpp
struct Base12 : Base1, Base2 { struct Base12 : Base1, Base2 {
Base12(int i, int j) : Base1(i), Base2(j) { } Base12(int i, int j) : Base1(i), Base2(j) {}
}; };
struct MIType : Base12 { struct MIType : Base12 {
MIType(int i, int j) : Base12(i, j) { } MIType(int i, int j) : Base12(i, j) {}
}; };
py::class_<Base12, Base1, Base2>(m, "Base12"); py::class_<Base12, Base1, Base2>(m, "Base12");
py::class_<MIType, Base12>(m, "MIType") py::class_<MIType, Base12>(m, "MIType").def(py::init<int, int>());
.def(py::init<int, int>());
// test_multiple_inheritance_python_many_bases // test_multiple_inheritance_python_many_bases
#define PYBIND11_BASEN(N) \ #define PYBIND11_BASEN(N) \
py::class_<BaseN<(N)>>(m, "BaseN" #N).def(py::init<int>()).def("f" #N, [](BaseN<N> &b) { \ py::class_<BaseN<(N)>>(m, "BaseN" #N).def(py::init<int>()).def("f" #N, [](BaseN<N> &b) { \
return b.i + (N); \ return b.i + (N); \
}) })
PYBIND11_BASEN( 1); PYBIND11_BASEN( 2); PYBIND11_BASEN( 3); PYBIND11_BASEN( 4); PYBIND11_BASEN(1);
PYBIND11_BASEN( 5); PYBIND11_BASEN( 6); PYBIND11_BASEN( 7); PYBIND11_BASEN( 8); PYBIND11_BASEN(2);
PYBIND11_BASEN( 9); PYBIND11_BASEN(10); PYBIND11_BASEN(11); PYBIND11_BASEN(12); PYBIND11_BASEN(3);
PYBIND11_BASEN(13); PYBIND11_BASEN(14); PYBIND11_BASEN(15); PYBIND11_BASEN(16); PYBIND11_BASEN(4);
PYBIND11_BASEN(5);
PYBIND11_BASEN(6);
PYBIND11_BASEN(7);
PYBIND11_BASEN(8);
PYBIND11_BASEN(9);
PYBIND11_BASEN(10);
PYBIND11_BASEN(11);
PYBIND11_BASEN(12);
PYBIND11_BASEN(13);
PYBIND11_BASEN(14);
PYBIND11_BASEN(15);
PYBIND11_BASEN(16);
PYBIND11_BASEN(17); PYBIND11_BASEN(17);
// Uncommenting this should result in a compile time failure (MI can only be specified via // Uncommenting this should result in a compile time failure (MI can only be specified via
// template parameters because pybind has to know the types involved; see discussion in #742 for // template parameters because pybind has to know the types involved; see discussion in #742
// details). // for details).
// struct Base12v2 : Base1, Base2 { // struct Base12v2 : Base1, Base2 {
// Base12v2(int i, int j) : Base1(i), Base2(j) { } // Base12v2(int i, int j) : Base1(i), Base2(j) { }
// }; // };
// py::class_<Base12v2>(m, "Base12v2", b1, b2) // py::class_<Base12v2>(m, "Base12v2", b1, b2)
// .def(py::init<int, int>()); // .def(py::init<int, int>());
// test_multiple_inheritance_virtbase // test_multiple_inheritance_virtbase
// Test the case where not all base classes are specified, and where pybind11 requires the // Test the case where not all base classes are specified, and where pybind11 requires the
...@@ -139,8 +156,8 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -139,8 +156,8 @@ TEST_SUBMODULE(multiple_inheritance, m) {
.def(py::init<int>()) .def(py::init<int>())
.def("bar", &Base2a::bar); .def("bar", &Base2a::bar);
py::class_<Base12a, /* Base1 missing */ Base2a, py::class_<Base12a, /* Base1 missing */ Base2a, std::shared_ptr<Base12a>>(
std::shared_ptr<Base12a>>(m, "Base12a", py::multiple_inheritance()) m, "Base12a", py::multiple_inheritance())
.def(py::init<int, int>()); .def(py::init<int, int>());
m.def("bar_base2a", [](Base2a *b) { return b->bar(); }); m.def("bar_base2a", [](Base2a *b) { return b->bar(); });
...@@ -150,11 +167,18 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -150,11 +167,18 @@ TEST_SUBMODULE(multiple_inheritance, m) {
// test_mi_base_return // test_mi_base_return
// Issue #801: invalid casting to derived type with MI bases // Issue #801: invalid casting to derived type with MI bases
// Unregistered classes: // Unregistered classes:
struct I801B3 { int c = 3; virtual ~I801B3() = default; }; struct I801B3 {
int c = 3;
virtual ~I801B3() = default;
};
struct I801E : I801B3, I801D {}; struct I801E : I801B3, I801D {};
py::class_<I801B1, std::shared_ptr<I801B1>>(m, "I801B1").def(py::init<>()).def_readonly("a", &I801B1::a); py::class_<I801B1, std::shared_ptr<I801B1>>(m, "I801B1")
py::class_<I801B2, std::shared_ptr<I801B2>>(m, "I801B2").def(py::init<>()).def_readonly("b", &I801B2::b); .def(py::init<>())
.def_readonly("a", &I801B1::a);
py::class_<I801B2, std::shared_ptr<I801B2>>(m, "I801B2")
.def(py::init<>())
.def_readonly("b", &I801B2::b);
py::class_<I801C, I801B1, I801B2, std::shared_ptr<I801C>>(m, "I801C").def(py::init<>()); py::class_<I801C, I801B1, I801B2, std::shared_ptr<I801C>>(m, "I801C").def(py::init<>());
py::class_<I801D, I801C, std::shared_ptr<I801D>>(m, "I801D").def(py::init<>()); py::class_<I801D, I801C, std::shared_ptr<I801D>>(m, "I801D").def(py::init<>());
...@@ -179,11 +203,8 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -179,11 +203,8 @@ TEST_SUBMODULE(multiple_inheritance, m) {
m.def("i801e_c", []() -> I801C * { return new I801E(); }); m.def("i801e_c", []() -> I801C * { return new I801E(); });
m.def("i801e_b2", []() -> I801B2 * { return new I801E(); }); m.def("i801e_b2", []() -> I801B2 * { return new I801E(); });
// test_mi_static_properties // test_mi_static_properties
py::class_<Vanilla>(m, "Vanilla") py::class_<Vanilla>(m, "Vanilla").def(py::init<>()).def("vanilla", &Vanilla::vanilla);
.def(py::init<>())
.def("vanilla", &Vanilla::vanilla);
py::class_<WithStatic1>(m, "WithStatic1") py::class_<WithStatic1>(m, "WithStatic1")
.def(py::init<>()) .def(py::init<>())
...@@ -195,22 +216,19 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -195,22 +216,19 @@ TEST_SUBMODULE(multiple_inheritance, m) {
.def_static("static_func2", &WithStatic2::static_func2) .def_static("static_func2", &WithStatic2::static_func2)
.def_readwrite_static("static_value2", &WithStatic2::static_value2); .def_readwrite_static("static_value2", &WithStatic2::static_value2);
py::class_<VanillaStaticMix1, Vanilla, WithStatic1, WithStatic2>( py::class_<VanillaStaticMix1, Vanilla, WithStatic1, WithStatic2>(m, "VanillaStaticMix1")
m, "VanillaStaticMix1")
.def(py::init<>()) .def(py::init<>())
.def_static("static_func", &VanillaStaticMix1::static_func) .def_static("static_func", &VanillaStaticMix1::static_func)
.def_readwrite_static("static_value", &VanillaStaticMix1::static_value); .def_readwrite_static("static_value", &VanillaStaticMix1::static_value);
py::class_<VanillaStaticMix2, WithStatic1, Vanilla, WithStatic2>( py::class_<VanillaStaticMix2, WithStatic1, Vanilla, WithStatic2>(m, "VanillaStaticMix2")
m, "VanillaStaticMix2")
.def(py::init<>()) .def(py::init<>())
.def_static("static_func", &VanillaStaticMix2::static_func) .def_static("static_func", &VanillaStaticMix2::static_func)
.def_readwrite_static("static_value", &VanillaStaticMix2::static_value); .def_readwrite_static("static_value", &VanillaStaticMix2::static_value);
struct WithDict {};
struct WithDict { }; struct VanillaDictMix1 : Vanilla, WithDict {};
struct VanillaDictMix1 : Vanilla, WithDict { }; struct VanillaDictMix2 : WithDict, Vanilla {};
struct VanillaDictMix2 : WithDict, Vanilla { };
py::class_<WithDict>(m, "WithDict", py::dynamic_attr()).def(py::init<>()); py::class_<WithDict>(m, "WithDict", py::dynamic_attr()).def(py::init<>());
py::class_<VanillaDictMix1, Vanilla, WithDict>(m, "VanillaDictMix1").def(py::init<>()); py::class_<VanillaDictMix1, Vanilla, WithDict>(m, "VanillaDictMix1").def(py::init<>());
py::class_<VanillaDictMix2, WithDict, Vanilla>(m, "VanillaDictMix2").def(py::init<>()); py::class_<VanillaDictMix2, WithDict, Vanilla>(m, "VanillaDictMix2").def(py::init<>());
...@@ -218,18 +236,25 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -218,18 +236,25 @@ TEST_SUBMODULE(multiple_inheritance, m) {
// test_diamond_inheritance // test_diamond_inheritance
// Issue #959: segfault when constructing diamond inheritance instance // Issue #959: segfault when constructing diamond inheritance instance
// All of these have int members so that there will be various unequal pointers involved. // All of these have int members so that there will be various unequal pointers involved.
struct B { int b; B() = default; B(const B&) = default; virtual ~B() = default; }; struct B {
struct C0 : public virtual B { int c0; }; int b;
struct C1 : public virtual B { int c1; }; B() = default;
struct D : public C0, public C1 { int d; }; B(const B &) = default;
py::class_<B>(m, "B") virtual ~B() = default;
.def("b", [](B *self) { return self; }); };
py::class_<C0, B>(m, "C0") struct C0 : public virtual B {
.def("c0", [](C0 *self) { return self; }); int c0;
py::class_<C1, B>(m, "C1") };
.def("c1", [](C1 *self) { return self; }); struct C1 : public virtual B {
py::class_<D, C0, C1>(m, "D") int c1;
.def(py::init<>()); };
struct D : public C0, public C1 {
int d;
};
py::class_<B>(m, "B").def("b", [](B *self) { return self; });
py::class_<C0, B>(m, "C0").def("c0", [](C0 *self) { return self; });
py::class_<C1, B>(m, "C1").def("c1", [](C1 *self) { return self; });
py::class_<D, C0, C1>(m, "D").def(py::init<>());
// test_pr3635_diamond_* // test_pr3635_diamond_*
// - functions are get_{base}_{var}, return {var} // - functions are get_{base}_{var}, return {var}
......
...@@ -8,38 +8,43 @@ ...@@ -8,38 +8,43 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include <pybind11/numpy.h> #include <pybind11/numpy.h>
#include "pybind11_tests.h"
#include <utility> #include <utility>
double my_func(int x, float y, double z) { double my_func(int x, float y, double z) {
py::print("my_func(x:int={}, y:float={:.0f}, z:float={:.0f})"_s.format(x, y, z)); py::print("my_func(x:int={}, y:float={:.0f}, z:float={:.0f})"_s.format(x, y, z));
return (float) x*y*z; return (float) x * y * z;
} }
TEST_SUBMODULE(numpy_vectorize, m) { TEST_SUBMODULE(numpy_vectorize, m) {
try { py::module_::import("numpy"); } try {
catch (...) { return; } py::module_::import("numpy");
} catch (...) {
return;
}
// test_vectorize, test_docs, test_array_collapse // test_vectorize, test_docs, test_array_collapse
// Vectorize all arguments of a function (though non-vector arguments are also allowed) // Vectorize all arguments of a function (though non-vector arguments are also allowed)
m.def("vectorized_func", py::vectorize(my_func)); m.def("vectorized_func", py::vectorize(my_func));
// Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization) // Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the
// vectorization)
m.def("vectorized_func2", [](py::array_t<int> x, py::array_t<float> y, float z) { m.def("vectorized_func2", [](py::array_t<int> x, py::array_t<float> y, float z) {
return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(std::move(x), return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(std::move(x),
std::move(y)); std::move(y));
}); });
// Vectorize a complex-valued function // Vectorize a complex-valued function
m.def("vectorized_func3", py::vectorize( m.def("vectorized_func3",
[](std::complex<double> c) { return c * std::complex<double>(2.f); } py::vectorize([](std::complex<double> c) { return c * std::complex<double>(2.f); }));
));
// test_type_selection // test_type_selection
// NumPy function which only accepts specific data types // NumPy function which only accepts specific data types
// A lot of these no lints could be replaced with const refs, and probably should at some point. // A lot of these no lints could be replaced with const refs, and probably should at some
// point.
m.def("selective_func", m.def("selective_func",
[](const py::array_t<int, py::array::c_style> &) { return "Int branch taken."; }); [](const py::array_t<int, py::array::c_style> &) { return "Int branch taken."; });
m.def("selective_func", m.def("selective_func",
...@@ -49,8 +54,8 @@ TEST_SUBMODULE(numpy_vectorize, m) { ...@@ -49,8 +54,8 @@ TEST_SUBMODULE(numpy_vectorize, m) {
}); });
// test_passthrough_arguments // test_passthrough_arguments
// Passthrough test: references and non-pod types should be automatically passed through (in the // Passthrough test: references and non-pod types should be automatically passed through (in
// function definition below, only `b`, `d`, and `g` are vectorized): // the function definition below, only `b`, `d`, and `g` are vectorized):
struct NonPODClass { struct NonPODClass {
explicit NonPODClass(int v) : value{v} {} explicit NonPODClass(int v) : value{v} {}
int value; int value;
...@@ -76,8 +81,7 @@ TEST_SUBMODULE(numpy_vectorize, m) { ...@@ -76,8 +81,7 @@ TEST_SUBMODULE(numpy_vectorize, m) {
int value = 0; int value = 0;
}; };
py::class_<VectorizeTestClass> vtc(m, "VectorizeTestClass"); py::class_<VectorizeTestClass> vtc(m, "VectorizeTestClass");
vtc .def(py::init<int>()) vtc.def(py::init<int>()).def_readwrite("value", &VectorizeTestClass::value);
.def_readwrite("value", &VectorizeTestClass::value);
// Automatic vectorizing of methods // Automatic vectorizing of methods
vtc.def("method", py::vectorize(&VectorizeTestClass::method)); vtc.def("method", py::vectorize(&VectorizeTestClass::method));
...@@ -99,5 +103,5 @@ TEST_SUBMODULE(numpy_vectorize, m) { ...@@ -99,5 +103,5 @@ TEST_SUBMODULE(numpy_vectorize, m) {
return py::detail::broadcast(buffers, ndim, shape); return py::detail::broadcast(buffers, ndim, shape);
}); });
m.def("add_to", py::vectorize([](NonPODClass& x, int a) { x.value += a; })); m.def("add_to", py::vectorize([](NonPODClass &x, int a) { x.value += a; }));
} }
...@@ -7,8 +7,10 @@ ...@@ -7,8 +7,10 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include "pybind11_tests.h"
#include <vector> #include <vector>
// IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures // IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures
...@@ -26,12 +28,13 @@ TEST_SUBMODULE(opaque_types, m) { ...@@ -26,12 +28,13 @@ TEST_SUBMODULE(opaque_types, m) {
.def(py::init<>()) .def(py::init<>())
.def("pop_back", &StringList::pop_back) .def("pop_back", &StringList::pop_back)
/* There are multiple versions of push_back(), etc. Select the right ones. */ /* There are multiple versions of push_back(), etc. Select the right ones. */
.def("push_back", (void (StringList::*)(const std::string &)) &StringList::push_back) .def("push_back", (void(StringList::*)(const std::string &)) & StringList::push_back)
.def("back", (std::string &(StringList::*)()) &StringList::back) .def("back", (std::string & (StringList::*) ()) & StringList::back)
.def("__len__", [](const StringList &v) { return v.size(); }) .def("__len__", [](const StringList &v) { return v.size(); })
.def("__iter__", [](StringList &v) { .def(
return py::make_iterator(v.begin(), v.end()); "__iter__",
}, py::keep_alive<0, 1>()); [](StringList &v) { return py::make_iterator(v.begin(), v.end()); },
py::keep_alive<0, 1>());
class ClassWithSTLVecProperty { class ClassWithSTLVecProperty {
public: public:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment