Unverified Commit ec24786e authored by Ralf W. Grosse-Kunstleve's avatar Ralf W. Grosse-Kunstleve Committed by GitHub
Browse files

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: default avatarHenry Schreiner <henryschreineriii@gmail.com>
parent e96221be
...@@ -11,18 +11,19 @@ ...@@ -11,18 +11,19 @@
// Intel compiler requires a separate header file to support aligned new operators // Intel compiler requires a separate header file to support aligned new operators
// and does not set the __cpp_aligned_new feature macro. // and does not set the __cpp_aligned_new feature macro.
// This header needs to be included before pybind11. // This header needs to be included before pybind11.
#include <aligned_new> # include <aligned_new>
#endif #endif
#include "pybind11_tests.h" #include <pybind11/stl.h>
#include "constructor_stats.h" #include "constructor_stats.h"
#include "local_bindings.h" #include "local_bindings.h"
#include <pybind11/stl.h> #include "pybind11_tests.h"
#include <utility> #include <utility>
#if defined(_MSC_VER) #if defined(_MSC_VER)
# pragma warning(disable: 4324) # pragma warning(disable : 4324)
// warning C4324: structure was padded due to alignment specifier // warning C4324: structure was padded due to alignment specifier
#endif #endif
...@@ -75,6 +76,7 @@ TEST_SUBMODULE(class_, m) { ...@@ -75,6 +76,7 @@ TEST_SUBMODULE(class_, m) {
: m_name(name), m_species(species) {} : m_name(name), m_species(species) {}
std::string name() const { return m_name; } std::string name() const { return m_name; }
std::string species() const { return m_species; } std::string species() const { return m_species; }
private: private:
std::string m_name; std::string m_name;
std::string m_species; std::string m_species;
...@@ -101,27 +103,24 @@ TEST_SUBMODULE(class_, m) { ...@@ -101,27 +103,24 @@ TEST_SUBMODULE(class_, m) {
}; };
py::class_<Pet> pet_class(m, "Pet"); py::class_<Pet> pet_class(m, "Pet");
pet_class pet_class.def(py::init<std::string, std::string>())
.def(py::init<std::string, std::string>())
.def("name", &Pet::name) .def("name", &Pet::name)
.def("species", &Pet::species); .def("species", &Pet::species);
/* One way of declaring a subclass relationship: reference parent's class_ object */ /* One way of declaring a subclass relationship: reference parent's class_ object */
py::class_<Dog>(m, "Dog", pet_class) py::class_<Dog>(m, "Dog", pet_class).def(py::init<std::string>());
.def(py::init<std::string>());
/* Another way of declaring a subclass relationship: reference parent's C++ type */ /* Another way of declaring a subclass relationship: reference parent's C++ type */
py::class_<Rabbit, Pet>(m, "Rabbit") py::class_<Rabbit, Pet>(m, "Rabbit").def(py::init<std::string>());
.def(py::init<std::string>());
/* And another: list parent in class template arguments */ /* And another: list parent in class template arguments */
py::class_<Hamster, Pet>(m, "Hamster") py::class_<Hamster, Pet>(m, "Hamster").def(py::init<std::string>());
.def(py::init<std::string>());
/* Constructors are not inherited by default */ /* Constructors are not inherited by default */
py::class_<Chimera, Pet>(m, "Chimera"); py::class_<Chimera, Pet>(m, "Chimera");
m.def("pet_name_species", [](const Pet &pet) { return pet.name() + " is a " + pet.species(); }); m.def("pet_name_species",
[](const Pet &pet) { return pet.name() + " is a " + pet.species(); });
m.def("dog_bark", [](const Dog &dog) { return dog.bark(); }); m.def("dog_bark", [](const Dog &dog) { return dog.bark(); });
// test_automatic_upcasting // test_automatic_upcasting
...@@ -131,15 +130,15 @@ TEST_SUBMODULE(class_, m) { ...@@ -131,15 +130,15 @@ TEST_SUBMODULE(class_, m) {
BaseClass(BaseClass &&) = default; BaseClass(BaseClass &&) = default;
virtual ~BaseClass() = default; virtual ~BaseClass() = default;
}; };
struct DerivedClass1 : BaseClass { }; struct DerivedClass1 : BaseClass {};
struct DerivedClass2 : BaseClass { }; struct DerivedClass2 : BaseClass {};
py::class_<BaseClass>(m, "BaseClass").def(py::init<>()); py::class_<BaseClass>(m, "BaseClass").def(py::init<>());
py::class_<DerivedClass1>(m, "DerivedClass1").def(py::init<>()); py::class_<DerivedClass1>(m, "DerivedClass1").def(py::init<>());
py::class_<DerivedClass2>(m, "DerivedClass2").def(py::init<>()); py::class_<DerivedClass2>(m, "DerivedClass2").def(py::init<>());
m.def("return_class_1", []() -> BaseClass* { return new DerivedClass1(); }); m.def("return_class_1", []() -> BaseClass * { return new DerivedClass1(); });
m.def("return_class_2", []() -> BaseClass* { return new DerivedClass2(); }); m.def("return_class_2", []() -> BaseClass * { return new DerivedClass2(); });
m.def("return_class_n", [](int n) -> BaseClass * { m.def("return_class_n", [](int n) -> BaseClass * {
if (n == 1) { if (n == 1) {
return new DerivedClass1(); return new DerivedClass1();
...@@ -149,19 +148,17 @@ TEST_SUBMODULE(class_, m) { ...@@ -149,19 +148,17 @@ TEST_SUBMODULE(class_, m) {
} }
return new BaseClass(); return new BaseClass();
}); });
m.def("return_none", []() -> BaseClass* { return nullptr; }); m.def("return_none", []() -> BaseClass * { return nullptr; });
// test_isinstance // test_isinstance
m.def("check_instances", [](const py::list &l) { m.def("check_instances", [](const py::list &l) {
return py::make_tuple( return py::make_tuple(py::isinstance<py::tuple>(l[0]),
py::isinstance<py::tuple>(l[0]), py::isinstance<py::dict>(l[1]),
py::isinstance<py::dict>(l[1]), py::isinstance<Pet>(l[2]),
py::isinstance<Pet>(l[2]), py::isinstance<Pet>(l[3]),
py::isinstance<Pet>(l[3]), py::isinstance<Dog>(l[4]),
py::isinstance<Dog>(l[4]), py::isinstance<Rabbit>(l[5]),
py::isinstance<Rabbit>(l[5]), py::isinstance<UnregisteredType>(l[6]));
py::isinstance<UnregisteredType>(l[6])
);
}); });
struct Invalid {}; struct Invalid {};
...@@ -180,18 +177,16 @@ TEST_SUBMODULE(class_, m) { ...@@ -180,18 +177,16 @@ TEST_SUBMODULE(class_, m) {
m.def("get_type_of", [](py::object ob) { return py::type::of(std::move(ob)); }); m.def("get_type_of", [](py::object ob) { return py::type::of(std::move(ob)); });
m.def("get_type_classic", [](py::handle h) { m.def("get_type_classic", [](py::handle h) { return h.get_type(); });
return h.get_type();
});
m.def("as_type", [](const py::object &ob) { return py::type(ob); }); m.def("as_type", [](const py::object &ob) { return py::type(ob); });
// test_mismatched_holder // test_mismatched_holder
struct MismatchBase1 { }; struct MismatchBase1 {};
struct MismatchDerived1 : MismatchBase1 { }; struct MismatchDerived1 : MismatchBase1 {};
struct MismatchBase2 { }; struct MismatchBase2 {};
struct MismatchDerived2 : MismatchBase2 { }; struct MismatchDerived2 : MismatchBase2 {};
m.def("mismatched_holder_1", []() { m.def("mismatched_holder_1", []() {
auto mod = py::module_::import("__main__"); auto mod = py::module_::import("__main__");
...@@ -201,16 +196,14 @@ TEST_SUBMODULE(class_, m) { ...@@ -201,16 +196,14 @@ TEST_SUBMODULE(class_, m) {
m.def("mismatched_holder_2", []() { m.def("mismatched_holder_2", []() {
auto mod = py::module_::import("__main__"); auto mod = py::module_::import("__main__");
py::class_<MismatchBase2>(mod, "MismatchBase2"); py::class_<MismatchBase2>(mod, "MismatchBase2");
py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>, py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>, MismatchBase2>(
MismatchBase2>(mod, "MismatchDerived2"); mod, "MismatchDerived2");
}); });
// test_override_static // test_override_static
// #511: problem with inheritance + overwritten def_static // #511: problem with inheritance + overwritten def_static
struct MyBase { struct MyBase {
static std::unique_ptr<MyBase> make() { static std::unique_ptr<MyBase> make() { return std::unique_ptr<MyBase>(new MyBase()); }
return std::unique_ptr<MyBase>(new MyBase());
}
}; };
struct MyDerived : MyBase { struct MyDerived : MyBase {
...@@ -219,8 +212,7 @@ TEST_SUBMODULE(class_, m) { ...@@ -219,8 +212,7 @@ TEST_SUBMODULE(class_, m) {
} }
}; };
py::class_<MyBase>(m, "MyBase") py::class_<MyBase>(m, "MyBase").def_static("make", &MyBase::make);
.def_static("make", &MyBase::make);
py::class_<MyDerived, MyBase>(m, "MyDerived") py::class_<MyDerived, MyBase>(m, "MyDerived")
.def_static("make", &MyDerived::make) .def_static("make", &MyDerived::make)
...@@ -233,8 +225,7 @@ TEST_SUBMODULE(class_, m) { ...@@ -233,8 +225,7 @@ TEST_SUBMODULE(class_, m) {
explicit ConvertibleFromUserType(UserType u) : i(u.value()) {} explicit ConvertibleFromUserType(UserType u) : i(u.value()) {}
}; };
py::class_<ConvertibleFromUserType>(m, "AcceptsUserType") py::class_<ConvertibleFromUserType>(m, "AcceptsUserType").def(py::init<UserType>());
.def(py::init<UserType>());
py::implicitly_convertible<UserType, ConvertibleFromUserType>(); py::implicitly_convertible<UserType, ConvertibleFromUserType>();
m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; }); m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; });
...@@ -257,31 +248,60 @@ TEST_SUBMODULE(class_, m) { ...@@ -257,31 +248,60 @@ TEST_SUBMODULE(class_, m) {
}; };
auto *def = new PyMethodDef{"f", f, METH_VARARGS, nullptr}; auto *def = new PyMethodDef{"f", f, METH_VARARGS, nullptr};
py::capsule def_capsule(def, [](void *ptr) { delete reinterpret_cast<PyMethodDef *>(ptr); }); py::capsule def_capsule(def,
return py::reinterpret_steal<py::object>(PyCFunction_NewEx(def, def_capsule.ptr(), m.ptr())); [](void *ptr) { delete reinterpret_cast<PyMethodDef *>(ptr); });
return py::reinterpret_steal<py::object>(
PyCFunction_NewEx(def, def_capsule.ptr(), m.ptr()));
}()); }());
// test_operator_new_delete // test_operator_new_delete
struct HasOpNewDel { struct HasOpNewDel {
std::uint64_t i; std::uint64_t i;
static void *operator new(size_t s) { py::print("A new", s); return ::operator new(s); } static void *operator new(size_t s) {
static void *operator new(size_t s, void *ptr) { py::print("A placement-new", s); return ptr; } py::print("A new", s);
static void operator delete(void *p) { py::print("A delete"); return ::operator delete(p); } return ::operator new(s);
}
static void *operator new(size_t s, void *ptr) {
py::print("A placement-new", s);
return ptr;
}
static void operator delete(void *p) {
py::print("A delete");
return ::operator delete(p);
}
}; };
struct HasOpNewDelSize { struct HasOpNewDelSize {
std::uint32_t i; std::uint32_t i;
static void *operator new(size_t s) { py::print("B new", s); return ::operator new(s); } static void *operator new(size_t s) {
static void *operator new(size_t s, void *ptr) { py::print("B placement-new", s); return ptr; } py::print("B new", s);
static void operator delete(void *p, size_t s) { py::print("B delete", s); return ::operator delete(p); } return ::operator new(s);
}
static void *operator new(size_t s, void *ptr) {
py::print("B placement-new", s);
return ptr;
}
static void operator delete(void *p, size_t s) {
py::print("B delete", s);
return ::operator delete(p);
}
}; };
struct AliasedHasOpNewDelSize { struct AliasedHasOpNewDelSize {
std::uint64_t i; std::uint64_t i;
static void *operator new(size_t s) { py::print("C new", s); return ::operator new(s); } static void *operator new(size_t s) {
static void *operator new(size_t s, void *ptr) { py::print("C placement-new", s); return ptr; } py::print("C new", s);
static void operator delete(void *p, size_t s) { py::print("C delete", s); return ::operator delete(p); } return ::operator new(s);
}
static void *operator new(size_t s, void *ptr) {
py::print("C placement-new", s);
return ptr;
}
static void operator delete(void *p, size_t s) {
py::print("C delete", s);
return ::operator delete(p);
}
virtual ~AliasedHasOpNewDelSize() = default; virtual ~AliasedHasOpNewDelSize() = default;
AliasedHasOpNewDelSize() = default; AliasedHasOpNewDelSize() = default;
AliasedHasOpNewDelSize(const AliasedHasOpNewDelSize&) = delete; AliasedHasOpNewDelSize(const AliasedHasOpNewDelSize &) = delete;
}; };
struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize { struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize {
PyAliasedHasOpNewDelSize() = default; PyAliasedHasOpNewDelSize() = default;
...@@ -290,15 +310,28 @@ TEST_SUBMODULE(class_, m) { ...@@ -290,15 +310,28 @@ TEST_SUBMODULE(class_, m) {
}; };
struct HasOpNewDelBoth { struct HasOpNewDelBoth {
std::uint32_t i[8]; std::uint32_t i[8];
static void *operator new(size_t s) { py::print("D new", s); return ::operator new(s); } static void *operator new(size_t s) {
static void *operator new(size_t s, void *ptr) { py::print("D placement-new", s); return ptr; } py::print("D new", s);
static void operator delete(void *p) { py::print("D delete"); return ::operator delete(p); } return ::operator new(s);
static void operator delete(void *p, size_t s) { py::print("D wrong delete", s); return ::operator delete(p); } }
static void *operator new(size_t s, void *ptr) {
py::print("D placement-new", s);
return ptr;
}
static void operator delete(void *p) {
py::print("D delete");
return ::operator delete(p);
}
static void operator delete(void *p, size_t s) {
py::print("D wrong delete", s);
return ::operator delete(p);
}
}; };
py::class_<HasOpNewDel>(m, "HasOpNewDel").def(py::init<>()); py::class_<HasOpNewDel>(m, "HasOpNewDel").def(py::init<>());
py::class_<HasOpNewDelSize>(m, "HasOpNewDelSize").def(py::init<>()); py::class_<HasOpNewDelSize>(m, "HasOpNewDelSize").def(py::init<>());
py::class_<HasOpNewDelBoth>(m, "HasOpNewDelBoth").def(py::init<>()); py::class_<HasOpNewDelBoth>(m, "HasOpNewDelBoth").def(py::init<>());
py::class_<AliasedHasOpNewDelSize, PyAliasedHasOpNewDelSize> aliased(m, "AliasedHasOpNewDelSize"); py::class_<AliasedHasOpNewDelSize, PyAliasedHasOpNewDelSize> aliased(m,
"AliasedHasOpNewDelSize");
aliased.def(py::init<>()); aliased.def(py::init<>());
aliased.attr("size_noalias") = py::int_(sizeof(AliasedHasOpNewDelSize)); aliased.attr("size_noalias") = py::int_(sizeof(AliasedHasOpNewDelSize));
aliased.attr("size_alias") = py::int_(sizeof(PyAliasedHasOpNewDelSize)); aliased.attr("size_alias") = py::int_(sizeof(PyAliasedHasOpNewDelSize));
...@@ -352,7 +385,7 @@ TEST_SUBMODULE(class_, m) { ...@@ -352,7 +385,7 @@ TEST_SUBMODULE(class_, m) {
// [workaround(intel)] = default does not work here // [workaround(intel)] = default does not work here
// Removing or defaulting this destructor results in linking errors with the Intel compiler // Removing or defaulting this destructor results in linking errors with the Intel compiler
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827) // (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
~PublicistB() override {}; // NOLINT(modernize-use-equals-default) ~PublicistB() override{}; // NOLINT(modernize-use-equals-default)
using ProtectedB::foo; using ProtectedB::foo;
}; };
...@@ -402,8 +435,8 @@ TEST_SUBMODULE(class_, m) { ...@@ -402,8 +435,8 @@ TEST_SUBMODULE(class_, m) {
py::class_<Nested>(base, "Nested") py::class_<Nested>(base, "Nested")
.def(py::init<>()) .def(py::init<>())
.def("fn", [](Nested &, int, NestBase &, Nested &) {}) .def("fn", [](Nested &, int, NestBase &, Nested &) {})
.def("fa", [](Nested &, int, NestBase &, Nested &) {}, .def(
"a"_a, "b"_a, "c"_a); "fa", [](Nested &, int, NestBase &, Nested &) {}, "a"_a, "b"_a, "c"_a);
base.def("g", [](NestBase &, Nested &) {}); base.def("g", [](NestBase &, Nested &) {});
base.def("h", []() { return NestBase(); }); base.def("h", []() { return NestBase(); });
...@@ -413,21 +446,21 @@ TEST_SUBMODULE(class_, m) { ...@@ -413,21 +446,21 @@ TEST_SUBMODULE(class_, m) {
// generate a useful error message // generate a useful error message
struct NotRegistered {}; struct NotRegistered {};
struct StringWrapper { std::string str; }; struct StringWrapper {
std::string str;
};
m.def("test_error_after_conversions", [](int) {}); m.def("test_error_after_conversions", [](int) {});
m.def("test_error_after_conversions", m.def("test_error_after_conversions",
[](const StringWrapper &) -> NotRegistered { return {}; }); [](const StringWrapper &) -> NotRegistered { return {}; });
py::class_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>()); py::class_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>());
py::implicitly_convertible<std::string, StringWrapper>(); py::implicitly_convertible<std::string, StringWrapper>();
#if defined(PYBIND11_CPP17) #if defined(PYBIND11_CPP17)
struct alignas(1024) Aligned { struct alignas(1024) Aligned {
std::uintptr_t ptr() const { return (uintptr_t) this; } std::uintptr_t ptr() const { return (uintptr_t) this; }
}; };
py::class_<Aligned>(m, "Aligned") py::class_<Aligned>(m, "Aligned").def(py::init<>()).def("ptr", &Aligned::ptr);
.def(py::init<>()) #endif
.def("ptr", &Aligned::ptr);
#endif
// test_final // test_final
struct IsFinal final {}; struct IsFinal final {};
...@@ -440,9 +473,7 @@ TEST_SUBMODULE(class_, m) { ...@@ -440,9 +473,7 @@ TEST_SUBMODULE(class_, m) {
// test_exception_rvalue_abort // test_exception_rvalue_abort
struct PyPrintDestructor { struct PyPrintDestructor {
PyPrintDestructor() = default; PyPrintDestructor() = default;
~PyPrintDestructor() { ~PyPrintDestructor() { py::print("Print from destructor"); }
py::print("Print from destructor");
}
void throw_something() { throw std::runtime_error("error"); } void throw_something() { throw std::runtime_error("error"); }
}; };
py::class_<PyPrintDestructor>(m, "PyPrintDestructor") py::class_<PyPrintDestructor>(m, "PyPrintDestructor")
...@@ -456,8 +487,7 @@ TEST_SUBMODULE(class_, m) { ...@@ -456,8 +487,7 @@ TEST_SUBMODULE(class_, m) {
.def(py::init([]() { return &samePointer; })); .def(py::init([]() { return &samePointer; }));
struct Empty {}; struct Empty {};
py::class_<Empty>(m, "Empty") py::class_<Empty>(m, "Empty").def(py::init<>());
.def(py::init<>());
// test_base_and_derived_nested_scope // test_base_and_derived_nested_scope
struct BaseWithNested { struct BaseWithNested {
...@@ -499,12 +529,15 @@ TEST_SUBMODULE(class_, m) { ...@@ -499,12 +529,15 @@ TEST_SUBMODULE(class_, m) {
}); });
} }
template <int N> class BreaksBase { public: template <int N>
class BreaksBase {
public:
virtual ~BreaksBase() = default; virtual ~BreaksBase() = default;
BreaksBase() = default; BreaksBase() = default;
BreaksBase(const BreaksBase&) = delete; BreaksBase(const BreaksBase &) = delete;
}; };
template <int N> class BreaksTramp : public BreaksBase<N> {}; template <int N>
class BreaksTramp : public BreaksBase<N> {};
// These should all compile just fine: // These should all compile just fine:
using DoesntBreak1 = py::class_<BreaksBase<1>, std::unique_ptr<BreaksBase<1>>, BreaksTramp<1>>; using DoesntBreak1 = py::class_<BreaksBase<1>, std::unique_ptr<BreaksBase<1>>, BreaksTramp<1>>;
using DoesntBreak2 = py::class_<BreaksBase<2>, BreaksTramp<2>, std::unique_ptr<BreaksBase<2>>>; using DoesntBreak2 = py::class_<BreaksBase<2>, BreaksTramp<2>, std::unique_ptr<BreaksBase<2>>>;
...@@ -514,45 +547,83 @@ using DoesntBreak5 = py::class_<BreaksBase<5>>; ...@@ -514,45 +547,83 @@ using DoesntBreak5 = py::class_<BreaksBase<5>>;
using DoesntBreak6 = py::class_<BreaksBase<6>, std::shared_ptr<BreaksBase<6>>, BreaksTramp<6>>; using DoesntBreak6 = py::class_<BreaksBase<6>, std::shared_ptr<BreaksBase<6>>, BreaksTramp<6>>;
using DoesntBreak7 = py::class_<BreaksBase<7>, BreaksTramp<7>, std::shared_ptr<BreaksBase<7>>>; using DoesntBreak7 = py::class_<BreaksBase<7>, BreaksTramp<7>, std::shared_ptr<BreaksBase<7>>>;
using DoesntBreak8 = py::class_<BreaksBase<8>, std::shared_ptr<BreaksBase<8>>>; using DoesntBreak8 = py::class_<BreaksBase<8>, std::shared_ptr<BreaksBase<8>>>;
#define CHECK_BASE(N) static_assert(std::is_same<typename DoesntBreak##N::type, BreaksBase<(N)>>::value, \ #define CHECK_BASE(N) \
"DoesntBreak" #N " has wrong type!") static_assert(std::is_same<typename DoesntBreak##N::type, BreaksBase<(N)>>::value, \
CHECK_BASE(1); CHECK_BASE(2); CHECK_BASE(3); CHECK_BASE(4); CHECK_BASE(5); CHECK_BASE(6); CHECK_BASE(7); CHECK_BASE(8); "DoesntBreak" #N " has wrong type!")
#define CHECK_ALIAS(N) static_assert(DoesntBreak##N::has_alias && std::is_same<typename DoesntBreak##N::type_alias, BreaksTramp<(N)>>::value, \ CHECK_BASE(1);
CHECK_BASE(2);
CHECK_BASE(3);
CHECK_BASE(4);
CHECK_BASE(5);
CHECK_BASE(6);
CHECK_BASE(7);
CHECK_BASE(8);
#define CHECK_ALIAS(N) \
static_assert( \
DoesntBreak##N::has_alias \
&& std::is_same<typename DoesntBreak##N::type_alias, BreaksTramp<(N)>>::value, \
"DoesntBreak" #N " has wrong type_alias!") "DoesntBreak" #N " has wrong type_alias!")
#define CHECK_NOALIAS(N) static_assert(!DoesntBreak##N::has_alias && std::is_void<typename DoesntBreak##N::type_alias>::value, \ #define CHECK_NOALIAS(N) \
"DoesntBreak" #N " has type alias, but shouldn't!") static_assert(!DoesntBreak##N::has_alias \
CHECK_ALIAS(1); CHECK_ALIAS(2); CHECK_NOALIAS(3); CHECK_ALIAS(4); CHECK_NOALIAS(5); CHECK_ALIAS(6); CHECK_ALIAS(7); CHECK_NOALIAS(8); && std::is_void<typename DoesntBreak##N::type_alias>::value, \
#define CHECK_HOLDER(N, TYPE) static_assert(std::is_same<typename DoesntBreak##N::holder_type, std::TYPE##_ptr<BreaksBase<(N)>>>::value, \ "DoesntBreak" #N " has type alias, but shouldn't!")
"DoesntBreak" #N " has wrong holder_type!") CHECK_ALIAS(1);
CHECK_HOLDER(1, unique); CHECK_HOLDER(2, unique); CHECK_HOLDER(3, unique); CHECK_HOLDER(4, unique); CHECK_HOLDER(5, unique); CHECK_ALIAS(2);
CHECK_HOLDER(6, shared); CHECK_HOLDER(7, shared); CHECK_HOLDER(8, shared); CHECK_NOALIAS(3);
CHECK_ALIAS(4);
CHECK_NOALIAS(5);
CHECK_ALIAS(6);
CHECK_ALIAS(7);
CHECK_NOALIAS(8);
#define CHECK_HOLDER(N, TYPE) \
static_assert(std::is_same<typename DoesntBreak##N::holder_type, \
std::TYPE##_ptr<BreaksBase<(N)>>>::value, \
"DoesntBreak" #N " has wrong holder_type!")
CHECK_HOLDER(1, unique);
CHECK_HOLDER(2, unique);
CHECK_HOLDER(3, unique);
CHECK_HOLDER(4, unique);
CHECK_HOLDER(5, unique);
CHECK_HOLDER(6, shared);
CHECK_HOLDER(7, shared);
CHECK_HOLDER(8, shared);
// There's no nice way to test that these fail because they fail to compile; leave them here, // There's no nice way to test that these fail because they fail to compile; leave them here,
// though, so that they can be manually tested by uncommenting them (and seeing that compilation // though, so that they can be manually tested by uncommenting them (and seeing that compilation
// failures occurs). // failures occurs).
// We have to actually look into the type: the typedef alone isn't enough to instantiate the type: // We have to actually look into the type: the typedef alone isn't enough to instantiate the type:
#define CHECK_BROKEN(N) static_assert(std::is_same<typename Breaks##N::type, BreaksBase<-(N)>>::value, \ #define CHECK_BROKEN(N) \
"Breaks1 has wrong type!"); static_assert(std::is_same<typename Breaks##N::type, BreaksBase<-(N)>>::value, \
"Breaks1 has wrong type!");
#ifdef PYBIND11_NEVER_DEFINED_EVER #ifdef PYBIND11_NEVER_DEFINED_EVER
// Two holder classes: // Two holder classes:
typedef py::class_<BreaksBase<-1>, std::unique_ptr<BreaksBase<-1>>, std::unique_ptr<BreaksBase<-1>>> Breaks1; typedef py::
class_<BreaksBase<-1>, std::unique_ptr<BreaksBase<-1>>, std::unique_ptr<BreaksBase<-1>>>
Breaks1;
CHECK_BROKEN(1); CHECK_BROKEN(1);
// Two aliases: // Two aliases:
typedef py::class_<BreaksBase<-2>, BreaksTramp<-2>, BreaksTramp<-2>> Breaks2; typedef py::class_<BreaksBase<-2>, BreaksTramp<-2>, BreaksTramp<-2>> Breaks2;
CHECK_BROKEN(2); CHECK_BROKEN(2);
// Holder + 2 aliases // Holder + 2 aliases
typedef py::class_<BreaksBase<-3>, std::unique_ptr<BreaksBase<-3>>, BreaksTramp<-3>, BreaksTramp<-3>> Breaks3; typedef py::
class_<BreaksBase<-3>, std::unique_ptr<BreaksBase<-3>>, BreaksTramp<-3>, BreaksTramp<-3>>
Breaks3;
CHECK_BROKEN(3); CHECK_BROKEN(3);
// Alias + 2 holders // Alias + 2 holders
typedef py::class_<BreaksBase<-4>, std::unique_ptr<BreaksBase<-4>>, BreaksTramp<-4>, std::shared_ptr<BreaksBase<-4>>> Breaks4; typedef py::class_<BreaksBase<-4>,
std::unique_ptr<BreaksBase<-4>>,
BreaksTramp<-4>,
std::shared_ptr<BreaksBase<-4>>>
Breaks4;
CHECK_BROKEN(4); CHECK_BROKEN(4);
// Invalid option (not a subclass or holder) // Invalid option (not a subclass or holder)
typedef py::class_<BreaksBase<-5>, BreaksTramp<-4>> Breaks5; typedef py::class_<BreaksBase<-5>, BreaksTramp<-4>> Breaks5;
CHECK_BROKEN(5); CHECK_BROKEN(5);
// Invalid option: multiple inheritance not supported: // Invalid option: multiple inheritance not supported:
template <> struct BreaksBase<-8> : BreaksBase<-6>, BreaksBase<-7> {}; template <>
struct BreaksBase<-8> : BreaksBase<-6>, BreaksBase<-7> {};
typedef py::class_<BreaksBase<-8>, BreaksBase<-6>, BreaksBase<-7>> Breaks8; typedef py::class_<BreaksBase<-8>, BreaksBase<-6>, BreaksBase<-7>> Breaks8;
CHECK_BROKEN(8); CHECK_BROKEN(8);
#endif #endif
...@@ -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(
......
...@@ -8,30 +8,33 @@ ...@@ -8,30 +8,33 @@
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"
template <typename derived> template <typename derived>
struct empty { struct empty {
static const derived& get_one() { return instance_; } static const derived &get_one() { return instance_; }
static derived instance_; static derived instance_;
}; };
struct lacking_copy_ctor : public empty<lacking_copy_ctor> { struct lacking_copy_ctor : public empty<lacking_copy_ctor> {
lacking_copy_ctor() = default; lacking_copy_ctor() = default;
lacking_copy_ctor(const lacking_copy_ctor& other) = delete; lacking_copy_ctor(const lacking_copy_ctor &other) = delete;
}; };
template <> lacking_copy_ctor empty<lacking_copy_ctor>::instance_ = {}; template <>
lacking_copy_ctor empty<lacking_copy_ctor>::instance_ = {};
struct lacking_move_ctor : public empty<lacking_move_ctor> { struct lacking_move_ctor : public empty<lacking_move_ctor> {
lacking_move_ctor() = default; lacking_move_ctor() = default;
lacking_move_ctor(const lacking_move_ctor& other) = delete; lacking_move_ctor(const lacking_move_ctor &other) = delete;
lacking_move_ctor(lacking_move_ctor&& other) = delete; lacking_move_ctor(lacking_move_ctor &&other) = delete;
}; };
template <> lacking_move_ctor empty<lacking_move_ctor>::instance_ = {}; template <>
lacking_move_ctor empty<lacking_move_ctor>::instance_ = {};
/* Custom type caster move/copy test classes */ /* Custom type caster move/copy test classes */
class MoveOnlyInt { class MoveOnlyInt {
...@@ -71,7 +74,11 @@ public: ...@@ -71,7 +74,11 @@ public:
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
value = c.value; value = c.value;
} }
MoveOrCopyInt &operator=(const MoveOrCopyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; } MoveOrCopyInt &operator=(const MoveOrCopyInt &c) {
print_copy_assigned(this, c.value);
value = c.value;
return *this;
}
~MoveOrCopyInt() { print_destroyed(this); } ~MoveOrCopyInt() { print_destroyed(this); }
int value; int value;
...@@ -85,32 +92,55 @@ public: ...@@ -85,32 +92,55 @@ public:
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
value = c.value; value = c.value;
} }
CopyOnlyInt &operator=(const CopyOnlyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; } CopyOnlyInt &operator=(const CopyOnlyInt &c) {
print_copy_assigned(this, c.value);
value = c.value;
return *this;
}
~CopyOnlyInt() { print_destroyed(this); } ~CopyOnlyInt() { print_destroyed(this); }
int value; int value;
}; };
PYBIND11_NAMESPACE_BEGIN(pybind11) PYBIND11_NAMESPACE_BEGIN(pybind11)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
template <> struct type_caster<MoveOnlyInt> { template <>
struct type_caster<MoveOnlyInt> {
PYBIND11_TYPE_CASTER(MoveOnlyInt, const_name("MoveOnlyInt")); PYBIND11_TYPE_CASTER(MoveOnlyInt, const_name("MoveOnlyInt"));
bool load(handle src, bool) { value = MoveOnlyInt(src.cast<int>()); return true; } bool load(handle src, bool) {
static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); } value = MoveOnlyInt(src.cast<int>());
return true;
}
static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p) {
return pybind11::cast(m.value, r, p);
}
}; };
template <> struct type_caster<MoveOrCopyInt> { template <>
struct type_caster<MoveOrCopyInt> {
PYBIND11_TYPE_CASTER(MoveOrCopyInt, const_name("MoveOrCopyInt")); PYBIND11_TYPE_CASTER(MoveOrCopyInt, const_name("MoveOrCopyInt"));
bool load(handle src, bool) { value = MoveOrCopyInt(src.cast<int>()); return true; } bool load(handle src, bool) {
static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); } value = MoveOrCopyInt(src.cast<int>());
return true;
}
static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p) {
return pybind11::cast(m.value, r, p);
}
}; };
template <> struct type_caster<CopyOnlyInt> { template <>
struct type_caster<CopyOnlyInt> {
protected: protected:
CopyOnlyInt value; CopyOnlyInt value;
public: public:
static constexpr auto name = const_name("CopyOnlyInt"); static constexpr auto name = const_name("CopyOnlyInt");
bool load(handle src, bool) { value = CopyOnlyInt(src.cast<int>()); return true; } bool load(handle src, bool) {
static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); } value = CopyOnlyInt(src.cast<int>());
return true;
}
static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p) {
return pybind11::cast(m.value, r, p);
}
static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) { static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) {
if (!src) { if (!src) {
return none().release(); return none().release();
...@@ -119,7 +149,8 @@ public: ...@@ -119,7 +149,8 @@ public:
} }
explicit operator CopyOnlyInt *() { return &value; } explicit operator CopyOnlyInt *() { return &value; }
explicit operator CopyOnlyInt &() { return value; } explicit operator CopyOnlyInt &() { return value; }
template <typename T> using cast_op_type = pybind11::detail::cast_op_type<T>; template <typename T>
using cast_op_type = pybind11::detail::cast_op_type<T>;
}; };
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(pybind11) PYBIND11_NAMESPACE_END(pybind11)
...@@ -127,23 +158,21 @@ PYBIND11_NAMESPACE_END(pybind11) ...@@ -127,23 +158,21 @@ PYBIND11_NAMESPACE_END(pybind11)
TEST_SUBMODULE(copy_move_policies, m) { TEST_SUBMODULE(copy_move_policies, m) {
// test_lacking_copy_ctor // test_lacking_copy_ctor
py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor") py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
.def_static("get_one", &lacking_copy_ctor::get_one, .def_static("get_one", &lacking_copy_ctor::get_one, py::return_value_policy::copy);
py::return_value_policy::copy);
// test_lacking_move_ctor // test_lacking_move_ctor
py::class_<lacking_move_ctor>(m, "lacking_move_ctor") py::class_<lacking_move_ctor>(m, "lacking_move_ctor")
.def_static("get_one", &lacking_move_ctor::get_one, .def_static("get_one", &lacking_move_ctor::get_one, py::return_value_policy::move);
py::return_value_policy::move);
// test_move_and_copy_casts // test_move_and_copy_casts
// NOLINTNEXTLINE(performance-unnecessary-value-param) // NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("move_and_copy_casts", [](const py::object &o) { m.def("move_and_copy_casts", [](const py::object &o) {
int r = 0; int r = 0;
r += py::cast<MoveOrCopyInt>(o).value; /* moves */ r += py::cast<MoveOrCopyInt>(o).value; /* moves */
r += py::cast<MoveOnlyInt>(o).value; /* moves */ r += py::cast<MoveOnlyInt>(o).value; /* moves */
r += py::cast<CopyOnlyInt>(o).value; /* copies */ r += py::cast<CopyOnlyInt>(o).value; /* copies */
auto m1(py::cast<MoveOrCopyInt>(o)); /* moves */ auto m1(py::cast<MoveOrCopyInt>(o)); /* moves */
auto m2(py::cast<MoveOnlyInt>(o)); /* moves */ auto m2(py::cast<MoveOnlyInt>(o)); /* moves */
auto m3(py::cast<CopyOnlyInt>(o)); /* copies */ auto m3(py::cast<CopyOnlyInt>(o)); /* copies */
r += m1.value + m2.value + m3.value; r += m1.value + m2.value + m3.value;
return r; return r;
...@@ -157,28 +186,34 @@ TEST_SUBMODULE(copy_move_policies, m) { ...@@ -157,28 +186,34 @@ TEST_SUBMODULE(copy_move_policies, m) {
// Changing this breaks the existing test: needs careful review. // Changing this breaks the existing test: needs careful review.
// NOLINTNEXTLINE(performance-unnecessary-value-param) // NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("copy_only", [](CopyOnlyInt m) { return m.value; }); m.def("copy_only", [](CopyOnlyInt m) { return m.value; });
m.def("move_pair", [](std::pair<MoveOnlyInt, MoveOrCopyInt> p) { m.def("move_pair",
return p.first.value + p.second.value; [](std::pair<MoveOnlyInt, MoveOrCopyInt> p) { return p.first.value + p.second.value; });
});
m.def("move_tuple", [](std::tuple<MoveOnlyInt, MoveOrCopyInt, MoveOnlyInt> t) { m.def("move_tuple", [](std::tuple<MoveOnlyInt, MoveOrCopyInt, MoveOnlyInt> t) {
return std::get<0>(t).value + std::get<1>(t).value + std::get<2>(t).value; return std::get<0>(t).value + std::get<1>(t).value + std::get<2>(t).value;
}); });
m.def("copy_tuple", [](std::tuple<CopyOnlyInt, CopyOnlyInt> t) { m.def("copy_tuple", [](std::tuple<CopyOnlyInt, CopyOnlyInt> t) {
return std::get<0>(t).value + std::get<1>(t).value; return std::get<0>(t).value + std::get<1>(t).value;
}); });
m.def("move_copy_nested", [](std::pair<MoveOnlyInt, std::pair<std::tuple<MoveOrCopyInt, CopyOnlyInt, std::tuple<MoveOnlyInt>>, MoveOrCopyInt>> x) { m.def("move_copy_nested",
return x.first.value + std::get<0>(x.second.first).value + std::get<1>(x.second.first).value + [](std::pair<MoveOnlyInt,
std::get<0>(std::get<2>(x.second.first)).value + x.second.second.value; std::pair<std::tuple<MoveOrCopyInt, CopyOnlyInt, std::tuple<MoveOnlyInt>>,
}); MoveOrCopyInt>> x) {
return x.first.value + std::get<0>(x.second.first).value
+ std::get<1>(x.second.first).value
+ std::get<0>(std::get<2>(x.second.first)).value + x.second.second.value;
});
m.def("move_and_copy_cstats", []() { m.def("move_and_copy_cstats", []() {
ConstructorStats::gc(); ConstructorStats::gc();
// Reset counts to 0 so that previous tests don't affect later ones: // Reset counts to 0 so that previous tests don't affect later ones:
auto &mc = ConstructorStats::get<MoveOrCopyInt>(); auto &mc = ConstructorStats::get<MoveOrCopyInt>();
mc.move_assignments = mc.move_constructions = mc.copy_assignments = mc.copy_constructions = 0; mc.move_assignments = mc.move_constructions = mc.copy_assignments = mc.copy_constructions
= 0;
auto &mo = ConstructorStats::get<MoveOnlyInt>(); auto &mo = ConstructorStats::get<MoveOnlyInt>();
mo.move_assignments = mo.move_constructions = mo.copy_assignments = mo.copy_constructions = 0; mo.move_assignments = mo.move_constructions = mo.copy_assignments = mo.copy_constructions
= 0;
auto &co = ConstructorStats::get<CopyOnlyInt>(); auto &co = ConstructorStats::get<CopyOnlyInt>();
co.move_assignments = co.move_constructions = co.copy_assignments = co.copy_constructions = 0; co.move_assignments = co.move_constructions = co.copy_assignments = co.copy_constructions
= 0;
py::dict d; py::dict d;
d["MoveOrCopyInt"] = py::cast(mc, py::return_value_policy::reference); d["MoveOrCopyInt"] = py::cast(mc, py::return_value_policy::reference);
d["MoveOnlyInt"] = py::cast(mo, py::return_value_policy::reference); d["MoveOnlyInt"] = py::cast(mo, py::return_value_policy::reference);
...@@ -188,18 +223,13 @@ TEST_SUBMODULE(copy_move_policies, m) { ...@@ -188,18 +223,13 @@ TEST_SUBMODULE(copy_move_policies, m) {
#ifdef PYBIND11_HAS_OPTIONAL #ifdef PYBIND11_HAS_OPTIONAL
// test_move_and_copy_load_optional // test_move_and_copy_load_optional
m.attr("has_optional") = true; m.attr("has_optional") = true;
m.def("move_optional", [](std::optional<MoveOnlyInt> o) { m.def("move_optional", [](std::optional<MoveOnlyInt> o) { return o->value; });
return o->value; m.def("move_or_copy_optional", [](std::optional<MoveOrCopyInt> o) { return o->value; });
}); m.def("copy_optional", [](std::optional<CopyOnlyInt> o) { return o->value; });
m.def("move_or_copy_optional", [](std::optional<MoveOrCopyInt> o) { m.def("move_optional_tuple",
return o->value; [](std::optional<std::tuple<MoveOrCopyInt, MoveOnlyInt, CopyOnlyInt>> x) {
}); return std::get<0>(*x).value + std::get<1>(*x).value + std::get<2>(*x).value;
m.def("copy_optional", [](std::optional<CopyOnlyInt> o) { });
return o->value;
});
m.def("move_optional_tuple", [](std::optional<std::tuple<MoveOrCopyInt, MoveOnlyInt, CopyOnlyInt>> x) {
return std::get<0>(*x).value + std::get<1>(*x).value + std::get<2>(*x).value;
});
#else #else
m.attr("has_optional") = false; m.attr("has_optional") = false;
#endif #endif
...@@ -210,6 +240,7 @@ TEST_SUBMODULE(copy_move_policies, m) { ...@@ -210,6 +240,7 @@ TEST_SUBMODULE(copy_move_policies, m) {
// added later. // added later.
struct PrivateOpNew { struct PrivateOpNew {
int value = 1; int value = 1;
private: private:
void *operator new(size_t bytes) { void *operator new(size_t bytes) {
void *ptr = std::malloc(bytes); void *ptr = std::malloc(bytes);
...@@ -221,10 +252,13 @@ TEST_SUBMODULE(copy_move_policies, m) { ...@@ -221,10 +252,13 @@ TEST_SUBMODULE(copy_move_policies, m) {
}; };
py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value); py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
m.def("private_op_new_value", []() { return PrivateOpNew(); }); m.def("private_op_new_value", []() { return PrivateOpNew(); });
m.def("private_op_new_reference", []() -> const PrivateOpNew & { m.def(
static PrivateOpNew x{}; "private_op_new_reference",
return x; []() -> const PrivateOpNew & {
}, py::return_value_policy::reference); static PrivateOpNew x{};
return x;
},
py::return_value_policy::reference);
// test_move_fallback // test_move_fallback
// #389: rvp::move should fall-through to copy on non-movable objects // #389: rvp::move should fall-through to copy on non-movable objects
...@@ -234,16 +268,25 @@ TEST_SUBMODULE(copy_move_policies, m) { ...@@ -234,16 +268,25 @@ TEST_SUBMODULE(copy_move_policies, m) {
MoveIssue1(const MoveIssue1 &c) = default; MoveIssue1(const MoveIssue1 &c) = default;
MoveIssue1(MoveIssue1 &&) = delete; MoveIssue1(MoveIssue1 &&) = delete;
}; };
py::class_<MoveIssue1>(m, "MoveIssue1").def(py::init<int>()).def_readwrite("value", &MoveIssue1::v); py::class_<MoveIssue1>(m, "MoveIssue1")
.def(py::init<int>())
.def_readwrite("value", &MoveIssue1::v);
struct MoveIssue2 { struct MoveIssue2 {
int v; int v;
explicit MoveIssue2(int v) : v{v} {} explicit MoveIssue2(int v) : v{v} {}
MoveIssue2(MoveIssue2 &&) = default; MoveIssue2(MoveIssue2 &&) = default;
}; };
py::class_<MoveIssue2>(m, "MoveIssue2").def(py::init<int>()).def_readwrite("value", &MoveIssue2::v); py::class_<MoveIssue2>(m, "MoveIssue2")
.def(py::init<int>())
.def_readwrite("value", &MoveIssue2::v);
// #2742: Don't expect ownership of raw pointer to `new`ed object to be transferred with `py::return_value_policy::move` // #2742: Don't expect ownership of raw pointer to `new`ed object to be transferred with
m.def("get_moveissue1", [](int i) { return std::unique_ptr<MoveIssue1>(new MoveIssue1(i)); }, py::return_value_policy::move); // `py::return_value_policy::move`
m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move); m.def(
"get_moveissue1",
[](int i) { return std::unique_ptr<MoveIssue1>(new MoveIssue1(i)); },
py::return_value_policy::move);
m.def(
"get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
} }
...@@ -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");
} }
} }
...@@ -7,27 +7,27 @@ ...@@ -7,27 +7,27 @@
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/eigen.h> #include <pybind11/eigen.h>
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include "constructor_stats.h"
#include "pybind11_tests.h"
#if defined(_MSC_VER) #if defined(_MSC_VER)
#if _MSC_VER < 1910 // VS 2015's MSVC # if _MSC_VER < 1910 // VS 2015's MSVC
# pragma warning(disable: 4127) // C4127: conditional expression is constant # pragma warning(disable : 4127) // C4127: conditional expression is constant
#endif # endif
# pragma warning(disable: 4996) // C4996: std::unary_negation is deprecated # pragma warning(disable : 4996) // C4996: std::unary_negation is deprecated
#endif #endif
#include <Eigen/Cholesky> #include <Eigen/Cholesky>
using MatrixXdR = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>; using MatrixXdR = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
// Sets/resets a testing reference matrix to have values of 10*r + c, where r and c are the // Sets/resets a testing reference matrix to have values of 10*r + c, where r and c are the
// (1-based) row/column number. // (1-based) row/column number.
template <typename M> void reset_ref(M &x) { template <typename M>
void reset_ref(M &x) {
for (int i = 0; i < x.rows(); i++) { for (int i = 0; i < x.rows(); i++) {
for (int j = 0; j < x.cols(); j++) { for (int j = 0; j < x.cols(); j++) {
x(i, j) = 11 + 10 * i + j; x(i, j) = 11 + 10 * i + j;
...@@ -64,7 +64,8 @@ double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); }; ...@@ -64,7 +64,8 @@ double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); };
// Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix // Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix
// reference is referencing rows/columns correctly). // reference is referencing rows/columns correctly).
template <typename MatrixArgType> Eigen::MatrixXd adjust_matrix(MatrixArgType m) { template <typename MatrixArgType>
Eigen::MatrixXd adjust_matrix(MatrixArgType m) {
Eigen::MatrixXd ret(m); Eigen::MatrixXd ret(m);
for (int c = 0; c < m.cols(); c++) { for (int c = 0; c < m.cols(); c++) {
for (int r = 0; r < m.rows(); r++) { for (int r = 0; r < m.rows(); r++) {
...@@ -97,8 +98,10 @@ TEST_SUBMODULE(eigen, m) { ...@@ -97,8 +98,10 @@ TEST_SUBMODULE(eigen, m) {
// various tests // various tests
m.def("double_col", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2.0f * x; }); m.def("double_col", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2.0f * x; });
m.def("double_row", [](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2.0f * x; }); m.def("double_row",
m.def("double_complex", [](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; }); [](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2.0f * x; });
m.def("double_complex",
[](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; });
m.def("double_threec", [](py::EigenDRef<Eigen::Vector3f> x) { x *= 2; }); m.def("double_threec", [](py::EigenDRef<Eigen::Vector3f> x) { x *= 2; });
m.def("double_threer", [](py::EigenDRef<Eigen::RowVector3f> x) { x *= 2; }); m.def("double_threer", [](py::EigenDRef<Eigen::RowVector3f> x) { x *= 2; });
m.def("double_mat_cm", [](const Eigen::MatrixXf &x) -> Eigen::MatrixXf { return 2.0f * x; }); m.def("double_mat_cm", [](const Eigen::MatrixXf &x) -> Eigen::MatrixXf { return 2.0f * x; });
...@@ -108,19 +111,22 @@ TEST_SUBMODULE(eigen, m) { ...@@ -108,19 +111,22 @@ TEST_SUBMODULE(eigen, m) {
// Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended // Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended
m.def("cholesky1", m.def("cholesky1",
[](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); [](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
m.def("cholesky2", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky2", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd {
m.def("cholesky3", [](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); return x.llt().matrixL();
});
m.def("cholesky3",
[](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
m.def("cholesky4", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd { m.def("cholesky4", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd {
return x.llt().matrixL(); return x.llt().matrixL();
}); });
// test_eigen_ref_mutators // test_eigen_ref_mutators
// Mutators: these add some value to the given element using Eigen, but Eigen should be mapping into // Mutators: these add some value to the given element using Eigen, but Eigen should be mapping
// the numpy array data and so the result should show up there. There are three versions: one that // into the numpy array data and so the result should show up there. There are three versions:
// works on a contiguous-row matrix (numpy's default), one for a contiguous-column matrix, and one // one that works on a contiguous-row matrix (numpy's default), one for a contiguous-column
// for any matrix. // matrix, and one for any matrix.
auto add_rm = [](Eigen::Ref<MatrixXdR> x, int r, int c, double v) { x(r,c) += v; }; auto add_rm = [](Eigen::Ref<MatrixXdR> x, int r, int c, double v) { x(r, c) += v; };
auto add_cm = [](Eigen::Ref<Eigen::MatrixXd> x, int r, int c, double v) { x(r,c) += v; }; auto add_cm = [](Eigen::Ref<Eigen::MatrixXd> x, int r, int c, double v) { x(r, c) += v; };
// Mutators (Eigen maps into numpy variables): // Mutators (Eigen maps into numpy variables):
m.def("add_rm", add_rm); // Only takes row-contiguous m.def("add_rm", add_rm); // Only takes row-contiguous
...@@ -131,7 +137,8 @@ TEST_SUBMODULE(eigen, m) { ...@@ -131,7 +137,8 @@ TEST_SUBMODULE(eigen, m) {
m.def("add2", add_cm); m.def("add2", add_cm);
m.def("add2", add_rm); m.def("add2", add_rm);
// This one accepts a matrix of any stride: // This one accepts a matrix of any stride:
m.def("add_any", [](py::EigenDRef<Eigen::MatrixXd> x, int r, int c, double v) { x(r,c) += v; }); m.def("add_any",
[](py::EigenDRef<Eigen::MatrixXd> x, int r, int c, double v) { x(r, c) += v; });
// Return mutable references (numpy maps into eigen variables) // Return mutable references (numpy maps into eigen variables)
m.def("get_cm_ref", []() { return Eigen::Ref<Eigen::MatrixXd>(get_cm()); }); m.def("get_cm_ref", []() { return Eigen::Ref<Eigen::MatrixXd>(get_cm()); });
...@@ -143,45 +150,67 @@ TEST_SUBMODULE(eigen, m) { ...@@ -143,45 +150,67 @@ TEST_SUBMODULE(eigen, m) {
m.def("reset_refs", reset_refs); // Restores get_{cm,rm}_ref to original values m.def("reset_refs", reset_refs); // Restores get_{cm,rm}_ref to original values
// Increments and returns ref to (same) matrix // Increments and returns ref to (same) matrix
m.def("incr_matrix", [](Eigen::Ref<Eigen::MatrixXd> m, double v) { m.def(
m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v); "incr_matrix",
return m; [](Eigen::Ref<Eigen::MatrixXd> m, double v) {
}, py::return_value_policy::reference); m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v);
return m;
},
py::return_value_policy::reference);
// Same, but accepts a matrix of any strides // Same, but accepts a matrix of any strides
m.def("incr_matrix_any", [](py::EigenDRef<Eigen::MatrixXd> m, double v) { m.def(
m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v); "incr_matrix_any",
return m; [](py::EigenDRef<Eigen::MatrixXd> m, double v) {
}, py::return_value_policy::reference); m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v);
return m;
},
py::return_value_policy::reference);
// Returns an eigen slice of even rows // Returns an eigen slice of even rows
m.def("even_rows", [](py::EigenDRef<Eigen::MatrixXd> m) { m.def(
return py::EigenDMap<Eigen::MatrixXd>( "even_rows",
m.data(), (m.rows() + 1) / 2, m.cols(), [](py::EigenDRef<Eigen::MatrixXd> m) {
return py::EigenDMap<Eigen::MatrixXd>(
m.data(),
(m.rows() + 1) / 2,
m.cols(),
py::EigenDStride(m.outerStride(), 2 * m.innerStride())); py::EigenDStride(m.outerStride(), 2 * m.innerStride()));
}, py::return_value_policy::reference); },
py::return_value_policy::reference);
// Returns an eigen slice of even columns // Returns an eigen slice of even columns
m.def("even_cols", [](py::EigenDRef<Eigen::MatrixXd> m) { m.def(
return py::EigenDMap<Eigen::MatrixXd>( "even_cols",
m.data(), m.rows(), (m.cols() + 1) / 2, [](py::EigenDRef<Eigen::MatrixXd> m) {
return py::EigenDMap<Eigen::MatrixXd>(
m.data(),
m.rows(),
(m.cols() + 1) / 2,
py::EigenDStride(2 * m.outerStride(), m.innerStride())); py::EigenDStride(2 * m.outerStride(), m.innerStride()));
}, py::return_value_policy::reference); },
py::return_value_policy::reference);
// Returns diagonals: a vector-like object with an inner stride != 1 // Returns diagonals: a vector-like object with an inner stride != 1
m.def("diagonal", [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal(); }); m.def("diagonal", [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal(); });
m.def("diagonal_1", [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal<1>(); }); m.def("diagonal_1",
m.def("diagonal_n", [](const Eigen::Ref<const Eigen::MatrixXd> &x, int index) { return x.diagonal(index); }); [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal<1>(); });
m.def("diagonal_n",
[](const Eigen::Ref<const Eigen::MatrixXd> &x, int index) { return x.diagonal(index); });
// Return a block of a matrix (gives non-standard strides) // Return a block of a matrix (gives non-standard strides)
m.def("block", [](const Eigen::Ref<const Eigen::MatrixXd> &x, int start_row, int start_col, int block_rows, int block_cols) { m.def("block",
return x.block(start_row, start_col, block_rows, block_cols); [](const Eigen::Ref<const Eigen::MatrixXd> &x,
}); int start_row,
int start_col,
int block_rows,
int block_cols) { return x.block(start_row, start_col, block_rows, block_cols); });
// test_eigen_return_references, test_eigen_keepalive // test_eigen_return_references, test_eigen_keepalive
// return value referencing/copying tests: // return value referencing/copying tests:
class ReturnTester { class ReturnTester {
Eigen::MatrixXd mat = create(); Eigen::MatrixXd mat = create();
public: public:
ReturnTester() { print_created(this); } ReturnTester() { print_created(this); }
~ReturnTester() { print_destroyed(this); } ~ReturnTester() { print_destroyed(this); }
...@@ -194,12 +223,24 @@ TEST_SUBMODULE(eigen, m) { ...@@ -194,12 +223,24 @@ TEST_SUBMODULE(eigen, m) {
const Eigen::MatrixXd *viewPtr() { return &mat; } const Eigen::MatrixXd *viewPtr() { return &mat; }
Eigen::Ref<Eigen::MatrixXd> ref() { return mat; } Eigen::Ref<Eigen::MatrixXd> ref() { return mat; }
Eigen::Ref<const Eigen::MatrixXd> refConst() { return mat; } Eigen::Ref<const Eigen::MatrixXd> refConst() { return mat; }
Eigen::Block<Eigen::MatrixXd> block(int r, int c, int nrow, int ncol) { return mat.block(r, c, nrow, ncol); } Eigen::Block<Eigen::MatrixXd> block(int r, int c, int nrow, int ncol) {
Eigen::Block<const Eigen::MatrixXd> blockConst(int r, int c, int nrow, int ncol) const { return mat.block(r, c, nrow, ncol); } return mat.block(r, c, nrow, ncol);
py::EigenDMap<Eigen::Matrix2d> corners() { return py::EigenDMap<Eigen::Matrix2d>(mat.data(), }
py::EigenDStride(mat.outerStride() * (mat.outerSize()-1), mat.innerStride() * (mat.innerSize()-1))); } Eigen::Block<const Eigen::MatrixXd> blockConst(int r, int c, int nrow, int ncol) const {
py::EigenDMap<const Eigen::Matrix2d> cornersConst() const { return py::EigenDMap<const Eigen::Matrix2d>(mat.data(), return mat.block(r, c, nrow, ncol);
py::EigenDStride(mat.outerStride() * (mat.outerSize()-1), mat.innerStride() * (mat.innerSize()-1))); } }
py::EigenDMap<Eigen::Matrix2d> corners() {
return py::EigenDMap<Eigen::Matrix2d>(
mat.data(),
py::EigenDStride(mat.outerStride() * (mat.outerSize() - 1),
mat.innerStride() * (mat.innerSize() - 1)));
}
py::EigenDMap<const Eigen::Matrix2d> cornersConst() const {
return py::EigenDMap<const Eigen::Matrix2d>(
mat.data(),
py::EigenDStride(mat.outerStride() * (mat.outerSize() - 1),
mat.innerStride() * (mat.innerSize() - 1)));
}
}; };
using rvp = py::return_value_policy; using rvp = py::return_value_policy;
py::class_<ReturnTester>(m, "ReturnTester") py::class_<ReturnTester>(m, "ReturnTester")
...@@ -210,9 +251,9 @@ TEST_SUBMODULE(eigen, m) { ...@@ -210,9 +251,9 @@ TEST_SUBMODULE(eigen, m) {
.def("get_ptr", &ReturnTester::getPtr, rvp::reference_internal) .def("get_ptr", &ReturnTester::getPtr, rvp::reference_internal)
.def("view", &ReturnTester::view, rvp::reference_internal) .def("view", &ReturnTester::view, rvp::reference_internal)
.def("view_ptr", &ReturnTester::view, rvp::reference_internal) .def("view_ptr", &ReturnTester::view, rvp::reference_internal)
.def("copy_get", &ReturnTester::get) // Default rvp: copy .def("copy_get", &ReturnTester::get) // Default rvp: copy
.def("copy_view", &ReturnTester::view) // " .def("copy_view", &ReturnTester::view) // "
.def("ref", &ReturnTester::ref) // Default for Ref is to reference .def("ref", &ReturnTester::ref) // Default for Ref is to reference
.def("ref_const", &ReturnTester::refConst) // Likewise, but const .def("ref_const", &ReturnTester::refConst) // Likewise, but const
.def("ref_safe", &ReturnTester::ref, rvp::reference_internal) .def("ref_safe", &ReturnTester::ref, rvp::reference_internal)
.def("ref_const_safe", &ReturnTester::refConst, rvp::reference_internal) .def("ref_const_safe", &ReturnTester::refConst, rvp::reference_internal)
...@@ -223,8 +264,7 @@ TEST_SUBMODULE(eigen, m) { ...@@ -223,8 +264,7 @@ TEST_SUBMODULE(eigen, m) {
.def("block_const", &ReturnTester::blockConst, rvp::reference_internal) .def("block_const", &ReturnTester::blockConst, rvp::reference_internal)
.def("copy_block", &ReturnTester::block, rvp::copy) .def("copy_block", &ReturnTester::block, rvp::copy)
.def("corners", &ReturnTester::corners, rvp::reference_internal) .def("corners", &ReturnTester::corners, rvp::reference_internal)
.def("corners_const", &ReturnTester::cornersConst, rvp::reference_internal) .def("corners_const", &ReturnTester::cornersConst, rvp::reference_internal);
;
// test_special_matrix_objects // test_special_matrix_objects
// Returns a DiagonalMatrix with diagonal (1,2,3,...) // Returns a DiagonalMatrix with diagonal (1,2,3,...)
...@@ -237,21 +277,16 @@ TEST_SUBMODULE(eigen, m) { ...@@ -237,21 +277,16 @@ TEST_SUBMODULE(eigen, m) {
}); });
// Returns a SelfAdjointView referencing the lower triangle of m // Returns a SelfAdjointView referencing the lower triangle of m
m.def("symmetric_lower", [](const Eigen::MatrixXi &m) { m.def("symmetric_lower",
return m.selfadjointView<Eigen::Lower>(); [](const Eigen::MatrixXi &m) { return m.selfadjointView<Eigen::Lower>(); });
});
// Returns a SelfAdjointView referencing the lower triangle of m // Returns a SelfAdjointView referencing the lower triangle of m
m.def("symmetric_upper", [](const Eigen::MatrixXi &m) { m.def("symmetric_upper",
return m.selfadjointView<Eigen::Upper>(); [](const Eigen::MatrixXi &m) { return m.selfadjointView<Eigen::Upper>(); });
});
// Test matrix for various functions below. // Test matrix for various functions below.
Eigen::MatrixXf mat(5, 6); Eigen::MatrixXf mat(5, 6);
mat << 0, 3, 0, 0, 0, 11, mat << 0, 3, 0, 0, 0, 11, 22, 0, 0, 0, 17, 11, 7, 5, 0, 1, 0, 11, 0, 0, 0, 0, 0, 11, 0, 0, 14,
22, 0, 0, 0, 17, 11, 0, 8, 11;
7, 5, 0, 1, 0, 11,
0, 0, 0, 0, 0, 11,
0, 0, 14, 0, 8, 11;
// test_fixed, and various other tests // test_fixed, and various other tests
m.def("fixed_r", [mat]() -> FixedMatrixR { return FixedMatrixR(mat); }); m.def("fixed_r", [mat]() -> FixedMatrixR { return FixedMatrixR(mat); });
...@@ -276,7 +311,8 @@ TEST_SUBMODULE(eigen, m) { ...@@ -276,7 +311,8 @@ TEST_SUBMODULE(eigen, m) {
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
return Eigen::SparseView<Eigen::MatrixXf>(mat); return Eigen::SparseView<Eigen::MatrixXf>(mat);
}); });
m.def("sparse_c", [mat]() -> SparseMatrixC { return Eigen::SparseView<Eigen::MatrixXf>(mat); }); m.def("sparse_c",
[mat]() -> SparseMatrixC { return Eigen::SparseView<Eigen::MatrixXf>(mat); });
m.def("sparse_copy_r", [](const SparseMatrixR &m) -> SparseMatrixR { return m; }); m.def("sparse_copy_r", [](const SparseMatrixR &m) -> SparseMatrixR { return m; });
m.def("sparse_copy_c", [](const SparseMatrixC &m) -> SparseMatrixC { return m; }); m.def("sparse_copy_c", [](const SparseMatrixC &m) -> SparseMatrixC { return m; });
// test_partially_fixed // test_partially_fixed
...@@ -290,7 +326,8 @@ TEST_SUBMODULE(eigen, m) { ...@@ -290,7 +326,8 @@ TEST_SUBMODULE(eigen, m) {
m.def("cpp_copy", [](py::handle m) { return m.cast<Eigen::MatrixXd>()(1, 0); }); m.def("cpp_copy", [](py::handle m) { return m.cast<Eigen::MatrixXd>()(1, 0); });
m.def("cpp_ref_c", [](py::handle m) { return m.cast<Eigen::Ref<Eigen::MatrixXd>>()(1, 0); }); m.def("cpp_ref_c", [](py::handle m) { return m.cast<Eigen::Ref<Eigen::MatrixXd>>()(1, 0); });
m.def("cpp_ref_r", [](py::handle m) { return m.cast<Eigen::Ref<MatrixXdR>>()(1, 0); }); m.def("cpp_ref_r", [](py::handle m) { return m.cast<Eigen::Ref<MatrixXdR>>()(1, 0); });
m.def("cpp_ref_any", [](py::handle m) { return m.cast<py::EigenDRef<Eigen::MatrixXd>>()(1, 0); }); m.def("cpp_ref_any",
[](py::handle m) { return m.cast<py::EigenDRef<Eigen::MatrixXd>>()(1, 0); });
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works. // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
...@@ -304,15 +341,23 @@ TEST_SUBMODULE(eigen, m) { ...@@ -304,15 +341,23 @@ TEST_SUBMODULE(eigen, m) {
[](const Eigen::Ref<const Eigen::MatrixXd> &m) -> double { return get_elem(m); }, [](const Eigen::Ref<const Eigen::MatrixXd> &m) -> double { return get_elem(m); },
py::arg{}.noconvert()); py::arg{}.noconvert());
// Also test a row-major-only no-copy const ref: // Also test a row-major-only no-copy const ref:
m.def("get_elem_rm_nocopy", [](Eigen::Ref<const Eigen::Matrix<long, -1, -1, Eigen::RowMajor>> &m) -> long { return m(2, 1); }, m.def(
py::arg{}.noconvert()); "get_elem_rm_nocopy",
[](Eigen::Ref<const Eigen::Matrix<long, -1, -1, Eigen::RowMajor>> &m) -> long {
return m(2, 1);
},
py::arg{}.noconvert());
// test_issue738 // test_issue738
// Issue #738: 1xN or Nx1 2D matrices were neither accepted nor properly copied with an // Issue #738: 1xN or Nx1 2D matrices were neither accepted nor properly copied with an
// incompatible stride value on the length-1 dimension--but that should be allowed (without // incompatible stride value on the length-1 dimension--but that should be allowed (without
// requiring a copy!) because the stride value can be safely ignored on a size-1 dimension. // requiring a copy!) because the stride value can be safely ignored on a size-1 dimension.
m.def("iss738_f1", &adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>, py::arg{}.noconvert()); m.def("iss738_f1",
m.def("iss738_f2", &adjust_matrix<const Eigen::Ref<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>> &>, py::arg{}.noconvert()); &adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>,
py::arg{}.noconvert());
m.def("iss738_f2",
&adjust_matrix<const Eigen::Ref<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>> &>,
py::arg{}.noconvert());
// test_issue1105 // test_issue1105
// Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense // Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense
......
...@@ -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; });
......
...@@ -7,39 +7,43 @@ ...@@ -7,39 +7,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 "constructor_stats.h"
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include "constructor_stats.h"
#include "pybind11_tests.h"
#include <utility> #include <utility>
TEST_SUBMODULE(kwargs_and_defaults, m) { TEST_SUBMODULE(kwargs_and_defaults, m) {
auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); }; auto kw_func
= [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); };
// test_named_arguments // test_named_arguments
m.def("kw_func0", kw_func); m.def("kw_func0", kw_func);
m.def("kw_func1", kw_func, py::arg("x"), py::arg("y")); m.def("kw_func1", kw_func, py::arg("x"), py::arg("y"));
m.def("kw_func2", kw_func, py::arg("x") = 100, py::arg("y") = 200); m.def("kw_func2", kw_func, py::arg("x") = 100, py::arg("y") = 200);
m.def("kw_func3", [](const char *) { }, py::arg("data") = std::string("Hello world!")); m.def(
"kw_func3", [](const char *) {}, py::arg("data") = std::string("Hello world!"));
/* A fancier default argument */ /* A fancier default argument */
std::vector<int> list{{13, 17}}; std::vector<int> list{{13, 17}};
m.def("kw_func4", [](const std::vector<int> &entries) { m.def(
std::string ret = "{"; "kw_func4",
for (int i : entries) { [](const std::vector<int> &entries) {
ret += std::to_string(i) + " "; std::string ret = "{";
} for (int i : entries) {
ret.back() = '}'; ret += std::to_string(i) + " ";
return ret; }
}, py::arg("myList") = list); ret.back() = '}';
return ret;
},
py::arg("myList") = list);
m.def("kw_func_udl", kw_func, "x"_a, "y"_a=300); m.def("kw_func_udl", kw_func, "x"_a, "y"_a = 300);
m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a=0); m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a = 0);
// test_args_and_kwargs // test_args_and_kwargs
m.def("args_function", [](py::args args) -> py::tuple { m.def("args_function", [](py::args args) -> py::tuple { return std::move(args); });
return std::move(args);
});
m.def("args_kwargs_function", [](const py::args &args, const py::kwargs &kwargs) { m.def("args_kwargs_function", [](const py::args &args, const py::kwargs &kwargs) {
return py::make_tuple(args, kwargs); return py::make_tuple(args, kwargs);
}); });
...@@ -54,35 +58,60 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { ...@@ -54,35 +58,60 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
}; };
m.def("mixed_plus_args_kwargs", mixed_plus_both); m.def("mixed_plus_args_kwargs", mixed_plus_both);
m.def("mixed_plus_args_kwargs_defaults", mixed_plus_both, m.def("mixed_plus_args_kwargs_defaults",
py::arg("i") = 1, py::arg("j") = 3.14159); mixed_plus_both,
py::arg("i") = 1,
m.def("args_kwonly", py::arg("j") = 3.14159);
[](int i, double j, const py::args &args, int z) { return py::make_tuple(i, j, args, z); },
"i"_a, "j"_a, "z"_a); m.def(
m.def("args_kwonly_kwargs", "args_kwonly",
[](int i, double j, const py::args &args, int z, const py::kwargs &kwargs) { [](int i, double j, const py::args &args, int z) { return py::make_tuple(i, j, args, z); },
return py::make_tuple(i, j, args, z, kwargs); }, "i"_a,
"i"_a, "j"_a, py::kw_only{}, "z"_a); "j"_a,
m.def("args_kwonly_kwargs_defaults", "z"_a);
[](int i, double j, const py::args &args, int z, const py::kwargs &kwargs) { m.def(
return py::make_tuple(i, j, args, z, kwargs); }, "args_kwonly_kwargs",
"i"_a = 1, "j"_a = 3.14159, "z"_a = 42); [](int i, double j, const py::args &args, int z, const py::kwargs &kwargs) {
m.def("args_kwonly_full_monty", return py::make_tuple(i, j, args, z, kwargs);
[](int h, int i, double j, const py::args &args, int z, const py::kwargs &kwargs) { },
return py::make_tuple(h, i, j, args, z, kwargs); }, "i"_a,
py::arg() = 1, py::arg() = 2, py::pos_only{}, "j"_a = 3.14159, "z"_a = 42); "j"_a,
py::kw_only{},
"z"_a);
// test_args_refcount m.def(
// PyPy needs a garbage collection to get the reference count values to match CPython's behaviour "args_kwonly_kwargs_defaults",
#ifdef PYPY_VERSION [](int i, double j, const py::args &args, int z, const py::kwargs &kwargs) {
#define GC_IF_NEEDED ConstructorStats::gc() return py::make_tuple(i, j, args, z, kwargs);
#else },
#define GC_IF_NEEDED "i"_a = 1,
#endif "j"_a = 3.14159,
m.def("arg_refcount_h", [](py::handle h) { GC_IF_NEEDED; return h.ref_count(); }); "z"_a = 42);
m.def("arg_refcount_h", [](py::handle h, py::handle, py::handle) { GC_IF_NEEDED; return h.ref_count(); }); m.def(
"args_kwonly_full_monty",
[](int h, int i, double j, const py::args &args, int z, const py::kwargs &kwargs) {
return py::make_tuple(h, i, j, args, z, kwargs);
},
py::arg() = 1,
py::arg() = 2,
py::pos_only{},
"j"_a = 3.14159,
"z"_a = 42);
// test_args_refcount
// PyPy needs a garbage collection to get the reference count values to match CPython's behaviour
#ifdef PYPY_VERSION
# define GC_IF_NEEDED ConstructorStats::gc()
#else
# define GC_IF_NEEDED
#endif
m.def("arg_refcount_h", [](py::handle h) {
GC_IF_NEEDED;
return h.ref_count();
});
m.def("arg_refcount_h", [](py::handle h, py::handle, py::handle) {
GC_IF_NEEDED;
return h.ref_count();
});
m.def("arg_refcount_o", [](const py::object &o) { m.def("arg_refcount_o", [](const py::object &o) {
GC_IF_NEEDED; GC_IF_NEEDED;
return o.ref_count(); return o.ref_count();
...@@ -109,23 +138,42 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { ...@@ -109,23 +138,42 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
// pybind11 won't allow these to be bound: args and kwargs, if present, must be at the end. // pybind11 won't allow these to be bound: args and kwargs, if present, must be at the end.
// Uncomment these to test that the static_assert is indeed working: // Uncomment these to test that the static_assert is indeed working:
// m.def("bad_args1", [](py::args, int) {}); // m.def("bad_args1", [](py::args, int) {});
// m.def("bad_args2", [](py::kwargs, int) {}); // m.def("bad_args2", [](py::kwargs, int) {});
// m.def("bad_args3", [](py::kwargs, py::args) {}); // m.def("bad_args3", [](py::kwargs, py::args) {});
// m.def("bad_args4", [](py::args, int, py::kwargs) {}); // m.def("bad_args4", [](py::args, int, py::kwargs) {});
// m.def("bad_args5", [](py::args, py::kwargs, int) {}); // m.def("bad_args5", [](py::args, py::kwargs, int) {});
// m.def("bad_args6", [](py::args, py::args) {}); // m.def("bad_args6", [](py::args, py::args) {});
// m.def("bad_args7", [](py::kwargs, py::kwargs) {}); // m.def("bad_args7", [](py::kwargs, py::kwargs) {});
// test_keyword_only_args // test_keyword_only_args
m.def("kw_only_all", [](int i, int j) { return py::make_tuple(i, j); }, m.def(
py::kw_only(), py::arg("i"), py::arg("j")); "kw_only_all",
m.def("kw_only_some", [](int i, int j, int k) { return py::make_tuple(i, j, k); }, [](int i, int j) { return py::make_tuple(i, j); },
py::arg(), py::kw_only(), py::arg("j"), py::arg("k")); py::kw_only(),
m.def("kw_only_with_defaults", [](int i, int j, int k, int z) { return py::make_tuple(i, j, k, z); }, py::arg("i"),
py::arg() = 3, "j"_a = 4, py::kw_only(), "k"_a = 5, "z"_a); py::arg("j"));
m.def("kw_only_mixed", [](int i, int j) { return py::make_tuple(i, j); }, m.def(
"i"_a, py::kw_only(), "j"_a); "kw_only_some",
[](int i, int j, int k) { return py::make_tuple(i, j, k); },
py::arg(),
py::kw_only(),
py::arg("j"),
py::arg("k"));
m.def(
"kw_only_with_defaults",
[](int i, int j, int k, int z) { return py::make_tuple(i, j, k, z); },
py::arg() = 3,
"j"_a = 4,
py::kw_only(),
"k"_a = 5,
"z"_a);
m.def(
"kw_only_mixed",
[](int i, int j) { return py::make_tuple(i, j); },
"i"_a,
py::kw_only(),
"j"_a);
m.def( m.def(
"kw_only_plus_more", "kw_only_plus_more",
[](int i, int j, int k, const py::kwargs &kwargs) { [](int i, int j, int k, const py::kwargs &kwargs) {
...@@ -137,31 +185,57 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { ...@@ -137,31 +185,57 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
py::arg("k") /* kw-only */); py::arg("k") /* kw-only */);
m.def("register_invalid_kw_only", [](py::module_ m) { m.def("register_invalid_kw_only", [](py::module_ m) {
m.def("bad_kw_only", [](int i, int j) { return py::make_tuple(i, j); }, m.def(
py::kw_only(), py::arg() /* invalid unnamed argument */, "j"_a); "bad_kw_only",
[](int i, int j) { return py::make_tuple(i, j); },
py::kw_only(),
py::arg() /* invalid unnamed argument */,
"j"_a);
}); });
// test_positional_only_args // test_positional_only_args
m.def("pos_only_all", [](int i, int j) { return py::make_tuple(i, j); }, m.def(
py::arg("i"), py::arg("j"), py::pos_only()); "pos_only_all",
m.def("pos_only_mix", [](int i, int j) { return py::make_tuple(i, j); }, [](int i, int j) { return py::make_tuple(i, j); },
py::arg("i"), py::pos_only(), py::arg("j")); py::arg("i"),
m.def("pos_kw_only_mix", [](int i, int j, int k) { return py::make_tuple(i, j, k); }, py::arg("j"),
py::arg("i"), py::pos_only(), py::arg("j"), py::kw_only(), py::arg("k")); py::pos_only());
m.def("pos_only_def_mix", [](int i, int j, int k) { return py::make_tuple(i, j, k); }, m.def(
py::arg("i"), py::arg("j") = 2, py::pos_only(), py::arg("k") = 3); "pos_only_mix",
[](int i, int j) { return py::make_tuple(i, j); },
py::arg("i"),
py::pos_only(),
py::arg("j"));
m.def(
"pos_kw_only_mix",
[](int i, int j, int k) { return py::make_tuple(i, j, k); },
py::arg("i"),
py::pos_only(),
py::arg("j"),
py::kw_only(),
py::arg("k"));
m.def(
"pos_only_def_mix",
[](int i, int j, int k) { return py::make_tuple(i, j, k); },
py::arg("i"),
py::arg("j") = 2,
py::pos_only(),
py::arg("k") = 3);
// These should fail to compile: // These should fail to compile:
#ifdef PYBIND11_NEVER_DEFINED_EVER #ifdef PYBIND11_NEVER_DEFINED_EVER
// argument annotations are required when using kw_only // argument annotations are required when using kw_only
m.def("bad_kw_only1", [](int) {}, py::kw_only()); m.def(
"bad_kw_only1", [](int) {}, py::kw_only());
// can't specify both `py::kw_only` and a `py::args` argument // can't specify both `py::kw_only` and a `py::args` argument
m.def("bad_kw_only2", [](int i, py::args) {}, py::kw_only(), "i"_a); m.def(
"bad_kw_only2", [](int i, py::args) {}, py::kw_only(), "i"_a);
#endif #endif
// test_function_signatures (along with most of the above) // test_function_signatures (along with most of the above)
struct KWClass { void foo(int, float) {} }; struct KWClass {
void foo(int, float) {}
};
py::class_<KWClass>(m, "KWClass") py::class_<KWClass>(m, "KWClass")
.def("foo0", &KWClass::foo) .def("foo0", &KWClass::foo)
.def("foo1", &KWClass::foo, "x"_a, "y"_a); .def("foo1", &KWClass::foo, "x"_a, "y"_a);
...@@ -182,11 +256,18 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { ...@@ -182,11 +256,18 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
.def(py::init([](int) { return first_arg_kw_only(); }), .def(py::init([](int) { return first_arg_kw_only(); }),
py::kw_only(), // This being before any args was broken py::kw_only(), // This being before any args was broken
py::arg("i") = 0) py::arg("i") = 0)
.def("method", [](first_arg_kw_only&, int, int) {}, .def(
py::kw_only(), // and likewise here "method",
py::arg("i") = 1, py::arg("j") = 2) [](first_arg_kw_only &, int, int) {},
py::kw_only(), // and likewise here
py::arg("i") = 1,
py::arg("j") = 2)
// Closely related: pos_only marker didn't show up properly when it was before any other // Closely related: pos_only marker didn't show up properly when it was before any other
// arguments (although that is fairly useless in practice). // arguments (although that is fairly useless in practice).
.def("pos_only", [](first_arg_kw_only&, int, int) {}, .def(
py::pos_only{}, py::arg("i"), py::arg("j")); "pos_only",
[](first_arg_kw_only &, int, int) {},
py::pos_only{},
py::arg("i"),
py::arg("j"));
} }
...@@ -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"
#if !defined(PYBIND11_OVERLOAD_CAST) #if !defined(PYBIND11_OVERLOAD_CAST)
template <typename... Args> template <typename... Args>
...@@ -27,7 +27,10 @@ public: ...@@ -27,7 +27,10 @@ public:
std::string toString() const { return "ExampleMandA[value=" + std::to_string(value) + "]"; } std::string toString() const { return "ExampleMandA[value=" + std::to_string(value) + "]"; }
void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; } void operator=(const ExampleMandA &e) {
print_copy_assigned(this);
value = e.value;
}
void operator=(ExampleMandA &&e) noexcept { void operator=(ExampleMandA &&e) noexcept {
print_move_assigned(this); print_move_assigned(this);
value = e.value; value = e.value;
...@@ -40,37 +43,37 @@ public: ...@@ -40,37 +43,37 @@ public:
void add4(ExampleMandA *other) { value += other->value; } // passing by pointer void add4(ExampleMandA *other) { value += other->value; } // passing by pointer
void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer
void add6(int other) { value += other; } // passing by value void add6(int other) { value += other; } // passing by value
void add7(int &other) { value += other; } // passing by reference void add7(int &other) { value += other; } // passing by reference
void add8(const int &other) { value += other; } // passing by const reference void add8(const int &other) { value += other; } // passing by const reference
// NOLINTNEXTLINE(readability-non-const-parameter) Deliberately non-const for testing // NOLINTNEXTLINE(readability-non-const-parameter) Deliberately non-const for testing
void add9(int *other) { value += *other; } // passing by pointer void add9(int *other) { value += *other; } // passing by pointer
void add10(const int *other) { value += *other; } // passing by const pointer void add10(const int *other) { value += *other; } // passing by const pointer
void consume_str(std::string&&) {} void consume_str(std::string &&) {}
ExampleMandA self1() { return *this; } // return by value ExampleMandA self1() { return *this; } // return by value
ExampleMandA &self2() { return *this; } // return by reference ExampleMandA &self2() { return *this; } // return by reference
const ExampleMandA &self3() const { return *this; } // return by const reference const ExampleMandA &self3() const { return *this; } // return by const reference
ExampleMandA *self4() { return this; } // return by pointer ExampleMandA *self4() { return this; } // return by pointer
const ExampleMandA *self5() const { return this; } // return by const pointer const ExampleMandA *self5() const { return this; } // return by const pointer
int internal1() const { return value; } // return by value int internal1() const { return value; } // return by value
int &internal2() { return value; } // return by reference int &internal2() { return value; } // return by reference
const int &internal3() const { return value; } // return by const reference const int &internal3() const { return value; } // return by const reference
int *internal4() { return &value; } // return by pointer int *internal4() { return &value; } // return by pointer
const int *internal5() { return &value; } // return by const pointer const int *internal5() { return &value; } // return by const pointer
py::str overloaded() { return "()"; } py::str overloaded() { return "()"; }
py::str overloaded(int) { return "(int)"; } py::str overloaded(int) { return "(int)"; }
py::str overloaded(int, float) { return "(int, float)"; } py::str overloaded(int, float) { return "(int, float)"; }
py::str overloaded(float, int) { return "(float, int)"; } py::str overloaded(float, int) { return "(float, int)"; }
py::str overloaded(int, int) { return "(int, int)"; } py::str overloaded(int, int) { return "(int, int)"; }
py::str overloaded(float, float) { return "(float, float)"; } py::str overloaded(float, float) { return "(float, float)"; }
py::str overloaded(int) const { return "(int) const"; } py::str overloaded(int) const { return "(int) const"; }
py::str overloaded(int, float) const { return "(int, float) const"; } py::str overloaded(int, float) const { return "(int, float) const"; }
py::str overloaded(float, int) const { return "(float, int) const"; } py::str overloaded(float, int) const { return "(float, int) const"; }
py::str overloaded(int, int) const { return "(int, int) const"; } py::str overloaded(int, int) const { return "(int, int) const"; }
py::str overloaded(float, float) const { return "(float, float) const"; } py::str overloaded(float, float) const { return "(float, float) const"; }
static py::str overloaded(float) { return "static float"; } static py::str overloaded(float) { return "static float"; }
...@@ -112,7 +115,10 @@ UserType TestPropRVP::sv1(1); ...@@ -112,7 +115,10 @@ UserType TestPropRVP::sv1(1);
UserType TestPropRVP::sv2(1); UserType TestPropRVP::sv2(1);
// Test None-allowed py::arg argument policy // Test None-allowed py::arg argument policy
class NoneTester { public: int answer = 42; }; class NoneTester {
public:
int answer = 42;
};
int none1(const NoneTester &obj) { return obj.answer; } int none1(const NoneTester &obj) { return obj.answer; }
int none2(NoneTester *obj) { return obj ? obj->answer : -1; } int none2(NoneTester *obj) { return obj ? obj->answer : -1; }
int none3(std::shared_ptr<NoneTester> &obj) { return obj ? obj->answer : -1; } int none3(std::shared_ptr<NoneTester> &obj) { return obj ? obj->answer : -1; }
...@@ -134,11 +140,15 @@ struct StrIssue { ...@@ -134,11 +140,15 @@ struct StrIssue {
explicit StrIssue(int i) : val{i} {} explicit StrIssue(int i) : val{i} {}
}; };
// Issues #854, #910: incompatible function args when member function/pointer is in unregistered base class // Issues #854, #910: incompatible function args when member function/pointer is in unregistered
// base class
class UnregisteredBase { class UnregisteredBase {
public: public:
void do_nothing() const {} void do_nothing() const {}
void increase_value() { rw_value++; ro_value += 0.25; } void increase_value() {
rw_value++;
ro_value += 0.25;
}
void set_int(int v) { rw_value = v; } void set_int(int v) { rw_value = v; }
int get_int() const { return rw_value; } int get_int() const { return rw_value; }
double get_double() const { return ro_value; } double get_double() const { return ro_value; }
...@@ -161,10 +171,10 @@ struct RefQualified { ...@@ -161,10 +171,10 @@ struct RefQualified {
// Test rvalue ref param // Test rvalue ref param
struct RValueRefParam { struct RValueRefParam {
std::size_t func1(std::string&& s) { return s.size(); } std::size_t func1(std::string &&s) { return s.size(); }
std::size_t func2(std::string&& s) const { return s.size(); } std::size_t func2(std::string &&s) const { return s.size(); }
std::size_t func3(std::string&& s) & { return s.size(); } std::size_t func3(std::string &&s) & { return s.size(); }
std::size_t func4(std::string&& s) const & { return s.size(); } std::size_t func4(std::string &&s) const & { return s.size(); }
}; };
TEST_SUBMODULE(methods_and_attributes, m) { TEST_SUBMODULE(methods_and_attributes, m) {
...@@ -172,8 +182,8 @@ TEST_SUBMODULE(methods_and_attributes, m) { ...@@ -172,8 +182,8 @@ TEST_SUBMODULE(methods_and_attributes, m) {
py::class_<ExampleMandA> emna(m, "ExampleMandA"); py::class_<ExampleMandA> emna(m, "ExampleMandA");
emna.def(py::init<>()) emna.def(py::init<>())
.def(py::init<int>()) .def(py::init<int>())
.def(py::init<std::string&&>()) .def(py::init<std::string &&>())
.def(py::init<const ExampleMandA&>()) .def(py::init<const ExampleMandA &>())
.def("add1", &ExampleMandA::add1) .def("add1", &ExampleMandA::add1)
.def("add2", &ExampleMandA::add2) .def("add2", &ExampleMandA::add2)
.def("add3", &ExampleMandA::add3) .def("add3", &ExampleMandA::add3)
...@@ -198,16 +208,20 @@ TEST_SUBMODULE(methods_and_attributes, m) { ...@@ -198,16 +208,20 @@ TEST_SUBMODULE(methods_and_attributes, m) {
#if defined(PYBIND11_OVERLOAD_CAST) #if defined(PYBIND11_OVERLOAD_CAST)
.def("overloaded", py::overload_cast<>(&ExampleMandA::overloaded)) .def("overloaded", py::overload_cast<>(&ExampleMandA::overloaded))
.def("overloaded", py::overload_cast<int>(&ExampleMandA::overloaded)) .def("overloaded", py::overload_cast<int>(&ExampleMandA::overloaded))
.def("overloaded", py::overload_cast<int, float>(&ExampleMandA::overloaded)) .def("overloaded", py::overload_cast<int, float>(&ExampleMandA::overloaded))
.def("overloaded", py::overload_cast<float, int>(&ExampleMandA::overloaded)) .def("overloaded", py::overload_cast<float, int>(&ExampleMandA::overloaded))
.def("overloaded", py::overload_cast<int, int>(&ExampleMandA::overloaded)) .def("overloaded", py::overload_cast<int, int>(&ExampleMandA::overloaded))
.def("overloaded", py::overload_cast<float, float>(&ExampleMandA::overloaded)) .def("overloaded", py::overload_cast<float, float>(&ExampleMandA::overloaded))
.def("overloaded_float", py::overload_cast<float, float>(&ExampleMandA::overloaded)) .def("overloaded_float", py::overload_cast<float, float>(&ExampleMandA::overloaded))
.def("overloaded_const", py::overload_cast<int >(&ExampleMandA::overloaded, py::const_)) .def("overloaded_const", py::overload_cast<int>(&ExampleMandA::overloaded, py::const_))
.def("overloaded_const", py::overload_cast<int, float>(&ExampleMandA::overloaded, py::const_)) .def("overloaded_const",
.def("overloaded_const", py::overload_cast<float, int>(&ExampleMandA::overloaded, py::const_)) py::overload_cast<int, float>(&ExampleMandA::overloaded, py::const_))
.def("overloaded_const", py::overload_cast<int, int>(&ExampleMandA::overloaded, py::const_)) .def("overloaded_const",
.def("overloaded_const", py::overload_cast<float, float>(&ExampleMandA::overloaded, py::const_)) py::overload_cast<float, int>(&ExampleMandA::overloaded, py::const_))
.def("overloaded_const",
py::overload_cast<int, int>(&ExampleMandA::overloaded, py::const_))
.def("overloaded_const",
py::overload_cast<float, float>(&ExampleMandA::overloaded, py::const_))
#else #else
// Use both the traditional static_cast method and the C++11 compatible overload_cast_ // Use both the traditional static_cast method and the C++11 compatible overload_cast_
.def("overloaded", overload_cast_<>()(&ExampleMandA::overloaded)) .def("overloaded", overload_cast_<>()(&ExampleMandA::overloaded))
...@@ -225,16 +239,29 @@ TEST_SUBMODULE(methods_and_attributes, m) { ...@@ -225,16 +239,29 @@ TEST_SUBMODULE(methods_and_attributes, m) {
#endif #endif
// test_no_mixed_overloads // test_no_mixed_overloads
// Raise error if trying to mix static/non-static overloads on the same name: // Raise error if trying to mix static/non-static overloads on the same name:
.def_static("add_mixed_overloads1", []() { .def_static("add_mixed_overloads1",
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module_::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA")); []() {
emna.def ("overload_mixed1", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded)) auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(
.def_static("overload_mixed1", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded)); py::module_::import("pybind11_tests.methods_and_attributes")
}) .attr("ExampleMandA"));
.def_static("add_mixed_overloads2", []() { emna.def("overload_mixed1",
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module_::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA")); static_cast<py::str (ExampleMandA::*)(int, int)>(
emna.def_static("overload_mixed2", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded)) &ExampleMandA::overloaded))
.def ("overload_mixed2", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded)); .def_static(
}) "overload_mixed1",
static_cast<py::str (*)(float)>(&ExampleMandA::overloaded));
})
.def_static("add_mixed_overloads2",
[]() {
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(
py::module_::import("pybind11_tests.methods_and_attributes")
.attr("ExampleMandA"));
emna.def_static("overload_mixed2",
static_cast<py::str (*)(float)>(&ExampleMandA::overloaded))
.def("overload_mixed2",
static_cast<py::str (ExampleMandA::*)(int, int)>(
&ExampleMandA::overloaded));
})
.def("__str__", &ExampleMandA::toString) .def("__str__", &ExampleMandA::toString)
.def_readwrite("value", &ExampleMandA::value); .def_readwrite("value", &ExampleMandA::value);
...@@ -307,7 +334,7 @@ TEST_SUBMODULE(methods_and_attributes, m) { ...@@ -307,7 +334,7 @@ TEST_SUBMODULE(methods_and_attributes, m) {
[](const py::object &) { return UserType(1); }); [](const py::object &) { return UserType(1); });
// test_metaclass_override // test_metaclass_override
struct MetaclassOverride { }; struct MetaclassOverride {};
py::class_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type)) py::class_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type))
.def_property_readonly_static("readonly", [](const py::object &) { return 1; }); .def_property_readonly_static("readonly", [](const py::object &) { return 1; });
...@@ -315,22 +342,21 @@ TEST_SUBMODULE(methods_and_attributes, m) { ...@@ -315,22 +342,21 @@ TEST_SUBMODULE(methods_and_attributes, m) {
m.def("overload_order", [](const std::string &) { return 1; }); m.def("overload_order", [](const std::string &) { return 1; });
m.def("overload_order", [](const std::string &) { return 2; }); m.def("overload_order", [](const std::string &) { return 2; });
m.def("overload_order", [](int) { return 3; }); m.def("overload_order", [](int) { return 3; });
m.def("overload_order", [](int) { return 4; }, py::prepend{}); m.def(
"overload_order", [](int) { return 4; }, py::prepend{});
#if !defined(PYPY_VERSION) #if !defined(PYPY_VERSION)
// test_dynamic_attributes // test_dynamic_attributes
class DynamicClass { class DynamicClass {
public: public:
DynamicClass() { print_default_created(this); } DynamicClass() { print_default_created(this); }
DynamicClass(const DynamicClass&) = delete; DynamicClass(const DynamicClass &) = delete;
~DynamicClass() { print_destroyed(this); } ~DynamicClass() { print_destroyed(this); }
}; };
py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr()) py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr()).def(py::init());
.def(py::init());
class CppDerivedDynamicClass : public DynamicClass { }; class CppDerivedDynamicClass : public DynamicClass {};
py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass") py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass").def(py::init());
.def(py::init());
#endif #endif
// test_bad_arg_default // test_bad_arg_default
...@@ -340,20 +366,27 @@ TEST_SUBMODULE(methods_and_attributes, m) { ...@@ -340,20 +366,27 @@ TEST_SUBMODULE(methods_and_attributes, m) {
#else #else
m.attr("debug_enabled") = false; m.attr("debug_enabled") = false;
#endif #endif
m.def("bad_arg_def_named", []{ m.def("bad_arg_def_named", [] {
auto m = py::module_::import("pybind11_tests"); auto m = py::module_::import("pybind11_tests");
m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg("a") = UnregisteredType()); m.def(
"should_fail",
[](int, UnregisteredType) {},
py::arg(),
py::arg("a") = UnregisteredType());
}); });
m.def("bad_arg_def_unnamed", []{ m.def("bad_arg_def_unnamed", [] {
auto m = py::module_::import("pybind11_tests"); auto m = py::module_::import("pybind11_tests");
m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType()); m.def(
"should_fail",
[](int, UnregisteredType) {},
py::arg(),
py::arg() = UnregisteredType());
}); });
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works. // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
// test_accepts_none // test_accepts_none
py::class_<NoneTester, std::shared_ptr<NoneTester>>(m, "NoneTester") py::class_<NoneTester, std::shared_ptr<NoneTester>>(m, "NoneTester").def(py::init<>());
.def(py::init<>());
m.def("no_none1", &none1, py::arg{}.none(false)); m.def("no_none1", &none1, py::arg{}.none(false));
m.def("no_none2", &none2, py::arg{}.none(false)); m.def("no_none2", &none2, py::arg{}.none(false));
m.def("no_none3", &none3, py::arg{}.none(false)); m.def("no_none3", &none3, py::arg{}.none(false));
...@@ -371,21 +404,19 @@ TEST_SUBMODULE(methods_and_attributes, m) { ...@@ -371,21 +404,19 @@ TEST_SUBMODULE(methods_and_attributes, m) {
// test_casts_none // test_casts_none
// Issue #2778: implicit casting from None to object (not pointer) // Issue #2778: implicit casting from None to object (not pointer)
py::class_<NoneCastTester>(m, "NoneCastTester") py::class_<NoneCastTester>(m, "NoneCastTester")
.def(py::init<>()) .def(py::init<>())
.def(py::init<int>()) .def(py::init<int>())
.def(py::init([](py::none const&) { return NoneCastTester{}; })); .def(py::init([](py::none const &) { return NoneCastTester{}; }));
py::implicitly_convertible<py::none, NoneCastTester>(); py::implicitly_convertible<py::none, NoneCastTester>();
m.def("ok_obj_or_none", [](NoneCastTester const& foo) { return foo.answer; }); m.def("ok_obj_or_none", [](NoneCastTester const &foo) { return foo.answer; });
// test_str_issue // test_str_issue
// Issue #283: __str__ called on uninitialized instance when constructor arguments invalid // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
py::class_<StrIssue>(m, "StrIssue") py::class_<StrIssue>(m, "StrIssue")
.def(py::init<int>()) .def(py::init<int>())
.def(py::init<>()) .def(py::init<>())
.def("__str__", [](const StrIssue &si) { .def("__str__",
return "StrIssue[" + std::to_string(si.val) + "]"; } [](const StrIssue &si) { return "StrIssue[" + std::to_string(si.val) + "]"; });
);
// test_unregistered_base_implementations // test_unregistered_base_implementations
// //
...@@ -408,7 +439,8 @@ TEST_SUBMODULE(methods_and_attributes, m) { ...@@ -408,7 +439,8 @@ TEST_SUBMODULE(methods_and_attributes, m) {
// This one is in the registered class: // This one is in the registered class:
.def("sum", &RegisteredDerived::sum); .def("sum", &RegisteredDerived::sum);
using Adapted = decltype(py::method_adaptor<RegisteredDerived>(&RegisteredDerived::do_nothing)); using Adapted
= decltype(py::method_adaptor<RegisteredDerived>(&RegisteredDerived::do_nothing));
static_assert(std::is_same<Adapted, void (RegisteredDerived::*)() const>::value, ""); static_assert(std::is_same<Adapted, void (RegisteredDerived::*)() const>::value, "");
// test_methods_and_attributes // test_methods_and_attributes
......
...@@ -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;
}); });
......
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