mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-11 08:03:55 +00:00
Move tests from test_issues.cpp/py into appropriate files
This commit is contained in:
parent
44e9a4e6cf
commit
bdfb50f384
@ -40,7 +40,6 @@ set(PYBIND11_TEST_FILES
|
|||||||
test_eval.cpp
|
test_eval.cpp
|
||||||
test_exceptions.cpp
|
test_exceptions.cpp
|
||||||
test_inheritance.cpp
|
test_inheritance.cpp
|
||||||
test_issues.cpp
|
|
||||||
test_kwargs_and_defaults.cpp
|
test_kwargs_and_defaults.cpp
|
||||||
test_methods_and_attributes.cpp
|
test_methods_and_attributes.cpp
|
||||||
test_modules.cpp
|
test_modules.cpp
|
||||||
@ -59,7 +58,7 @@ set(PYBIND11_TEST_FILES
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Invoking cmake with something like:
|
# Invoking cmake with something like:
|
||||||
# cmake -DPYBIND11_TEST_OVERRIDE="test_issues.cpp;test_picking.cpp" ..
|
# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_picking.cpp" ..
|
||||||
# lets you override the tests that get compiled and run. You can restore to all tests with:
|
# lets you override the tests that get compiled and run. You can restore to all tests with:
|
||||||
# cmake -DPYBIND11_TEST_OVERRIDE= ..
|
# cmake -DPYBIND11_TEST_OVERRIDE= ..
|
||||||
if (PYBIND11_TEST_OVERRIDE)
|
if (PYBIND11_TEST_OVERRIDE)
|
||||||
|
@ -187,4 +187,23 @@ test_initializer copy_move_policies([](py::module &m) {
|
|||||||
static PrivateOpNew x{};
|
static PrivateOpNew x{};
|
||||||
return x;
|
return x;
|
||||||
}, py::return_value_policy::reference);
|
}, py::return_value_policy::reference);
|
||||||
|
|
||||||
|
// #389: rvp::move should fall-through to copy on non-movable objects
|
||||||
|
struct MoveIssue1 {
|
||||||
|
int v;
|
||||||
|
MoveIssue1(int v) : v{v} {}
|
||||||
|
MoveIssue1(const MoveIssue1 &c) = default;
|
||||||
|
MoveIssue1(MoveIssue1 &&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MoveIssue2 {
|
||||||
|
int v;
|
||||||
|
MoveIssue2(int v) : v{v} {}
|
||||||
|
MoveIssue2(MoveIssue2 &&) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
py::class_<MoveIssue1>(m, "MoveIssue1").def(py::init<int>()).def_readwrite("value", &MoveIssue1::v);
|
||||||
|
py::class_<MoveIssue2>(m, "MoveIssue2").def(py::init<int>()).def_readwrite("value", &MoveIssue2::v);
|
||||||
|
m.def("get_moveissue1", [](int i) { return new MoveIssue1(i); }, py::return_value_policy::move);
|
||||||
|
m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
|
||||||
});
|
});
|
||||||
|
@ -109,3 +109,13 @@ def test_private_op_new():
|
|||||||
assert "the object is neither movable nor copyable" in str(excinfo.value)
|
assert "the object is neither movable nor copyable" in str(excinfo.value)
|
||||||
|
|
||||||
assert m.private_op_new_reference().value == 1
|
assert m.private_op_new_reference().value == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_move_fallback():
|
||||||
|
"""#389: rvp::move should fall-through to copy on non-movable objects"""
|
||||||
|
from pybind11_tests import get_moveissue1, get_moveissue2
|
||||||
|
|
||||||
|
m2 = get_moveissue2(2)
|
||||||
|
assert m2.value == 2
|
||||||
|
m1 = get_moveissue1(1)
|
||||||
|
assert m1.value == 1
|
||||||
|
@ -120,4 +120,24 @@ test_initializer inheritance([](py::module &m) {
|
|||||||
py::class_<MismatchBase2>(m, "MismatchBase2");
|
py::class_<MismatchBase2>(m, "MismatchBase2");
|
||||||
py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>, MismatchBase2>(m, "MismatchDerived2");
|
py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>, MismatchBase2>(m, "MismatchDerived2");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// #511: problem with inheritance + overwritten def_static
|
||||||
|
struct MyBase {
|
||||||
|
static std::unique_ptr<MyBase> make() {
|
||||||
|
return std::unique_ptr<MyBase>(new MyBase());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MyDerived : MyBase {
|
||||||
|
static std::unique_ptr<MyDerived> make() {
|
||||||
|
return std::unique_ptr<MyDerived>(new MyDerived());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
py::class_<MyBase>(m, "MyBase")
|
||||||
|
.def_static("make", &MyBase::make);
|
||||||
|
|
||||||
|
py::class_<MyDerived, MyBase>(m, "MyDerived")
|
||||||
|
.def_static("make", &MyDerived::make)
|
||||||
|
.def_static("make2", &MyDerived::make);
|
||||||
});
|
});
|
||||||
|
@ -76,3 +76,16 @@ def test_holder():
|
|||||||
assert str(excinfo.value) == ("generic_type: type \"MismatchDerived2\" has a "
|
assert str(excinfo.value) == ("generic_type: type \"MismatchDerived2\" has a "
|
||||||
"non-default holder type while its base "
|
"non-default holder type while its base "
|
||||||
"\"MismatchBase2\" does not")
|
"\"MismatchBase2\" does not")
|
||||||
|
|
||||||
|
|
||||||
|
def test_inheritance_override_def_static():
|
||||||
|
"""#511: problem with inheritance + overwritten def_static"""
|
||||||
|
from pybind11_tests import MyBase, MyDerived
|
||||||
|
|
||||||
|
b = MyBase.make()
|
||||||
|
d1 = MyDerived.make2()
|
||||||
|
d2 = MyDerived.make()
|
||||||
|
|
||||||
|
assert isinstance(b, MyBase)
|
||||||
|
assert isinstance(d1, MyDerived)
|
||||||
|
assert isinstance(d2, MyDerived)
|
||||||
|
@ -1,377 +0,0 @@
|
|||||||
/*
|
|
||||||
tests/test_issues.cpp -- collection of testcases for miscellaneous issues
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "pybind11_tests.h"
|
|
||||||
#include "constructor_stats.h"
|
|
||||||
#include <pybind11/stl.h>
|
|
||||||
#include <pybind11/operators.h>
|
|
||||||
#include <pybind11/complex.h>
|
|
||||||
|
|
||||||
#define TRACKERS(CLASS) CLASS() { print_default_created(this); } ~CLASS() { print_destroyed(this); }
|
|
||||||
struct NestABase { int value = -2; TRACKERS(NestABase) };
|
|
||||||
struct NestA : NestABase { int value = 3; NestA& operator+=(int i) { value += i; return *this; } TRACKERS(NestA) };
|
|
||||||
struct NestB { NestA a; int value = 4; NestB& operator-=(int i) { value -= i; return *this; } TRACKERS(NestB) };
|
|
||||||
struct NestC { NestB b; int value = 5; NestC& operator*=(int i) { value *= i; return *this; } TRACKERS(NestC) };
|
|
||||||
|
|
||||||
/// #393
|
|
||||||
class OpTest1 {};
|
|
||||||
class OpTest2 {};
|
|
||||||
|
|
||||||
OpTest1 operator+(const OpTest1 &, const OpTest1 &) {
|
|
||||||
py::print("Add OpTest1 with OpTest1");
|
|
||||||
return OpTest1();
|
|
||||||
}
|
|
||||||
OpTest2 operator+(const OpTest2 &, const OpTest2 &) {
|
|
||||||
py::print("Add OpTest2 with OpTest2");
|
|
||||||
return OpTest2();
|
|
||||||
}
|
|
||||||
OpTest2 operator+(const OpTest2 &, const OpTest1 &) {
|
|
||||||
py::print("Add OpTest2 with OpTest1");
|
|
||||||
return OpTest2();
|
|
||||||
}
|
|
||||||
|
|
||||||
// #461
|
|
||||||
class Dupe1 {
|
|
||||||
public:
|
|
||||||
Dupe1(int v) : v_{v} {}
|
|
||||||
int get_value() const { return v_; }
|
|
||||||
private:
|
|
||||||
int v_;
|
|
||||||
};
|
|
||||||
class Dupe2 {};
|
|
||||||
class Dupe3 {};
|
|
||||||
class DupeException : public std::runtime_error {};
|
|
||||||
|
|
||||||
// #478
|
|
||||||
template <typename T> class custom_unique_ptr {
|
|
||||||
public:
|
|
||||||
custom_unique_ptr() { print_default_created(this); }
|
|
||||||
custom_unique_ptr(T *ptr) : _ptr{ptr} { print_created(this, ptr); }
|
|
||||||
custom_unique_ptr(custom_unique_ptr<T> &&move) : _ptr{move._ptr} { move._ptr = nullptr; print_move_created(this); }
|
|
||||||
custom_unique_ptr &operator=(custom_unique_ptr<T> &&move) { print_move_assigned(this); if (_ptr) destruct_ptr(); _ptr = move._ptr; move._ptr = nullptr; return *this; }
|
|
||||||
custom_unique_ptr(const custom_unique_ptr<T> &) = delete;
|
|
||||||
void operator=(const custom_unique_ptr<T> ©) = delete;
|
|
||||||
~custom_unique_ptr() { print_destroyed(this); if (_ptr) destruct_ptr(); }
|
|
||||||
private:
|
|
||||||
T *_ptr = nullptr;
|
|
||||||
void destruct_ptr() { delete _ptr; }
|
|
||||||
};
|
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
|
|
||||||
|
|
||||||
/// Issue #528: templated constructor
|
|
||||||
struct TplConstrClass {
|
|
||||||
template <typename T> TplConstrClass(const T &arg) : str{arg} {}
|
|
||||||
std::string str;
|
|
||||||
bool operator==(const TplConstrClass &t) const { return t.str == str; }
|
|
||||||
};
|
|
||||||
namespace std {
|
|
||||||
template <> struct hash<TplConstrClass> { size_t operator()(const TplConstrClass &t) const { return std::hash<std::string>()(t.str); } };
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_issues(py::module &m) {
|
|
||||||
py::module m2 = m.def_submodule("issues");
|
|
||||||
|
|
||||||
// #137: const char* isn't handled properly
|
|
||||||
m2.def("print_cchar", [](const char *s) { return std::string(s); });
|
|
||||||
|
|
||||||
// #150: char bindings broken
|
|
||||||
m2.def("print_char", [](char c) { return std::string(1, c); });
|
|
||||||
|
|
||||||
// #159: virtual function dispatch has problems with similar-named functions
|
|
||||||
struct Base { virtual std::string dispatch() const {
|
|
||||||
/* for some reason MSVC2015 can't compile this if the function is pure virtual */
|
|
||||||
return {};
|
|
||||||
}; };
|
|
||||||
|
|
||||||
struct DispatchIssue : Base {
|
|
||||||
virtual std::string dispatch() const {
|
|
||||||
PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
py::class_<Base, DispatchIssue>(m2, "DispatchIssue")
|
|
||||||
.def(py::init<>())
|
|
||||||
.def("dispatch", &Base::dispatch);
|
|
||||||
|
|
||||||
m2.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
|
|
||||||
|
|
||||||
struct Placeholder { int i; Placeholder(int i) : i(i) { } };
|
|
||||||
|
|
||||||
py::class_<Placeholder>(m2, "Placeholder")
|
|
||||||
.def(py::init<int>())
|
|
||||||
.def("__repr__", [](const Placeholder &p) { return "Placeholder[" + std::to_string(p.i) + "]"; });
|
|
||||||
|
|
||||||
// #181: iterator passthrough did not compile
|
|
||||||
m2.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
|
|
||||||
return py::make_iterator(std::begin(s), std::end(s));
|
|
||||||
});
|
|
||||||
|
|
||||||
// #187: issue involving std::shared_ptr<> return value policy & garbage collection
|
|
||||||
struct ElementBase { virtual void foo() { } /* Force creation of virtual table */ };
|
|
||||||
struct ElementA : ElementBase {
|
|
||||||
ElementA(int v) : v(v) { }
|
|
||||||
int value() { return v; }
|
|
||||||
int v;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ElementList {
|
|
||||||
void add(std::shared_ptr<ElementBase> e) { l.push_back(e); }
|
|
||||||
std::vector<std::shared_ptr<ElementBase>> l;
|
|
||||||
};
|
|
||||||
|
|
||||||
py::class_<ElementBase, std::shared_ptr<ElementBase>> (m2, "ElementBase");
|
|
||||||
|
|
||||||
py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m2, "ElementA")
|
|
||||||
.def(py::init<int>())
|
|
||||||
.def("value", &ElementA::value);
|
|
||||||
|
|
||||||
py::class_<ElementList, std::shared_ptr<ElementList>>(m2, "ElementList")
|
|
||||||
.def(py::init<>())
|
|
||||||
.def("add", &ElementList::add)
|
|
||||||
.def("get", [](ElementList &el) {
|
|
||||||
py::list list;
|
|
||||||
for (auto &e : el.l)
|
|
||||||
list.append(py::cast(e));
|
|
||||||
return list;
|
|
||||||
});
|
|
||||||
|
|
||||||
// (no id): should not be able to pass 'None' to a reference argument
|
|
||||||
m2.def("get_element", [](ElementA &el) { return el.value(); });
|
|
||||||
|
|
||||||
// (no id): don't cast doubles to ints
|
|
||||||
m2.def("expect_float", [](float f) { return f; });
|
|
||||||
m2.def("expect_int", [](int i) { return i; });
|
|
||||||
|
|
||||||
try {
|
|
||||||
py::class_<Placeholder>(m2, "Placeholder");
|
|
||||||
throw std::logic_error("Expected an exception!");
|
|
||||||
} catch (std::runtime_error &) {
|
|
||||||
/* All good */
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
|
|
||||||
class StrIssue {
|
|
||||||
public:
|
|
||||||
StrIssue(int i) : val{i} {}
|
|
||||||
StrIssue() : StrIssue(-1) {}
|
|
||||||
int value() const { return val; }
|
|
||||||
private:
|
|
||||||
int val;
|
|
||||||
};
|
|
||||||
py::class_<StrIssue> si(m2, "StrIssue");
|
|
||||||
si .def(py::init<int>())
|
|
||||||
.def(py::init<>())
|
|
||||||
.def("__str__", [](const StrIssue &si) { return "StrIssue[" + std::to_string(si.value()) + "]"; })
|
|
||||||
;
|
|
||||||
|
|
||||||
// Issue #328: first member in a class can't be used in operators
|
|
||||||
py::class_<NestABase>(m2, "NestABase").def(py::init<>()).def_readwrite("value", &NestABase::value);
|
|
||||||
py::class_<NestA>(m2, "NestA").def(py::init<>()).def(py::self += int())
|
|
||||||
.def("as_base", [](NestA &a) -> NestABase& { return (NestABase&) a; }, py::return_value_policy::reference_internal);
|
|
||||||
py::class_<NestB>(m2, "NestB").def(py::init<>()).def(py::self -= int()).def_readwrite("a", &NestB::a);
|
|
||||||
py::class_<NestC>(m2, "NestC").def(py::init<>()).def(py::self *= int()).def_readwrite("b", &NestC::b);
|
|
||||||
m2.def("get_NestA", [](const NestA &a) { return a.value; });
|
|
||||||
m2.def("get_NestB", [](const NestB &b) { return b.value; });
|
|
||||||
m2.def("get_NestC", [](const NestC &c) { return c.value; });
|
|
||||||
|
|
||||||
// Issue 389: r_v_p::move should fall-through to copy on non-movable objects
|
|
||||||
class MoveIssue1 {
|
|
||||||
public:
|
|
||||||
MoveIssue1(int v) : v{v} {}
|
|
||||||
MoveIssue1(const MoveIssue1 &c) { v = c.v; }
|
|
||||||
MoveIssue1(MoveIssue1 &&) = delete;
|
|
||||||
int v;
|
|
||||||
};
|
|
||||||
class MoveIssue2 {
|
|
||||||
public:
|
|
||||||
MoveIssue2(int v) : v{v} {}
|
|
||||||
MoveIssue2(MoveIssue2 &&) = default;
|
|
||||||
int v;
|
|
||||||
};
|
|
||||||
py::class_<MoveIssue1>(m2, "MoveIssue1").def(py::init<int>()).def_readwrite("value", &MoveIssue1::v);
|
|
||||||
py::class_<MoveIssue2>(m2, "MoveIssue2").def(py::init<int>()).def_readwrite("value", &MoveIssue2::v);
|
|
||||||
m2.def("get_moveissue1", [](int i) -> MoveIssue1 * { return new MoveIssue1(i); }, py::return_value_policy::move);
|
|
||||||
m2.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
|
|
||||||
|
|
||||||
// Issues 392/397: overridding reference-returning functions
|
|
||||||
class OverrideTest {
|
|
||||||
public:
|
|
||||||
struct A { std::string value = "hi"; };
|
|
||||||
std::string v;
|
|
||||||
A a;
|
|
||||||
explicit OverrideTest(const std::string &v) : v{v} {}
|
|
||||||
virtual std::string str_value() { return v; }
|
|
||||||
virtual std::string &str_ref() { return v; }
|
|
||||||
virtual A A_value() { return a; }
|
|
||||||
virtual A &A_ref() { return a; }
|
|
||||||
};
|
|
||||||
class PyOverrideTest : public OverrideTest {
|
|
||||||
public:
|
|
||||||
using OverrideTest::OverrideTest;
|
|
||||||
std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
|
|
||||||
// Not allowed (uncommenting should hit a static_assert failure): we can't get a reference
|
|
||||||
// to a python numeric value, since we only copy values in the numeric type caster:
|
|
||||||
// std::string &str_ref() override { PYBIND11_OVERLOAD(std::string &, OverrideTest, str_ref); }
|
|
||||||
// But we can work around it like this:
|
|
||||||
private:
|
|
||||||
std::string _tmp;
|
|
||||||
std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); }
|
|
||||||
public:
|
|
||||||
std::string &str_ref() override { return _tmp = str_ref_helper(); }
|
|
||||||
|
|
||||||
A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); }
|
|
||||||
A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); }
|
|
||||||
};
|
|
||||||
py::class_<OverrideTest::A>(m2, "OverrideTest_A")
|
|
||||||
.def_readwrite("value", &OverrideTest::A::value);
|
|
||||||
py::class_<OverrideTest, PyOverrideTest>(m2, "OverrideTest")
|
|
||||||
.def(py::init<const std::string &>())
|
|
||||||
.def("str_value", &OverrideTest::str_value)
|
|
||||||
// .def("str_ref", &OverrideTest::str_ref)
|
|
||||||
.def("A_value", &OverrideTest::A_value)
|
|
||||||
.def("A_ref", &OverrideTest::A_ref);
|
|
||||||
|
|
||||||
/// Issue 393: need to return NotSupported to ensure correct arithmetic operator behavior
|
|
||||||
py::class_<OpTest1>(m2, "OpTest1")
|
|
||||||
.def(py::init<>())
|
|
||||||
.def(py::self + py::self);
|
|
||||||
|
|
||||||
py::class_<OpTest2>(m2, "OpTest2")
|
|
||||||
.def(py::init<>())
|
|
||||||
.def(py::self + py::self)
|
|
||||||
.def("__add__", [](const OpTest2& c2, const OpTest1& c1) { return c2 + c1; })
|
|
||||||
.def("__radd__", [](const OpTest2& c2, const OpTest1& c1) { return c2 + c1; });
|
|
||||||
|
|
||||||
// Issue 388: Can't make iterators via make_iterator() with different r/v policies
|
|
||||||
static std::vector<int> list = { 1, 2, 3 };
|
|
||||||
m2.def("make_iterator_1", []() { return py::make_iterator<py::return_value_policy::copy>(list); });
|
|
||||||
m2.def("make_iterator_2", []() { return py::make_iterator<py::return_value_policy::automatic>(list); });
|
|
||||||
|
|
||||||
static std::vector<std::string> nothrows;
|
|
||||||
// Issue 461: registering two things with the same name:
|
|
||||||
py::class_<Dupe1>(m2, "Dupe1")
|
|
||||||
.def("get_value", &Dupe1::get_value)
|
|
||||||
;
|
|
||||||
m2.def("dupe1_factory", [](int v) { return new Dupe1(v); });
|
|
||||||
|
|
||||||
py::class_<Dupe2>(m2, "Dupe2");
|
|
||||||
py::exception<DupeException>(m2, "DupeException");
|
|
||||||
|
|
||||||
try {
|
|
||||||
m2.def("Dupe1", [](int v) { return new Dupe1(v); });
|
|
||||||
nothrows.emplace_back("Dupe1");
|
|
||||||
}
|
|
||||||
catch (std::runtime_error &) {}
|
|
||||||
try {
|
|
||||||
py::class_<Dupe3>(m2, "dupe1_factory");
|
|
||||||
nothrows.emplace_back("dupe1_factory");
|
|
||||||
}
|
|
||||||
catch (std::runtime_error &) {}
|
|
||||||
try {
|
|
||||||
py::exception<Dupe3>(m2, "Dupe2");
|
|
||||||
nothrows.emplace_back("Dupe2");
|
|
||||||
}
|
|
||||||
catch (std::runtime_error &) {}
|
|
||||||
try {
|
|
||||||
m2.def("DupeException", []() { return 30; });
|
|
||||||
nothrows.emplace_back("DupeException1");
|
|
||||||
}
|
|
||||||
catch (std::runtime_error &) {}
|
|
||||||
try {
|
|
||||||
py::class_<DupeException>(m2, "DupeException");
|
|
||||||
nothrows.emplace_back("DupeException2");
|
|
||||||
}
|
|
||||||
catch (std::runtime_error &) {}
|
|
||||||
m2.def("dupe_exception_failures", []() {
|
|
||||||
py::list l;
|
|
||||||
for (auto &e : nothrows) l.append(py::cast(e));
|
|
||||||
return l;
|
|
||||||
});
|
|
||||||
|
|
||||||
/// Issue #471: shared pointer instance not dellocated
|
|
||||||
class SharedChild : public std::enable_shared_from_this<SharedChild> {
|
|
||||||
public:
|
|
||||||
SharedChild() { print_created(this); }
|
|
||||||
~SharedChild() { print_destroyed(this); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class SharedParent {
|
|
||||||
public:
|
|
||||||
SharedParent() : child(std::make_shared<SharedChild>()) { }
|
|
||||||
const SharedChild &get_child() const { return *child; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<SharedChild> child;
|
|
||||||
};
|
|
||||||
|
|
||||||
py::class_<SharedChild, std::shared_ptr<SharedChild>>(m, "SharedChild");
|
|
||||||
py::class_<SharedParent, std::shared_ptr<SharedParent>>(m, "SharedParent")
|
|
||||||
.def(py::init<>())
|
|
||||||
.def("get_child", &SharedParent::get_child, py::return_value_policy::reference);
|
|
||||||
|
|
||||||
/// Issue/PR #478: unique ptrs constructed and freed without destruction
|
|
||||||
class SpecialHolderObj {
|
|
||||||
public:
|
|
||||||
int val = 0;
|
|
||||||
SpecialHolderObj *ch = nullptr;
|
|
||||||
SpecialHolderObj(int v, bool make_child = true) : val{v}, ch{make_child ? new SpecialHolderObj(val+1, false) : nullptr}
|
|
||||||
{ print_created(this, val); }
|
|
||||||
~SpecialHolderObj() { delete ch; print_destroyed(this); }
|
|
||||||
SpecialHolderObj *child() { return ch; }
|
|
||||||
};
|
|
||||||
|
|
||||||
py::class_<SpecialHolderObj, custom_unique_ptr<SpecialHolderObj>>(m, "SpecialHolderObj")
|
|
||||||
.def(py::init<int>())
|
|
||||||
.def("child", &SpecialHolderObj::child, pybind11::return_value_policy::reference_internal)
|
|
||||||
.def_readwrite("val", &SpecialHolderObj::val)
|
|
||||||
.def_static("holder_cstats", &ConstructorStats::get<custom_unique_ptr<SpecialHolderObj>>,
|
|
||||||
py::return_value_policy::reference);
|
|
||||||
|
|
||||||
/// Issue #484: number conversion generates unhandled exceptions
|
|
||||||
m2.def("test_complex", [](float x) { py::print("{}"_s.format(x)); });
|
|
||||||
m2.def("test_complex", [](std::complex<float> x) { py::print("({}, {})"_s.format(x.real(), x.imag())); });
|
|
||||||
|
|
||||||
/// Issue #511: problem with inheritance + overwritten def_static
|
|
||||||
struct MyBase {
|
|
||||||
static std::unique_ptr<MyBase> make() {
|
|
||||||
return std::unique_ptr<MyBase>(new MyBase());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MyDerived : MyBase {
|
|
||||||
static std::unique_ptr<MyDerived> make() {
|
|
||||||
return std::unique_ptr<MyDerived>(new MyDerived());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
py::class_<MyBase>(m2, "MyBase")
|
|
||||||
.def_static("make", &MyBase::make);
|
|
||||||
|
|
||||||
py::class_<MyDerived, MyBase>(m2, "MyDerived")
|
|
||||||
.def_static("make", &MyDerived::make)
|
|
||||||
.def_static("make2", &MyDerived::make);
|
|
||||||
|
|
||||||
py::dict d;
|
|
||||||
std::string bar = "bar";
|
|
||||||
d["str"] = bar;
|
|
||||||
d["num"] = 3.7;
|
|
||||||
|
|
||||||
/// Issue #528: templated constructor
|
|
||||||
m2.def("tpl_constr_vector", [](std::vector<TplConstrClass> &) {});
|
|
||||||
m2.def("tpl_constr_map", [](std::unordered_map<TplConstrClass, TplConstrClass> &) {});
|
|
||||||
m2.def("tpl_constr_set", [](std::unordered_set<TplConstrClass> &) {});
|
|
||||||
#if defined(PYBIND11_HAS_OPTIONAL)
|
|
||||||
m2.def("tpl_constr_optional", [](std::optional<TplConstrClass> &) {});
|
|
||||||
#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
|
|
||||||
m2.def("tpl_constr_optional", [](std::experimental::optional<TplConstrClass> &) {});
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// MSVC workaround: trying to use a lambda here crashes MSVC
|
|
||||||
test_initializer issues(&init_issues);
|
|
@ -1,243 +0,0 @@
|
|||||||
import pytest
|
|
||||||
from pybind11_tests import ConstructorStats
|
|
||||||
|
|
||||||
|
|
||||||
def test_regressions():
|
|
||||||
from pybind11_tests.issues import print_cchar, print_char
|
|
||||||
|
|
||||||
# #137: const char* isn't handled properly
|
|
||||||
assert print_cchar("const char *") == "const char *"
|
|
||||||
# #150: char bindings broken
|
|
||||||
assert print_char("c") == "c"
|
|
||||||
|
|
||||||
|
|
||||||
def test_dispatch_issue(msg):
|
|
||||||
"""#159: virtual function dispatch has problems with similar-named functions"""
|
|
||||||
from pybind11_tests.issues import DispatchIssue, dispatch_issue_go
|
|
||||||
|
|
||||||
class PyClass1(DispatchIssue):
|
|
||||||
def dispatch(self):
|
|
||||||
return "Yay.."
|
|
||||||
|
|
||||||
class PyClass2(DispatchIssue):
|
|
||||||
def dispatch(self):
|
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
|
||||||
super(PyClass2, self).dispatch()
|
|
||||||
assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
|
|
||||||
|
|
||||||
p = PyClass1()
|
|
||||||
return dispatch_issue_go(p)
|
|
||||||
|
|
||||||
b = PyClass2()
|
|
||||||
assert dispatch_issue_go(b) == "Yay.."
|
|
||||||
|
|
||||||
|
|
||||||
def test_iterator_passthrough():
|
|
||||||
"""#181: iterator passthrough did not compile"""
|
|
||||||
from pybind11_tests.issues import iterator_passthrough
|
|
||||||
|
|
||||||
assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15]
|
|
||||||
|
|
||||||
|
|
||||||
def test_shared_ptr_gc():
|
|
||||||
"""// #187: issue involving std::shared_ptr<> return value policy & garbage collection"""
|
|
||||||
from pybind11_tests.issues import ElementList, ElementA
|
|
||||||
|
|
||||||
el = ElementList()
|
|
||||||
for i in range(10):
|
|
||||||
el.add(ElementA(i))
|
|
||||||
pytest.gc_collect()
|
|
||||||
for i, v in enumerate(el.get()):
|
|
||||||
assert i == v.value()
|
|
||||||
|
|
||||||
|
|
||||||
def test_no_id(msg):
|
|
||||||
from pybind11_tests.issues import get_element, expect_float, expect_int
|
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
|
||||||
get_element(None)
|
|
||||||
assert msg(excinfo.value) == """
|
|
||||||
get_element(): incompatible function arguments. The following argument types are supported:
|
|
||||||
1. (arg0: m.issues.ElementA) -> int
|
|
||||||
|
|
||||||
Invoked with: None
|
|
||||||
"""
|
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
|
||||||
expect_int(5.2)
|
|
||||||
assert msg(excinfo.value) == """
|
|
||||||
expect_int(): incompatible function arguments. The following argument types are supported:
|
|
||||||
1. (arg0: int) -> int
|
|
||||||
|
|
||||||
Invoked with: 5.2
|
|
||||||
"""
|
|
||||||
assert expect_float(12) == 12
|
|
||||||
|
|
||||||
|
|
||||||
def test_str_issue(msg):
|
|
||||||
"""Issue #283: __str__ called on uninitialized instance when constructor arguments invalid"""
|
|
||||||
from pybind11_tests.issues import StrIssue
|
|
||||||
|
|
||||||
assert str(StrIssue(3)) == "StrIssue[3]"
|
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
|
||||||
str(StrIssue("no", "such", "constructor"))
|
|
||||||
assert msg(excinfo.value) == """
|
|
||||||
__init__(): incompatible constructor arguments. The following argument types are supported:
|
|
||||||
1. m.issues.StrIssue(arg0: int)
|
|
||||||
2. m.issues.StrIssue()
|
|
||||||
|
|
||||||
Invoked with: 'no', 'such', 'constructor'
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def test_nested():
|
|
||||||
""" #328: first member in a class can't be used in operators"""
|
|
||||||
from pybind11_tests.issues import NestA, NestB, NestC, get_NestA, get_NestB, get_NestC
|
|
||||||
|
|
||||||
a = NestA()
|
|
||||||
b = NestB()
|
|
||||||
c = NestC()
|
|
||||||
|
|
||||||
a += 10
|
|
||||||
assert get_NestA(a) == 13
|
|
||||||
b.a += 100
|
|
||||||
assert get_NestA(b.a) == 103
|
|
||||||
c.b.a += 1000
|
|
||||||
assert get_NestA(c.b.a) == 1003
|
|
||||||
b -= 1
|
|
||||||
assert get_NestB(b) == 3
|
|
||||||
c.b -= 3
|
|
||||||
assert get_NestB(c.b) == 1
|
|
||||||
c *= 7
|
|
||||||
assert get_NestC(c) == 35
|
|
||||||
|
|
||||||
abase = a.as_base()
|
|
||||||
assert abase.value == -2
|
|
||||||
a.as_base().value += 44
|
|
||||||
assert abase.value == 42
|
|
||||||
assert c.b.a.as_base().value == -2
|
|
||||||
c.b.a.as_base().value += 44
|
|
||||||
assert c.b.a.as_base().value == 42
|
|
||||||
|
|
||||||
del c
|
|
||||||
pytest.gc_collect()
|
|
||||||
del a # Should't delete while abase is still alive
|
|
||||||
pytest.gc_collect()
|
|
||||||
|
|
||||||
assert abase.value == 42
|
|
||||||
del abase, b
|
|
||||||
pytest.gc_collect()
|
|
||||||
|
|
||||||
|
|
||||||
def test_move_fallback():
|
|
||||||
from pybind11_tests.issues import get_moveissue1, get_moveissue2
|
|
||||||
m2 = get_moveissue2(2)
|
|
||||||
assert m2.value == 2
|
|
||||||
m1 = get_moveissue1(1)
|
|
||||||
assert m1.value == 1
|
|
||||||
|
|
||||||
|
|
||||||
def test_override_ref():
|
|
||||||
from pybind11_tests.issues import OverrideTest
|
|
||||||
o = OverrideTest("asdf")
|
|
||||||
|
|
||||||
# Not allowed (see associated .cpp comment)
|
|
||||||
# i = o.str_ref()
|
|
||||||
# assert o.str_ref() == "asdf"
|
|
||||||
assert o.str_value() == "asdf"
|
|
||||||
|
|
||||||
assert o.A_value().value == "hi"
|
|
||||||
a = o.A_ref()
|
|
||||||
assert a.value == "hi"
|
|
||||||
a.value = "bye"
|
|
||||||
assert a.value == "bye"
|
|
||||||
|
|
||||||
|
|
||||||
def test_operators_notimplemented(capture):
|
|
||||||
from pybind11_tests.issues import OpTest1, OpTest2
|
|
||||||
with capture:
|
|
||||||
c1, c2 = OpTest1(), OpTest2()
|
|
||||||
c1 + c1
|
|
||||||
c2 + c2
|
|
||||||
c2 + c1
|
|
||||||
c1 + c2
|
|
||||||
assert capture == """
|
|
||||||
Add OpTest1 with OpTest1
|
|
||||||
Add OpTest2 with OpTest2
|
|
||||||
Add OpTest2 with OpTest1
|
|
||||||
Add OpTest2 with OpTest1
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def test_iterator_rvpolicy():
|
|
||||||
""" Issue 388: Can't make iterators via make_iterator() with different r/v policies """
|
|
||||||
from pybind11_tests.issues import make_iterator_1
|
|
||||||
from pybind11_tests.issues import make_iterator_2
|
|
||||||
|
|
||||||
assert list(make_iterator_1()) == [1, 2, 3]
|
|
||||||
assert list(make_iterator_2()) == [1, 2, 3]
|
|
||||||
assert not isinstance(make_iterator_1(), type(make_iterator_2()))
|
|
||||||
|
|
||||||
|
|
||||||
def test_dupe_assignment():
|
|
||||||
""" Issue 461: overwriting a class with a function """
|
|
||||||
from pybind11_tests.issues import dupe_exception_failures
|
|
||||||
assert dupe_exception_failures() == []
|
|
||||||
|
|
||||||
|
|
||||||
def test_enable_shared_from_this_with_reference_rvp():
|
|
||||||
""" Issue #471: shared pointer instance not dellocated """
|
|
||||||
from pybind11_tests import SharedParent, SharedChild
|
|
||||||
|
|
||||||
parent = SharedParent()
|
|
||||||
child = parent.get_child()
|
|
||||||
|
|
||||||
cstats = ConstructorStats.get(SharedChild)
|
|
||||||
assert cstats.alive() == 1
|
|
||||||
del child, parent
|
|
||||||
assert cstats.alive() == 0
|
|
||||||
|
|
||||||
|
|
||||||
def test_non_destructed_holders():
|
|
||||||
""" Issue #478: unique ptrs constructed and freed without destruction """
|
|
||||||
from pybind11_tests import SpecialHolderObj
|
|
||||||
|
|
||||||
a = SpecialHolderObj(123)
|
|
||||||
b = a.child()
|
|
||||||
|
|
||||||
assert a.val == 123
|
|
||||||
assert b.val == 124
|
|
||||||
|
|
||||||
cstats = SpecialHolderObj.holder_cstats()
|
|
||||||
assert cstats.alive() == 1
|
|
||||||
del b
|
|
||||||
assert cstats.alive() == 1
|
|
||||||
del a
|
|
||||||
assert cstats.alive() == 0
|
|
||||||
|
|
||||||
|
|
||||||
def test_complex_cast(capture):
|
|
||||||
""" Issue #484: number conversion generates unhandled exceptions """
|
|
||||||
from pybind11_tests.issues import test_complex
|
|
||||||
|
|
||||||
with capture:
|
|
||||||
test_complex(1)
|
|
||||||
test_complex(2j)
|
|
||||||
|
|
||||||
assert capture == """
|
|
||||||
1.0
|
|
||||||
(0.0, 2.0)
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def test_inheritance_override_def_static():
|
|
||||||
from pybind11_tests.issues import MyBase, MyDerived
|
|
||||||
|
|
||||||
b = MyBase.make()
|
|
||||||
d1 = MyDerived.make2()
|
|
||||||
d2 = MyDerived.make()
|
|
||||||
|
|
||||||
assert isinstance(b, MyBase)
|
|
||||||
assert isinstance(d1, MyDerived)
|
|
||||||
assert isinstance(d2, MyDerived)
|
|
@ -170,6 +170,13 @@ int none3(std::shared_ptr<NoneTester> &obj) { return obj ? obj->answer : -1; }
|
|||||||
int none4(std::shared_ptr<NoneTester> *obj) { return obj && *obj ? (*obj)->answer : -1; }
|
int none4(std::shared_ptr<NoneTester> *obj) { return obj && *obj ? (*obj)->answer : -1; }
|
||||||
int none5(std::shared_ptr<NoneTester> obj) { return obj ? obj->answer : -1; }
|
int none5(std::shared_ptr<NoneTester> obj) { return obj ? obj->answer : -1; }
|
||||||
|
|
||||||
|
struct StrIssue {
|
||||||
|
int val = -1;
|
||||||
|
|
||||||
|
StrIssue() = default;
|
||||||
|
StrIssue(int i) : val{i} {}
|
||||||
|
};
|
||||||
|
|
||||||
test_initializer methods_and_attributes([](py::module &m) {
|
test_initializer methods_and_attributes([](py::module &m) {
|
||||||
py::class_<ExampleMandA> emna(m, "ExampleMandA");
|
py::class_<ExampleMandA> emna(m, "ExampleMandA");
|
||||||
emna.def(py::init<>())
|
emna.def(py::init<>())
|
||||||
@ -315,6 +322,8 @@ test_initializer methods_and_attributes([](py::module &m) {
|
|||||||
|
|
||||||
m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f"));
|
m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f"));
|
||||||
m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert());
|
m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert());
|
||||||
|
m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i"));
|
||||||
|
m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert());
|
||||||
|
|
||||||
/// Issue/PR #648: bad arg default debugging output
|
/// Issue/PR #648: bad arg default debugging output
|
||||||
#if !defined(NDEBUG)
|
#if !defined(NDEBUG)
|
||||||
@ -344,4 +353,11 @@ test_initializer methods_and_attributes([](py::module &m) {
|
|||||||
m.def("ok_none4", &none4, py::arg().none(true));
|
m.def("ok_none4", &none4, py::arg().none(true));
|
||||||
m.def("ok_none5", &none5);
|
m.def("ok_none5", &none5);
|
||||||
|
|
||||||
|
// Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
|
||||||
|
py::class_<StrIssue>(m, "StrIssue")
|
||||||
|
.def(py::init<int>())
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("__str__", [](const StrIssue &si) {
|
||||||
|
return "StrIssue[" + std::to_string(si.val) + "]"; }
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
@ -304,9 +304,9 @@ def test_cyclic_gc():
|
|||||||
|
|
||||||
|
|
||||||
def test_noconvert_args(msg):
|
def test_noconvert_args(msg):
|
||||||
from pybind11_tests import ArgInspector, arg_inspect_func, floats_only, floats_preferred
|
import pybind11_tests as m
|
||||||
|
|
||||||
a = ArgInspector()
|
a = m.ArgInspector()
|
||||||
assert msg(a.f("hi")) == """
|
assert msg(a.f("hi")) == """
|
||||||
loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
|
loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
|
||||||
"""
|
"""
|
||||||
@ -330,15 +330,15 @@ def test_noconvert_args(msg):
|
|||||||
"""
|
"""
|
||||||
assert (a.h("arg 1") ==
|
assert (a.h("arg 1") ==
|
||||||
"loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1")
|
"loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1")
|
||||||
assert msg(arg_inspect_func("A1", "A2")) == """
|
assert msg(m.arg_inspect_func("A1", "A2")) == """
|
||||||
loading ArgInspector2 argument WITH conversion allowed. Argument value = A1
|
loading ArgInspector2 argument WITH conversion allowed. Argument value = A1
|
||||||
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2
|
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert floats_preferred(4) == 2.0
|
assert m.floats_preferred(4) == 2.0
|
||||||
assert floats_only(4.0) == 2.0
|
assert m.floats_only(4.0) == 2.0
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
floats_only(4)
|
m.floats_only(4)
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
floats_only(): incompatible function arguments. The following argument types are supported:
|
floats_only(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (f: float) -> float
|
1. (f: float) -> float
|
||||||
@ -346,6 +346,27 @@ def test_noconvert_args(msg):
|
|||||||
Invoked with: 4
|
Invoked with: 4
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
assert m.ints_preferred(4) == 2
|
||||||
|
assert m.ints_preferred(True) == 0
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.ints_preferred(4.0)
|
||||||
|
assert msg(excinfo.value) == """
|
||||||
|
ints_preferred(): incompatible function arguments. The following argument types are supported:
|
||||||
|
1. (i: int) -> int
|
||||||
|
|
||||||
|
Invoked with: 4.0
|
||||||
|
""" # noqa: E501 line too long
|
||||||
|
|
||||||
|
assert m.ints_only(4) == 2
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
m.ints_only(4.0)
|
||||||
|
assert msg(excinfo.value) == """
|
||||||
|
ints_only(): incompatible function arguments. The following argument types are supported:
|
||||||
|
1. (i: int) -> int
|
||||||
|
|
||||||
|
Invoked with: 4.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def test_bad_arg_default(msg):
|
def test_bad_arg_default(msg):
|
||||||
from pybind11_tests import debug_enabled, bad_arg_def_named, bad_arg_def_unnamed
|
from pybind11_tests import debug_enabled, bad_arg_def_named, bad_arg_def_unnamed
|
||||||
@ -371,7 +392,7 @@ def test_bad_arg_default(msg):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_accepts_none():
|
def test_accepts_none(msg):
|
||||||
from pybind11_tests import (NoneTester,
|
from pybind11_tests import (NoneTester,
|
||||||
no_none1, no_none2, no_none3, no_none4, no_none5,
|
no_none1, no_none2, no_none3, no_none4, no_none5,
|
||||||
ok_none1, ok_none2, ok_none3, ok_none4, ok_none5)
|
ok_none1, ok_none2, ok_none3, ok_none4, ok_none5)
|
||||||
@ -407,9 +428,32 @@ def test_accepts_none():
|
|||||||
# The first one still raises because you can't pass None as a lvalue reference arg:
|
# The first one still raises because you can't pass None as a lvalue reference arg:
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
assert ok_none1(None) == -1
|
assert ok_none1(None) == -1
|
||||||
assert "incompatible function arguments" in str(excinfo.value)
|
assert msg(excinfo.value) == """
|
||||||
|
ok_none1(): incompatible function arguments. The following argument types are supported:
|
||||||
|
1. (arg0: m.NoneTester) -> int
|
||||||
|
|
||||||
|
Invoked with: None
|
||||||
|
"""
|
||||||
|
|
||||||
# The rest take the argument as pointer or holder, and accept None:
|
# The rest take the argument as pointer or holder, and accept None:
|
||||||
assert ok_none2(None) == -1
|
assert ok_none2(None) == -1
|
||||||
assert ok_none3(None) == -1
|
assert ok_none3(None) == -1
|
||||||
assert ok_none4(None) == -1
|
assert ok_none4(None) == -1
|
||||||
assert ok_none5(None) == -1
|
assert ok_none5(None) == -1
|
||||||
|
|
||||||
|
|
||||||
|
def test_str_issue(msg):
|
||||||
|
"""#283: __str__ called on uninitialized instance when constructor arguments invalid"""
|
||||||
|
from pybind11_tests import StrIssue
|
||||||
|
|
||||||
|
assert str(StrIssue(3)) == "StrIssue[3]"
|
||||||
|
|
||||||
|
with pytest.raises(TypeError) as excinfo:
|
||||||
|
str(StrIssue("no", "such", "constructor"))
|
||||||
|
assert msg(excinfo.value) == """
|
||||||
|
__init__(): incompatible constructor arguments. The following argument types are supported:
|
||||||
|
1. m.StrIssue(arg0: int)
|
||||||
|
2. m.StrIssue()
|
||||||
|
|
||||||
|
Invoked with: 'no', 'such', 'constructor'
|
||||||
|
"""
|
||||||
|
@ -55,4 +55,47 @@ test_initializer modules([](py::module &m) {
|
|||||||
.def_readwrite("a2", &B::a2);
|
.def_readwrite("a2", &B::a2);
|
||||||
|
|
||||||
m.attr("OD") = py::module::import("collections").attr("OrderedDict");
|
m.attr("OD") = py::module::import("collections").attr("OrderedDict");
|
||||||
|
|
||||||
|
// Registering two things with the same name
|
||||||
|
m.def("duplicate_registration", []() {
|
||||||
|
class Dupe1 { };
|
||||||
|
class Dupe2 { };
|
||||||
|
class Dupe3 { };
|
||||||
|
class DupeException { };
|
||||||
|
|
||||||
|
auto dm = py::module("dummy");
|
||||||
|
auto failures = py::list();
|
||||||
|
|
||||||
|
py::class_<Dupe1>(dm, "Dupe1");
|
||||||
|
py::class_<Dupe2>(dm, "Dupe2");
|
||||||
|
dm.def("dupe1_factory", []() { return Dupe1(); });
|
||||||
|
py::exception<DupeException>(dm, "DupeException");
|
||||||
|
|
||||||
|
try {
|
||||||
|
py::class_<Dupe1>(dm, "Dupe1");
|
||||||
|
failures.append("Dupe1 class");
|
||||||
|
} catch (std::runtime_error &) {}
|
||||||
|
try {
|
||||||
|
dm.def("Dupe1", []() { return Dupe1(); });
|
||||||
|
failures.append("Dupe1 function");
|
||||||
|
} catch (std::runtime_error &) {}
|
||||||
|
try {
|
||||||
|
py::class_<Dupe3>(dm, "dupe1_factory");
|
||||||
|
failures.append("dupe1_factory");
|
||||||
|
} catch (std::runtime_error &) {}
|
||||||
|
try {
|
||||||
|
py::exception<Dupe3>(dm, "Dupe2");
|
||||||
|
failures.append("Dupe2");
|
||||||
|
} catch (std::runtime_error &) {}
|
||||||
|
try {
|
||||||
|
dm.def("DupeException", []() { return 30; });
|
||||||
|
failures.append("DupeException1");
|
||||||
|
} catch (std::runtime_error &) {}
|
||||||
|
try {
|
||||||
|
py::class_<DupeException>(dm, "DupeException");
|
||||||
|
failures.append("DupeException2");
|
||||||
|
} catch (std::runtime_error &) {}
|
||||||
|
|
||||||
|
return failures;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -61,3 +61,10 @@ def test_pydoc():
|
|||||||
|
|
||||||
assert pybind11_tests.__doc__ == "pybind11 test module"
|
assert pybind11_tests.__doc__ == "pybind11 test module"
|
||||||
assert pydoc.text.docmodule(pybind11_tests)
|
assert pydoc.text.docmodule(pybind11_tests)
|
||||||
|
|
||||||
|
|
||||||
|
def test_duplicate_registration():
|
||||||
|
"""Registering two things with the same name"""
|
||||||
|
from pybind11_tests import duplicate_registration
|
||||||
|
|
||||||
|
assert duplicate_registration() == []
|
||||||
|
@ -56,7 +56,38 @@ private:
|
|||||||
float x, y;
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
test_initializer operator_overloading([](py::module &m) {
|
class C1 { };
|
||||||
|
class C2 { };
|
||||||
|
|
||||||
|
int operator+(const C1 &, const C1 &) { return 11; }
|
||||||
|
int operator+(const C2 &, const C2 &) { return 22; }
|
||||||
|
int operator+(const C2 &, const C1 &) { return 21; }
|
||||||
|
int operator+(const C1 &, const C2 &) { return 12; }
|
||||||
|
|
||||||
|
struct NestABase {
|
||||||
|
int value = -2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NestA : NestABase {
|
||||||
|
int value = 3;
|
||||||
|
NestA& operator+=(int i) { value += i; return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NestB {
|
||||||
|
NestA a;
|
||||||
|
int value = 4;
|
||||||
|
NestB& operator-=(int i) { value -= i; return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NestC {
|
||||||
|
NestB b;
|
||||||
|
int value = 5;
|
||||||
|
NestC& operator*=(int i) { value *= i; return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
test_initializer operator_overloading([](py::module &pm) {
|
||||||
|
auto m = pm.def_submodule("operators");
|
||||||
|
|
||||||
py::class_<Vector2>(m, "Vector2")
|
py::class_<Vector2>(m, "Vector2")
|
||||||
.def(py::init<float, float>())
|
.def(py::init<float, float>())
|
||||||
.def(py::self + py::self)
|
.def(py::self + py::self)
|
||||||
@ -81,4 +112,41 @@ test_initializer operator_overloading([](py::module &m) {
|
|||||||
;
|
;
|
||||||
|
|
||||||
m.attr("Vector") = m.attr("Vector2");
|
m.attr("Vector") = m.attr("Vector2");
|
||||||
|
|
||||||
|
// #393: need to return NotSupported to ensure correct arithmetic operator behavior
|
||||||
|
py::class_<C1>(m, "C1")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def(py::self + py::self);
|
||||||
|
|
||||||
|
py::class_<C2>(m, "C2")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def(py::self + py::self)
|
||||||
|
.def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; })
|
||||||
|
.def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; });
|
||||||
|
|
||||||
|
// #328: first member in a class can't be used in operators
|
||||||
|
py::class_<NestABase>(m, "NestABase")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def_readwrite("value", &NestABase::value);
|
||||||
|
|
||||||
|
py::class_<NestA>(m, "NestA")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def(py::self += int())
|
||||||
|
.def("as_base", [](NestA &a) -> NestABase& {
|
||||||
|
return (NestABase&) a;
|
||||||
|
}, py::return_value_policy::reference_internal);
|
||||||
|
|
||||||
|
py::class_<NestB>(m, "NestB")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def(py::self -= int())
|
||||||
|
.def_readwrite("a", &NestB::a);
|
||||||
|
|
||||||
|
py::class_<NestC>(m, "NestC")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def(py::self *= int())
|
||||||
|
.def_readwrite("b", &NestC::b);
|
||||||
|
|
||||||
|
m.def("get_NestA", [](const NestA &a) { return a.value; });
|
||||||
|
m.def("get_NestB", [](const NestB &b) { return b.value; });
|
||||||
|
m.def("get_NestC", [](const NestC &c) { return c.value; });
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
|
import pytest
|
||||||
|
from pybind11_tests import ConstructorStats
|
||||||
|
|
||||||
|
|
||||||
def test_operator_overloading():
|
def test_operator_overloading():
|
||||||
from pybind11_tests import Vector2, Vector, ConstructorStats
|
from pybind11_tests.operators import Vector2, Vector
|
||||||
|
|
||||||
v1 = Vector2(1, 2)
|
v1 = Vector2(1, 2)
|
||||||
v2 = Vector(3, -1)
|
v2 = Vector(3, -1)
|
||||||
@ -51,3 +55,53 @@ def test_operator_overloading():
|
|||||||
assert cstats.move_constructions >= 10
|
assert cstats.move_constructions >= 10
|
||||||
assert cstats.copy_assignments == 0
|
assert cstats.copy_assignments == 0
|
||||||
assert cstats.move_assignments == 0
|
assert cstats.move_assignments == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_operators_notimplemented():
|
||||||
|
"""#393: need to return NotSupported to ensure correct arithmetic operator behavior"""
|
||||||
|
from pybind11_tests.operators import C1, C2
|
||||||
|
|
||||||
|
c1, c2 = C1(), C2()
|
||||||
|
assert c1 + c1 == 11
|
||||||
|
assert c2 + c2 == 22
|
||||||
|
assert c2 + c1 == 21
|
||||||
|
assert c1 + c2 == 12
|
||||||
|
|
||||||
|
|
||||||
|
def test_nested():
|
||||||
|
"""#328: first member in a class can't be used in operators"""
|
||||||
|
from pybind11_tests.operators import NestA, NestB, NestC, get_NestA, get_NestB, get_NestC
|
||||||
|
|
||||||
|
a = NestA()
|
||||||
|
b = NestB()
|
||||||
|
c = NestC()
|
||||||
|
|
||||||
|
a += 10
|
||||||
|
assert get_NestA(a) == 13
|
||||||
|
b.a += 100
|
||||||
|
assert get_NestA(b.a) == 103
|
||||||
|
c.b.a += 1000
|
||||||
|
assert get_NestA(c.b.a) == 1003
|
||||||
|
b -= 1
|
||||||
|
assert get_NestB(b) == 3
|
||||||
|
c.b -= 3
|
||||||
|
assert get_NestB(c.b) == 1
|
||||||
|
c *= 7
|
||||||
|
assert get_NestC(c) == 35
|
||||||
|
|
||||||
|
abase = a.as_base()
|
||||||
|
assert abase.value == -2
|
||||||
|
a.as_base().value += 44
|
||||||
|
assert abase.value == 42
|
||||||
|
assert c.b.a.as_base().value == -2
|
||||||
|
c.b.a.as_base().value += 44
|
||||||
|
assert c.b.a.as_base().value == 42
|
||||||
|
|
||||||
|
del c
|
||||||
|
pytest.gc_collect()
|
||||||
|
del a # Should't delete while abase is still alive
|
||||||
|
pytest.gc_collect()
|
||||||
|
|
||||||
|
assert abase.value == 42
|
||||||
|
del abase, b
|
||||||
|
pytest.gc_collect()
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "pybind11_tests.h"
|
#include "pybind11_tests.h"
|
||||||
#include "constructor_stats.h"
|
#include "constructor_stats.h"
|
||||||
#include <pybind11/stl.h>
|
#include <pybind11/stl.h>
|
||||||
|
#include <pybind11/complex.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
@ -215,6 +216,17 @@ std::vector<std::reference_wrapper<IncrIntWrapper>> incr_int_wrappers() {
|
|||||||
return r;
|
return r;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Issue #528: templated constructor
|
||||||
|
struct TplCtorClass {
|
||||||
|
template <typename T> TplCtorClass(const T &) { }
|
||||||
|
bool operator==(const TplCtorClass &) const { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct hash<TplCtorClass> { size_t operator()(const TplCtorClass &) const { return 0; } };
|
||||||
|
}
|
||||||
|
|
||||||
test_initializer python_types([](py::module &m) {
|
test_initializer python_types([](py::module &m) {
|
||||||
/* No constructor is explicitly defined below. An exception is raised when
|
/* No constructor is explicitly defined below. An exception is raised when
|
||||||
trying to construct it directly from Python */
|
trying to construct it directly from Python */
|
||||||
@ -501,6 +513,8 @@ test_initializer python_types([](py::module &m) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m.def("string_roundtrip", [](const char *s) { return s; });
|
||||||
|
|
||||||
// Some test characters in utf16 and utf32 encodings. The last one (the 𝐀) contains a null byte
|
// Some test characters in utf16 and utf32 encodings. The last one (the 𝐀) contains a null byte
|
||||||
char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/, mathbfA32 = 0x1d400 /*𝐀*/;
|
char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/, mathbfA32 = 0x1d400 /*𝐀*/;
|
||||||
char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82, mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00;
|
char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82, mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00;
|
||||||
@ -661,6 +675,19 @@ test_initializer python_types([](py::module &m) {
|
|||||||
return l;
|
return l;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Issue #484: number conversion generates unhandled exceptions
|
||||||
|
m.def("test_complex", [](float x) { return "{}"_s.format(x); });
|
||||||
|
m.def("test_complex", [](std::complex<float> x) { return "({}, {})"_s.format(x.real(), x.imag()); });
|
||||||
|
|
||||||
|
/// Issue #528: templated constructor
|
||||||
|
m.def("tpl_ctor_vector", [](std::vector<TplCtorClass> &) {});
|
||||||
|
m.def("tpl_ctor_map", [](std::unordered_map<TplCtorClass, TplCtorClass> &) {});
|
||||||
|
m.def("tpl_ctor_set", [](std::unordered_set<TplCtorClass> &) {});
|
||||||
|
#if defined(PYBIND11_HAS_OPTIONAL)
|
||||||
|
m.def("tpl_constr_optional", [](std::optional<TplCtorClass> &) {});
|
||||||
|
#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
|
||||||
|
m.def("tpl_constr_optional", [](std::experimental::optional<TplCtorClass> &) {});
|
||||||
|
#endif
|
||||||
});
|
});
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
|
@ -452,6 +452,12 @@ def test_implicit_casting():
|
|||||||
assert z['l'] == [3, 6, 9, 12, 15]
|
assert z['l'] == [3, 6, 9, 12, 15]
|
||||||
|
|
||||||
|
|
||||||
|
def test_simple_string():
|
||||||
|
from pybind11_tests import string_roundtrip
|
||||||
|
|
||||||
|
assert string_roundtrip("const char *") == "const char *"
|
||||||
|
|
||||||
|
|
||||||
def test_unicode_conversion():
|
def test_unicode_conversion():
|
||||||
"""Tests unicode conversion and error reporting."""
|
"""Tests unicode conversion and error reporting."""
|
||||||
import pybind11_tests
|
import pybind11_tests
|
||||||
@ -699,3 +705,11 @@ def test_reference_wrapper():
|
|||||||
|
|
||||||
assert refwrap_iiw(IncrIntWrapper(5)) == 5
|
assert refwrap_iiw(IncrIntWrapper(5)) == 5
|
||||||
assert refwrap_call_iiw(IncrIntWrapper(10), refwrap_iiw) == [10, 10, 10, 10]
|
assert refwrap_call_iiw(IncrIntWrapper(10), refwrap_iiw) == [10, 10, 10, 10]
|
||||||
|
|
||||||
|
|
||||||
|
def test_complex_cast():
|
||||||
|
"""#484: number conversion generates unhandled exceptions"""
|
||||||
|
from pybind11_tests import test_complex
|
||||||
|
|
||||||
|
assert test_complex(1) == "1.0"
|
||||||
|
assert test_complex(2j) == "(0.0, 2.0)"
|
||||||
|
@ -351,4 +351,14 @@ test_initializer sequences_and_iterators([](py::module &pm) {
|
|||||||
m.def("tuple_iterator", [](py::tuple x) { return test_random_access_iterator(x); });
|
m.def("tuple_iterator", [](py::tuple x) { return test_random_access_iterator(x); });
|
||||||
m.def("list_iterator", [](py::list x) { return test_random_access_iterator(x); });
|
m.def("list_iterator", [](py::list x) { return test_random_access_iterator(x); });
|
||||||
m.def("sequence_iterator", [](py::sequence x) { return test_random_access_iterator(x); });
|
m.def("sequence_iterator", [](py::sequence x) { return test_random_access_iterator(x); });
|
||||||
|
|
||||||
|
// #181: iterator passthrough did not compile
|
||||||
|
m.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
|
||||||
|
return py::make_iterator(std::begin(s), std::end(s));
|
||||||
|
});
|
||||||
|
|
||||||
|
// #388: Can't make iterators via make_iterator() with different r/v policies
|
||||||
|
static std::vector<int> list = { 1, 2, 3 };
|
||||||
|
m.def("make_iterator_1", []() { return py::make_iterator<py::return_value_policy::copy>(list); });
|
||||||
|
m.def("make_iterator_2", []() { return py::make_iterator<py::return_value_policy::automatic>(list); });
|
||||||
});
|
});
|
||||||
|
@ -147,3 +147,20 @@ def test_python_iterator_in_cpp():
|
|||||||
assert all(m.tuple_iterator(tuple(r)))
|
assert all(m.tuple_iterator(tuple(r)))
|
||||||
assert all(m.list_iterator(list(r)))
|
assert all(m.list_iterator(list(r)))
|
||||||
assert all(m.sequence_iterator(r))
|
assert all(m.sequence_iterator(r))
|
||||||
|
|
||||||
|
|
||||||
|
def test_iterator_passthrough():
|
||||||
|
"""#181: iterator passthrough did not compile"""
|
||||||
|
from pybind11_tests.sequences_and_iterators import iterator_passthrough
|
||||||
|
|
||||||
|
assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15]
|
||||||
|
|
||||||
|
|
||||||
|
def test_iterator_rvp():
|
||||||
|
"""#388: Can't make iterators via make_iterator() with different r/v policies """
|
||||||
|
import pybind11_tests.sequences_and_iterators as m
|
||||||
|
|
||||||
|
assert list(m.make_iterator_1()) == [1, 2, 3]
|
||||||
|
assert list(m.make_iterator_2()) == [1, 2, 3]
|
||||||
|
assert not isinstance(m.make_iterator_1(), type(m.make_iterator_2()))
|
||||||
|
|
||||||
|
@ -259,6 +259,18 @@ public:
|
|||||||
|
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, CustomUniquePtr<T>);
|
PYBIND11_DECLARE_HOLDER_TYPE(T, CustomUniquePtr<T>);
|
||||||
|
|
||||||
|
struct ElementBase { virtual void foo() { } /* Force creation of virtual table */ };
|
||||||
|
struct ElementA : ElementBase {
|
||||||
|
ElementA(int v) : v(v) { }
|
||||||
|
int value() { return v; }
|
||||||
|
int v;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ElementList {
|
||||||
|
void add(std::shared_ptr<ElementBase> e) { l.push_back(e); }
|
||||||
|
std::vector<std::shared_ptr<ElementBase>> l;
|
||||||
|
};
|
||||||
|
|
||||||
test_initializer smart_ptr_and_references([](py::module &pm) {
|
test_initializer smart_ptr_and_references([](py::module &pm) {
|
||||||
auto m = pm.def_submodule("smart_ptr");
|
auto m = pm.def_submodule("smart_ptr");
|
||||||
|
|
||||||
@ -309,4 +321,21 @@ test_initializer smart_ptr_and_references([](py::module &pm) {
|
|||||||
py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder")
|
py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {});
|
.def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {});
|
||||||
|
|
||||||
|
// #187: issue involving std::shared_ptr<> return value policy & garbage collection
|
||||||
|
py::class_<ElementBase, std::shared_ptr<ElementBase>>(m, "ElementBase");
|
||||||
|
|
||||||
|
py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m, "ElementA")
|
||||||
|
.def(py::init<int>())
|
||||||
|
.def("value", &ElementA::value);
|
||||||
|
|
||||||
|
py::class_<ElementList, std::shared_ptr<ElementList>>(m, "ElementList")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("add", &ElementList::add)
|
||||||
|
.def("get", [](ElementList &el) {
|
||||||
|
py::list list;
|
||||||
|
for (auto &e : el.l)
|
||||||
|
list.append(py::cast(e));
|
||||||
|
return list;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -234,3 +234,15 @@ def test_smart_ptr_from_default():
|
|||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
HeldByDefaultHolder.load_shared_ptr(instance)
|
HeldByDefaultHolder.load_shared_ptr(instance)
|
||||||
assert "Unable to load a custom holder type from a default-holder instance" in str(excinfo)
|
assert "Unable to load a custom holder type from a default-holder instance" in str(excinfo)
|
||||||
|
|
||||||
|
|
||||||
|
def test_shared_ptr_gc():
|
||||||
|
"""#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
|
||||||
|
from pybind11_tests.smart_ptr import ElementList, ElementA
|
||||||
|
|
||||||
|
el = ElementList()
|
||||||
|
for i in range(10):
|
||||||
|
el.add(ElementA(i))
|
||||||
|
pytest.gc_collect()
|
||||||
|
for i, v in enumerate(el.get()):
|
||||||
|
assert i == v.value()
|
||||||
|
@ -311,6 +311,16 @@ void initialize_inherited_virtuals(py::module &m) {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Base {
|
||||||
|
/* for some reason MSVC2015 can't compile this if the function is pure virtual */
|
||||||
|
virtual std::string dispatch() const { return {}; };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DispatchIssue : Base {
|
||||||
|
virtual std::string dispatch() const {
|
||||||
|
PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
test_initializer virtual_functions([](py::module &m) {
|
test_initializer virtual_functions([](py::module &m) {
|
||||||
py::class_<ExampleVirt, PyExampleVirt>(m, "ExampleVirt")
|
py::class_<ExampleVirt, PyExampleVirt>(m, "ExampleVirt")
|
||||||
@ -341,4 +351,51 @@ test_initializer virtual_functions([](py::module &m) {
|
|||||||
|
|
||||||
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
|
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
|
||||||
initialize_inherited_virtuals(m);
|
initialize_inherited_virtuals(m);
|
||||||
|
|
||||||
|
// #159: virtual function dispatch has problems with similar-named functions
|
||||||
|
py::class_<Base, DispatchIssue>(m, "DispatchIssue")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("dispatch", &Base::dispatch);
|
||||||
|
|
||||||
|
m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
|
||||||
|
|
||||||
|
// #392/397: overridding reference-returning functions
|
||||||
|
class OverrideTest {
|
||||||
|
public:
|
||||||
|
struct A { std::string value = "hi"; };
|
||||||
|
std::string v;
|
||||||
|
A a;
|
||||||
|
explicit OverrideTest(const std::string &v) : v{v} {}
|
||||||
|
virtual std::string str_value() { return v; }
|
||||||
|
virtual std::string &str_ref() { return v; }
|
||||||
|
virtual A A_value() { return a; }
|
||||||
|
virtual A &A_ref() { return a; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class PyOverrideTest : public OverrideTest {
|
||||||
|
public:
|
||||||
|
using OverrideTest::OverrideTest;
|
||||||
|
std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
|
||||||
|
// Not allowed (uncommenting should hit a static_assert failure): we can't get a reference
|
||||||
|
// to a python numeric value, since we only copy values in the numeric type caster:
|
||||||
|
// std::string &str_ref() override { PYBIND11_OVERLOAD(std::string &, OverrideTest, str_ref); }
|
||||||
|
// But we can work around it like this:
|
||||||
|
private:
|
||||||
|
std::string _tmp;
|
||||||
|
std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); }
|
||||||
|
public:
|
||||||
|
std::string &str_ref() override { return _tmp = str_ref_helper(); }
|
||||||
|
|
||||||
|
A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); }
|
||||||
|
A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); }
|
||||||
|
};
|
||||||
|
|
||||||
|
py::class_<OverrideTest::A>(m, "OverrideTest_A")
|
||||||
|
.def_readwrite("value", &OverrideTest::A::value);
|
||||||
|
py::class_<OverrideTest, PyOverrideTest>(m, "OverrideTest")
|
||||||
|
.def(py::init<const std::string &>())
|
||||||
|
.def("str_value", &OverrideTest::str_value)
|
||||||
|
// .def("str_ref", &OverrideTest::str_ref)
|
||||||
|
.def("A_value", &OverrideTest::A_value)
|
||||||
|
.def("A_ref", &OverrideTest::A_ref);
|
||||||
});
|
});
|
||||||
|
@ -257,3 +257,42 @@ def test_move_support():
|
|||||||
assert mv_stats.copy_constructions == 1
|
assert mv_stats.copy_constructions == 1
|
||||||
assert nc_stats.move_constructions >= 0
|
assert nc_stats.move_constructions >= 0
|
||||||
assert mv_stats.move_constructions >= 0
|
assert mv_stats.move_constructions >= 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_dispatch_issue(msg):
|
||||||
|
"""#159: virtual function dispatch has problems with similar-named functions"""
|
||||||
|
from pybind11_tests import DispatchIssue, dispatch_issue_go
|
||||||
|
|
||||||
|
class PyClass1(DispatchIssue):
|
||||||
|
def dispatch(self):
|
||||||
|
return "Yay.."
|
||||||
|
|
||||||
|
class PyClass2(DispatchIssue):
|
||||||
|
def dispatch(self):
|
||||||
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
|
super(PyClass2, self).dispatch()
|
||||||
|
assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
|
||||||
|
|
||||||
|
p = PyClass1()
|
||||||
|
return dispatch_issue_go(p)
|
||||||
|
|
||||||
|
b = PyClass2()
|
||||||
|
assert dispatch_issue_go(b) == "Yay.."
|
||||||
|
|
||||||
|
|
||||||
|
def test_override_ref():
|
||||||
|
"""#392/397: overridding reference-returning functions"""
|
||||||
|
from pybind11_tests import OverrideTest
|
||||||
|
|
||||||
|
o = OverrideTest("asdf")
|
||||||
|
|
||||||
|
# Not allowed (see associated .cpp comment)
|
||||||
|
# i = o.str_ref()
|
||||||
|
# assert o.str_ref() == "asdf"
|
||||||
|
assert o.str_value() == "asdf"
|
||||||
|
|
||||||
|
assert o.A_value().value == "hi"
|
||||||
|
a = o.A_ref()
|
||||||
|
assert a.value == "hi"
|
||||||
|
a.value = "bye"
|
||||||
|
assert a.value == "bye"
|
||||||
|
Loading…
Reference in New Issue
Block a user