Commit 391c7544 by Jason Rhinelander

Update all remaining tests to new test styles

This udpates all the remaining tests to the new test suite code and
comment styles started in #898.  For the most part, the test coverage
here is unchanged, with a few minor exceptions as noted below.

- test_constants_and_functions: this adds more overload tests with
  overloads with different number of arguments for more comprehensive
  overload_cast testing.  The test style conversion broke the overload
  tests under MSVC 2015, prompting the additional tests while looking
  for a workaround.

- test_eigen: this dropped the unused functions `get_cm_corners` and
  `get_cm_corners_const`--these same tests were duplicates of the same
  things provided (and used) via ReturnTester methods.

- test_opaque_types: this test had a hidden dependence on ExampleMandA
  which is now fixed by using the global UserType which suffices for the
  relevant test.

- test_methods_and_attributes: this required some additions to UserType
  to make it usable as a replacement for the test's previous SimpleType:
  UserType gained a value mutator, and the `value` property is not
  mutable (it was previously readonly).  Some overload tests were also
  added to better test overload_cast (as described above).

- test_numpy_array: removed the untemplated mutate_data/mutate_data_t:
  the templated versions with an empty parameter pack expand to the same
  thing.

- test_stl: this was already mostly in the new style; this just tweaks
  things a bit, localizing a class, and adding some missing
  `// test_whatever` comments.

- test_virtual_functions: like `test_stl`, this was mostly in the new
  test style already, but needed some `// test_whatever` comments.
  This commit also moves the inherited virtual example code to the end
  of the file, after the main set of tests (since it is less important
  than the other tests, and rather length); it also got renamed to
  `test_inherited_virtuals` (from `test_inheriting_repeat`) because it
  tests both inherited virtual approaches, not just the repeat approach.
parent 9866a0f9
...@@ -196,7 +196,7 @@ def pytest_namespace(): ...@@ -196,7 +196,7 @@ def pytest_namespace():
except ImportError: except ImportError:
scipy = None scipy = None
try: try:
from pybind11_tests import have_eigen from pybind11_tests.eigen import have_eigen
except ImportError: except ImportError:
have_eigen = False have_eigen = False
pypy = platform.python_implementation() == "PyPy" pypy = platform.python_implementation() == "PyPy"
......
...@@ -77,7 +77,8 @@ PYBIND11_MODULE(pybind11_tests, m) { ...@@ -77,7 +77,8 @@ PYBIND11_MODULE(pybind11_tests, m) {
.def(py::init<>()) .def(py::init<>())
.def(py::init<int>()) .def(py::init<int>())
.def("get_value", &UserType::value, "Get value using a method") .def("get_value", &UserType::value, "Get value using a method")
.def_property_readonly("value", &UserType::value, "Get value using a property") .def("set_value", &UserType::set, "Set value using a method")
.def_property("value", &UserType::value, &UserType::set, "Get/set value using a property")
.def("__repr__", [](const UserType& u) { return "UserType({})"_s.format(u.value()); }); .def("__repr__", [](const UserType& u) { return "UserType({})"_s.format(u.value()); });
py::class_<IncType, UserType>(m, "IncType") py::class_<IncType, UserType>(m, "IncType")
......
...@@ -33,6 +33,7 @@ public: ...@@ -33,6 +33,7 @@ public:
UserType(int i) : i(i) { } UserType(int i) : i(i) { }
int value() const { return i; } int value() const { return i; }
void set(int set) { i = set; }
private: private:
int i = -1; int i = -1;
......
...@@ -10,105 +10,73 @@ ...@@ -10,105 +10,73 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include "constructor_stats.h" #include "constructor_stats.h"
class Matrix { TEST_SUBMODULE(buffers, m) {
public: // test_from_python / test_to_python:
Matrix(ssize_t rows, ssize_t cols) : m_rows(rows), m_cols(cols) { class Matrix {
print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); public:
m_data = new float[(size_t) (rows*cols)]; Matrix(ssize_t rows, ssize_t cols) : m_rows(rows), m_cols(cols) {
memset(m_data, 0, sizeof(float) * (size_t) (rows * cols)); print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
} m_data = new float[(size_t) (rows*cols)];
memset(m_data, 0, sizeof(float) * (size_t) (rows * cols));
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
m_data = new float[(size_t) (m_rows * m_cols)];
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
}
Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
print_move_created(this);
s.m_rows = 0;
s.m_cols = 0;
s.m_data = nullptr;
}
~Matrix() {
print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
delete[] m_data;
}
Matrix &operator=(const Matrix &s) {
print_copy_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
delete[] m_data;
m_rows = s.m_rows;
m_cols = s.m_cols;
m_data = new float[(size_t) (m_rows * m_cols)];
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
return *this;
}
Matrix &operator=(Matrix &&s) {
print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
if (&s != this) {
delete[] m_data;
m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data;
s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr;
} }
return *this;
}
float operator()(ssize_t i, ssize_t j) const {
return m_data[(size_t) (i*m_cols + j)];
}
float &operator()(ssize_t i, ssize_t j) {
return m_data[(size_t) (i*m_cols + j)];
}
float *data() { return m_data; }
ssize_t rows() const { return m_rows; } Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
ssize_t cols() const { return m_cols; } print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
private: m_data = new float[(size_t) (m_rows * m_cols)];
ssize_t m_rows; memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
ssize_t m_cols; }
float *m_data;
};
class SquareMatrix : public Matrix {
public:
SquareMatrix(ssize_t n) : Matrix(n, n) { }
};
struct PTMFBuffer {
int32_t value = 0;
py::buffer_info get_buffer_info() {
return py::buffer_info(&value, sizeof(value),
py::format_descriptor<int32_t>::format(), 1);
}
};
class ConstPTMFBuffer { Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
std::unique_ptr<int32_t> value; print_move_created(this);
s.m_rows = 0;
s.m_cols = 0;
s.m_data = nullptr;
}
public: ~Matrix() {
int32_t get_value() const { return *value; } print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
void set_value(int32_t v) { *value = v; } delete[] m_data;
}
py::buffer_info get_buffer_info() const { Matrix &operator=(const Matrix &s) {
return py::buffer_info(value.get(), sizeof(*value), print_copy_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
py::format_descriptor<int32_t>::format(), 1); delete[] m_data;
} m_rows = s.m_rows;
m_cols = s.m_cols;
m_data = new float[(size_t) (m_rows * m_cols)];
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
return *this;
}
ConstPTMFBuffer() : value(new int32_t{0}) { }; Matrix &operator=(Matrix &&s) {
}; print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
if (&s != this) {
delete[] m_data;
m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data;
s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr;
}
return *this;
}
struct DerivedPTMFBuffer : public PTMFBuffer { }; float operator()(ssize_t i, ssize_t j) const {
return m_data[(size_t) (i*m_cols + j)];
}
test_initializer buffers([](py::module &m) { float &operator()(ssize_t i, ssize_t j) {
py::class_<Matrix> mtx(m, "Matrix", py::buffer_protocol()); return m_data[(size_t) (i*m_cols + j)];
}
mtx.def(py::init<ssize_t, ssize_t>()) float *data() { return m_data; }
ssize_t rows() const { return m_rows; }
ssize_t cols() const { return m_cols; }
private:
ssize_t m_rows;
ssize_t m_cols;
float *m_data;
};
py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
.def(py::init<ssize_t, ssize_t>())
/// Construct from a buffer /// Construct from a buffer
.def("__init__", [](Matrix &v, py::buffer b) { .def("__init__", [](Matrix &v, py::buffer b) {
py::buffer_info info = b.request(); py::buffer_info info = b.request();
...@@ -143,24 +111,57 @@ test_initializer buffers([](py::module &m) { ...@@ -143,24 +111,57 @@ test_initializer buffers([](py::module &m) {
}) })
; ;
// test_inherited_protocol
class SquareMatrix : public Matrix {
public:
SquareMatrix(ssize_t n) : Matrix(n, n) { }
};
// Derived classes inherit the buffer protocol and the buffer access function // Derived classes inherit the buffer protocol and the buffer access function
py::class_<SquareMatrix, Matrix>(m, "SquareMatrix") py::class_<SquareMatrix, Matrix>(m, "SquareMatrix")
.def(py::init<ssize_t>()); .def(py::init<ssize_t>());
py::class_<PTMFBuffer>(m, "PTMFBuffer", py::buffer_protocol())
// test_pointer_to_member_fn
// Tests that passing a pointer to member to the base class works in
// the derived class.
struct Buffer {
int32_t value = 0;
py::buffer_info get_buffer_info() {
return py::buffer_info(&value, sizeof(value),
py::format_descriptor<int32_t>::format(), 1);
}
};
py::class_<Buffer>(m, "Buffer", py::buffer_protocol())
.def(py::init<>()) .def(py::init<>())
.def_readwrite("value", &PTMFBuffer::value) .def_readwrite("value", &Buffer::value)
.def_buffer(&PTMFBuffer::get_buffer_info); .def_buffer(&Buffer::get_buffer_info);
py::class_<ConstPTMFBuffer>(m, "ConstPTMFBuffer", py::buffer_protocol()) class ConstBuffer {
std::unique_ptr<int32_t> value;
public:
int32_t get_value() const { return *value; }
void set_value(int32_t v) { *value = v; }
py::buffer_info get_buffer_info() const {
return py::buffer_info(value.get(), sizeof(*value),
py::format_descriptor<int32_t>::format(), 1);
}
ConstBuffer() : value(new int32_t{0}) { };
};
py::class_<ConstBuffer>(m, "ConstBuffer", py::buffer_protocol())
.def(py::init<>()) .def(py::init<>())
.def_property("value", &ConstPTMFBuffer::get_value, &ConstPTMFBuffer::set_value) .def_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value)
.def_buffer(&ConstPTMFBuffer::get_buffer_info); .def_buffer(&ConstBuffer::get_buffer_info);
// Tests that passing a pointer to member to the base class works in struct DerivedBuffer : public Buffer { };
// the derived class. py::class_<DerivedBuffer>(m, "DerivedBuffer", py::buffer_protocol())
py::class_<DerivedPTMFBuffer>(m, "DerivedPTMFBuffer", py::buffer_protocol())
.def(py::init<>()) .def(py::init<>())
.def_readwrite("value", (int32_t DerivedPTMFBuffer::*) &DerivedPTMFBuffer::value) .def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value)
.def_buffer(&DerivedPTMFBuffer::get_buffer_info); .def_buffer(&DerivedBuffer::get_buffer_info);
});
}
import struct import struct
import pytest import pytest
from pybind11_tests import Matrix, ConstructorStats, PTMFBuffer, ConstPTMFBuffer, DerivedPTMFBuffer from pybind11_tests import buffers as m
from pybind11_tests import ConstructorStats
pytestmark = pytest.requires_numpy pytestmark = pytest.requires_numpy
...@@ -10,17 +11,17 @@ with pytest.suppress(ImportError): ...@@ -10,17 +11,17 @@ with pytest.suppress(ImportError):
def test_from_python(): def test_from_python():
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
Matrix(np.array([1, 2, 3])) # trying to assign a 1D array m.Matrix(np.array([1, 2, 3])) # trying to assign a 1D array
assert str(excinfo.value) == "Incompatible buffer format!" assert str(excinfo.value) == "Incompatible buffer format!"
m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32)
m4 = Matrix(m3) m4 = m.Matrix(m3)
for i in range(m4.rows()): for i in range(m4.rows()):
for j in range(m4.cols()): for j in range(m4.cols()):
assert m3[i, j] == m4[i, j] assert m3[i, j] == m4[i, j]
cstats = ConstructorStats.get(Matrix) cstats = ConstructorStats.get(m.Matrix)
assert cstats.alive() == 1 assert cstats.alive() == 1
del m3, m4 del m3, m4
assert cstats.alive() == 0 assert cstats.alive() == 0
...@@ -35,26 +36,26 @@ def test_from_python(): ...@@ -35,26 +36,26 @@ def test_from_python():
# https://bitbucket.org/pypy/pypy/issues/2444 # https://bitbucket.org/pypy/pypy/issues/2444
@pytest.unsupported_on_pypy @pytest.unsupported_on_pypy
def test_to_python(): def test_to_python():
m = Matrix(5, 5) mat = m.Matrix(5, 5)
assert memoryview(m).shape == (5, 5) assert memoryview(mat).shape == (5, 5)
assert m[2, 3] == 0 assert mat[2, 3] == 0
m[2, 3] = 4 mat[2, 3] = 4
assert m[2, 3] == 4 assert mat[2, 3] == 4
m2 = np.array(m, copy=False) mat2 = np.array(mat, copy=False)
assert m2.shape == (5, 5) assert mat2.shape == (5, 5)
assert abs(m2).sum() == 4 assert abs(mat2).sum() == 4
assert m2[2, 3] == 4 assert mat2[2, 3] == 4
m2[2, 3] = 5 mat2[2, 3] = 5
assert m2[2, 3] == 5 assert mat2[2, 3] == 5
cstats = ConstructorStats.get(Matrix) cstats = ConstructorStats.get(m.Matrix)
assert cstats.alive() == 1 assert cstats.alive() == 1
del m del mat
pytest.gc_collect() pytest.gc_collect()
assert cstats.alive() == 1 assert cstats.alive() == 1
del m2 # holds an m reference del mat2 # holds a mat reference
pytest.gc_collect() pytest.gc_collect()
assert cstats.alive() == 0 assert cstats.alive() == 0
assert cstats.values() == ["5x5 matrix"] assert cstats.values() == ["5x5 matrix"]
...@@ -67,16 +68,15 @@ def test_to_python(): ...@@ -67,16 +68,15 @@ def test_to_python():
@pytest.unsupported_on_pypy @pytest.unsupported_on_pypy
def test_inherited_protocol(): def test_inherited_protocol():
"""SquareMatrix is derived from Matrix and inherits the buffer protocol""" """SquareMatrix is derived from Matrix and inherits the buffer protocol"""
from pybind11_tests import SquareMatrix
matrix = SquareMatrix(5) matrix = m.SquareMatrix(5)
assert memoryview(matrix).shape == (5, 5) assert memoryview(matrix).shape == (5, 5)
assert np.asarray(matrix).shape == (5, 5) assert np.asarray(matrix).shape == (5, 5)
@pytest.unsupported_on_pypy @pytest.unsupported_on_pypy
def test_ptmf(): def test_pointer_to_member_fn():
for cls in [PTMFBuffer, ConstPTMFBuffer, DerivedPTMFBuffer]: for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]:
buf = cls() buf = cls()
buf.value = 0x12345678 buf.value = 0x12345678
value = struct.unpack('i', bytearray(buf))[0] value = struct.unpack('i', bytearray(buf))[0]
......
...@@ -9,47 +9,6 @@ ...@@ -9,47 +9,6 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
class Child {
public:
Child() { py::print("Allocating child."); }
~Child() { py::print("Releasing child."); }
};
class Parent {
public:
Parent() { py::print("Allocating parent."); }
~Parent() { py::print("Releasing parent."); }
void addChild(Child *) { }
Child *returnChild() { return new Child(); }
Child *returnNullChild() { return nullptr; }
};
#if !defined(PYPY_VERSION)
class ParentGC : public Parent {
public:
using Parent::Parent;
};
#endif
test_initializer keep_alive([](py::module &m) {
py::class_<Parent>(m, "Parent")
.def(py::init<>())
.def("addChild", &Parent::addChild)
.def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>())
.def("returnChild", &Parent::returnChild)
.def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>())
.def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>())
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>());
#if !defined(PYPY_VERSION)
py::class_<ParentGC, Parent>(m, "ParentGC", py::dynamic_attr())
.def(py::init<>());
#endif
py::class_<Child>(m, "Child")
.def(py::init<>());
});
struct CustomGuard { struct CustomGuard {
static bool enabled; static bool enabled;
...@@ -58,7 +17,6 @@ struct CustomGuard { ...@@ -58,7 +17,6 @@ struct CustomGuard {
static const char *report_status() { return enabled ? "guarded" : "unguarded"; } static const char *report_status() { return enabled ? "guarded" : "unguarded"; }
}; };
bool CustomGuard::enabled = false; bool CustomGuard::enabled = false;
struct DependentGuard { struct DependentGuard {
...@@ -69,12 +27,48 @@ struct DependentGuard { ...@@ -69,12 +27,48 @@ struct DependentGuard {
static const char *report_status() { return enabled ? "guarded" : "unguarded"; } static const char *report_status() { return enabled ? "guarded" : "unguarded"; }
}; };
bool DependentGuard::enabled = false; bool DependentGuard::enabled = false;
test_initializer call_guard([](py::module &pm) { TEST_SUBMODULE(call_policies, m) {
auto m = pm.def_submodule("call_policies"); // Parent/Child are used in:
// test_keep_alive_argument, test_keep_alive_return_value, test_alive_gc_derived,
// test_alive_gc_multi_derived, test_return_none
class Child {
public:
Child() { py::print("Allocating child."); }
~Child() { py::print("Releasing child."); }
};
py::class_<Child>(m, "Child")
.def(py::init<>());
class Parent {
public:
Parent() { py::print("Allocating parent."); }
~Parent() { py::print("Releasing parent."); }
void addChild(Child *) { }
Child *returnChild() { return new Child(); }
Child *returnNullChild() { return nullptr; }
};
py::class_<Parent>(m, "Parent")
.def(py::init<>())
.def("addChild", &Parent::addChild)
.def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>())
.def("returnChild", &Parent::returnChild)
.def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>())
.def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>())
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>());
#if !defined(PYPY_VERSION)
// test_alive_gc
class ParentGC : public Parent {
public:
using Parent::Parent;
};
py::class_<ParentGC, Parent>(m, "ParentGC", py::dynamic_attr())
.def(py::init<>());
#endif
// test_call_guard
m.def("unguarded_call", &CustomGuard::report_status); m.def("unguarded_call", &CustomGuard::report_status);
m.def("guarded_call", &CustomGuard::report_status, py::call_guard<CustomGuard>()); m.def("guarded_call", &CustomGuard::report_status, py::call_guard<CustomGuard>());
...@@ -100,4 +94,4 @@ test_initializer call_guard([](py::module &pm) { ...@@ -100,4 +94,4 @@ test_initializer call_guard([](py::module &pm) {
m.def("with_gil", report_gil_status); m.def("with_gil", report_gil_status);
m.def("without_gil", report_gil_status, py::call_guard<py::gil_scoped_release>()); m.def("without_gil", report_gil_status, py::call_guard<py::gil_scoped_release>());
#endif #endif
}); }
import pytest import pytest
from pybind11_tests import call_policies as m
from pybind11_tests import ConstructorStats
def test_keep_alive_argument(capture): def test_keep_alive_argument(capture):
from pybind11_tests import Parent, Child, ConstructorStats
n_inst = ConstructorStats.detail_reg_inst() n_inst = ConstructorStats.detail_reg_inst()
with capture: with capture:
p = Parent() p = m.Parent()
assert capture == "Allocating parent." assert capture == "Allocating parent."
with capture: with capture:
p.addChild(Child()) p.addChild(m.Child())
assert ConstructorStats.detail_reg_inst() == n_inst + 1 assert ConstructorStats.detail_reg_inst() == n_inst + 1
assert capture == """ assert capture == """
Allocating child. Allocating child.
...@@ -21,10 +21,10 @@ def test_keep_alive_argument(capture): ...@@ -21,10 +21,10 @@ def test_keep_alive_argument(capture):
assert capture == "Releasing parent." assert capture == "Releasing parent."
with capture: with capture:
p = Parent() p = m.Parent()
assert capture == "Allocating parent." assert capture == "Allocating parent."
with capture: with capture:
p.addChildKeepAlive(Child()) p.addChildKeepAlive(m.Child())
assert ConstructorStats.detail_reg_inst() == n_inst + 2 assert ConstructorStats.detail_reg_inst() == n_inst + 2
assert capture == "Allocating child." assert capture == "Allocating child."
with capture: with capture:
...@@ -37,11 +37,9 @@ def test_keep_alive_argument(capture): ...@@ -37,11 +37,9 @@ def test_keep_alive_argument(capture):
def test_keep_alive_return_value(capture): def test_keep_alive_return_value(capture):
from pybind11_tests import Parent, ConstructorStats
n_inst = ConstructorStats.detail_reg_inst() n_inst = ConstructorStats.detail_reg_inst()
with capture: with capture:
p = Parent() p = m.Parent()
assert capture == "Allocating parent." assert capture == "Allocating parent."
with capture: with capture:
p.returnChild() p.returnChild()
...@@ -56,7 +54,7 @@ def test_keep_alive_return_value(capture): ...@@ -56,7 +54,7 @@ def test_keep_alive_return_value(capture):
assert capture == "Releasing parent." assert capture == "Releasing parent."
with capture: with capture:
p = Parent() p = m.Parent()
assert capture == "Allocating parent." assert capture == "Allocating parent."
with capture: with capture:
p.returnChildKeepAlive() p.returnChildKeepAlive()
...@@ -74,11 +72,9 @@ def test_keep_alive_return_value(capture): ...@@ -74,11 +72,9 @@ def test_keep_alive_return_value(capture):
# https://bitbucket.org/pypy/pypy/issues/2447 # https://bitbucket.org/pypy/pypy/issues/2447
@pytest.unsupported_on_pypy @pytest.unsupported_on_pypy
def test_alive_gc(capture): def test_alive_gc(capture):
from pybind11_tests import ParentGC, Child, ConstructorStats
n_inst = ConstructorStats.detail_reg_inst() n_inst = ConstructorStats.detail_reg_inst()
p = ParentGC() p = m.ParentGC()
p.addChildKeepAlive(Child()) p.addChildKeepAlive(m.Child())
assert ConstructorStats.detail_reg_inst() == n_inst + 2 assert ConstructorStats.detail_reg_inst() == n_inst + 2
lst = [p] lst = [p]
lst.append(lst) # creates a circular reference lst.append(lst) # creates a circular reference
...@@ -92,14 +88,12 @@ def test_alive_gc(capture): ...@@ -92,14 +88,12 @@ def test_alive_gc(capture):
def test_alive_gc_derived(capture): def test_alive_gc_derived(capture):
from pybind11_tests import Parent, Child, ConstructorStats class Derived(m.Parent):
class Derived(Parent):
pass pass
n_inst = ConstructorStats.detail_reg_inst() n_inst = ConstructorStats.detail_reg_inst()
p = Derived() p = Derived()
p.addChildKeepAlive(Child()) p.addChildKeepAlive(m.Child())
assert ConstructorStats.detail_reg_inst() == n_inst + 2 assert ConstructorStats.detail_reg_inst() == n_inst + 2
lst = [p] lst = [p]
lst.append(lst) # creates a circular reference lst.append(lst) # creates a circular reference
...@@ -113,16 +107,14 @@ def test_alive_gc_derived(capture): ...@@ -113,16 +107,14 @@ def test_alive_gc_derived(capture):
def test_alive_gc_multi_derived(capture): def test_alive_gc_multi_derived(capture):
from pybind11_tests import Parent, Child, ConstructorStats class Derived(m.Parent, m.Child):
class Derived(Parent, Child):
def __init__(self): def __init__(self):
Parent.__init__(self) m.Parent.__init__(self)
Child.__init__(self) m.Child.__init__(self)
n_inst = ConstructorStats.detail_reg_inst() n_inst = ConstructorStats.detail_reg_inst()
p = Derived() p = Derived()
p.addChildKeepAlive(Child()) p.addChildKeepAlive(m.Child())
# +3 rather than +2 because Derived corresponds to two registered instances # +3 rather than +2 because Derived corresponds to two registered instances
assert ConstructorStats.detail_reg_inst() == n_inst + 3 assert ConstructorStats.detail_reg_inst() == n_inst + 3
lst = [p] lst = [p]
...@@ -138,11 +130,9 @@ def test_alive_gc_multi_derived(capture): ...@@ -138,11 +130,9 @@ def test_alive_gc_multi_derived(capture):
def test_return_none(capture): def test_return_none(capture):
from pybind11_tests import Parent, ConstructorStats
n_inst = ConstructorStats.detail_reg_inst() n_inst = ConstructorStats.detail_reg_inst()
with capture: with capture:
p = Parent() p = m.Parent()
assert capture == "Allocating parent." assert capture == "Allocating parent."
with capture: with capture:
p.returnNullChildKeepAliveChild() p.returnNullChildKeepAliveChild()
...@@ -154,7 +144,7 @@ def test_return_none(capture): ...@@ -154,7 +144,7 @@ def test_return_none(capture):
assert capture == "Releasing parent." assert capture == "Releasing parent."
with capture: with capture:
p = Parent() p = m.Parent()
assert capture == "Allocating parent." assert capture == "Allocating parent."
with capture: with capture:
p.returnNullChildKeepAliveParent() p.returnNullChildKeepAliveParent()
...@@ -167,14 +157,12 @@ def test_return_none(capture): ...@@ -167,14 +157,12 @@ def test_return_none(capture):
def test_call_guard(): def test_call_guard():
from pybind11_tests import call_policies assert m.unguarded_call() == "unguarded"
assert m.guarded_call() == "guarded"
assert call_policies.unguarded_call() == "unguarded"
assert call_policies.guarded_call() == "guarded"
assert call_policies.multiple_guards_correct_order() == "guarded & guarded" assert m.multiple_guards_correct_order() == "guarded & guarded"
assert call_policies.multiple_guards_wrong_order() == "unguarded & guarded" assert m.multiple_guards_wrong_order() == "unguarded & guarded"
if hasattr(call_policies, "with_gil"): if hasattr(m, "with_gil"):
assert call_policies.with_gil() == "GIL held" assert m.with_gil() == "GIL held"
assert call_policies.without_gil() == "GIL released" assert m.without_gil() == "GIL released"
...@@ -12,94 +12,20 @@ ...@@ -12,94 +12,20 @@
#include <pybind11/functional.h> #include <pybind11/functional.h>
py::object test_callback1(py::object func) {
return func();
}
py::tuple test_callback2(py::object func) {
return func("Hello", 'x', true, 5);
}
std::string test_callback3(const std::function<int(int)> &func) {
return "func(43) = " + std::to_string(func(43));
}
std::function<int(int)> test_callback4() {
return [](int i) { return i+1; };
}
py::cpp_function test_callback5() {
return py::cpp_function([](int i) { return i+1; },
py::arg("number"));
}
int dummy_function(int i) { return i + 1; } int dummy_function(int i) { return i + 1; }
int dummy_function2(int i, int j) { return i + j; }
std::function<int(int)> roundtrip(std::function<int(int)> f, bool expect_none = false) {
if (expect_none && f) {
throw std::runtime_error("Expected None to be converted to empty std::function");
}
return f;
}
std::string test_dummy_function(const std::function<int(int)> &f) { TEST_SUBMODULE(callbacks, m) {
using fn_type = int (*)(int); // test_callbacks, test_function_signatures
auto result = f.target<fn_type>(); m.def("test_callback1", [](py::object func) { return func(); });
if (!result) { m.def("test_callback2", [](py::object func) { return func("Hello", 'x', true, 5); });
auto r = f(1); m.def("test_callback3", [](const std::function<int(int)> &func) {
return "can't convert to function pointer: eval(1) = " + std::to_string(r); return "func(43) = " + std::to_string(func(43)); });
} else if (*result == dummy_function) { m.def("test_callback4", []() -> std::function<int(int)> { return [](int i) { return i+1; }; });
auto r = (*result)(1); m.def("test_callback5", []() {
return "matches dummy_function: eval(1) = " + std::to_string(r); return py::cpp_function([](int i) { return i+1; }, py::arg("number"));
} else { });
return "argument does NOT match dummy_function. This should never happen!";
}
}
struct Payload { // test_keyword_args_and_generalized_unpacking
Payload() {
print_default_created(this);
}
~Payload() {
print_destroyed(this);
}
Payload(const Payload &) {
print_copy_created(this);
}
Payload(Payload &&) {
print_move_created(this);
}
};
class AbstractBase {
public:
virtual unsigned int func() = 0;
};
void func_accepting_func_accepting_base(std::function<double(AbstractBase&)>) { }
struct MovableObject {
bool valid = true;
MovableObject() = default;
MovableObject(const MovableObject &) = default;
MovableObject &operator=(const MovableObject &) = default;
MovableObject(MovableObject &&o) : valid(o.valid) { o.valid = false; }
MovableObject &operator=(MovableObject &&o) {
valid = o.valid;
o.valid = false;
return *this;
}
};
test_initializer callbacks([](py::module &m) {
m.def("test_callback1", &test_callback1);
m.def("test_callback2", &test_callback2);
m.def("test_callback3", &test_callback3);
m.def("test_callback4", &test_callback4);
m.def("test_callback5", &test_callback5);
// Test keyword args and generalized unpacking
m.def("test_tuple_unpacking", [](py::function f) { m.def("test_tuple_unpacking", [](py::function f) {
auto t1 = py::make_tuple(2, 3); auto t1 = py::make_tuple(2, 3);
auto t2 = py::make_tuple(5, 6); auto t2 = py::make_tuple(5, 6);
...@@ -148,6 +74,15 @@ test_initializer callbacks([](py::module &m) { ...@@ -148,6 +74,15 @@ test_initializer callbacks([](py::module &m) {
f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567); f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567);
}); });
// test_lambda_closure_cleanup
struct Payload {
Payload() { print_default_created(this); }
~Payload() { print_destroyed(this); }
Payload(const Payload &) { print_copy_created(this); }
Payload(Payload &&) { print_move_created(this); }
};
// Export the payload constructor statistics for testing purposes:
m.def("payload_cstats", &ConstructorStats::get<Payload>);
/* Test cleanup of lambda closure */ /* Test cleanup of lambda closure */
m.def("test_cleanup", []() -> std::function<void(void)> { m.def("test_cleanup", []() -> std::function<void(void)> {
Payload p; Payload p;
...@@ -158,27 +93,57 @@ test_initializer callbacks([](py::module &m) { ...@@ -158,27 +93,57 @@ test_initializer callbacks([](py::module &m) {
}; };
}); });
// test_cpp_function_roundtrip
/* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */ /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
m.def("dummy_function", &dummy_function); m.def("dummy_function", &dummy_function);
m.def("dummy_function2", &dummy_function2); m.def("dummy_function2", [](int i, int j) { return i + j; });
m.def("roundtrip", &roundtrip, py::arg("f"), py::arg("expect_none")=false); m.def("roundtrip", [](std::function<int(int)> f, bool expect_none = false) {
m.def("test_dummy_function", &test_dummy_function); if (expect_none && f)
// Export the payload constructor statistics for testing purposes: throw std::runtime_error("Expected None to be converted to empty std::function");
m.def("payload_cstats", &ConstructorStats::get<Payload>); return f;
}, py::arg("f"), py::arg("expect_none")=false);
m.def("func_accepting_func_accepting_base", m.def("test_dummy_function", [](const std::function<int(int)> &f) -> std::string {
func_accepting_func_accepting_base); using fn_type = int (*)(int);
auto result = f.target<fn_type>();
if (!result) {
auto r = f(1);
return "can't convert to function pointer: eval(1) = " + std::to_string(r);
} else if (*result == dummy_function) {
auto r = (*result)(1);
return "matches dummy_function: eval(1) = " + std::to_string(r);
} else {
return "argument does NOT match dummy_function. This should never happen!";
}
});
class AbstractBase { public: virtual unsigned int func() = 0; };
m.def("func_accepting_func_accepting_base", [](std::function<double(AbstractBase&)>) { });
struct MovableObject {
bool valid = true;
MovableObject() = default;
MovableObject(const MovableObject &) = default;
MovableObject &operator=(const MovableObject &) = default;
MovableObject(MovableObject &&o) : valid(o.valid) { o.valid = false; }
MovableObject &operator=(MovableObject &&o) {
valid = o.valid;
o.valid = false;
return *this;
}
};
py::class_<MovableObject>(m, "MovableObject"); py::class_<MovableObject>(m, "MovableObject");
// test_movable_object
m.def("callback_with_movable", [](std::function<void(MovableObject &)> f) { m.def("callback_with_movable", [](std::function<void(MovableObject &)> f) {
auto x = MovableObject(); auto x = MovableObject();
f(x); // lvalue reference shouldn't move out object f(x); // lvalue reference shouldn't move out object
return x.valid; // must still return `true` return x.valid; // must still return `true`
}); });
// test_bound_method_callback
struct CppBoundMethodTest {}; struct CppBoundMethodTest {};
py::class_<CppBoundMethodTest>(m, "CppBoundMethodTest") py::class_<CppBoundMethodTest>(m, "CppBoundMethodTest")
.def(py::init<>()) .def(py::init<>())
.def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; }); .def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; });
}); }
import pytest import pytest
from pybind11_tests import callbacks as m
def test_callbacks(): def test_callbacks():
from functools import partial from functools import partial
from pybind11_tests import (test_callback1, test_callback2, test_callback3,
test_callback4, test_callback5)
def func1(): def func1():
return "func1" return "func1"
...@@ -15,73 +14,65 @@ def test_callbacks(): ...@@ -15,73 +14,65 @@ def test_callbacks():
def func3(a): def func3(a):
return "func3({})".format(a) return "func3({})".format(a)
assert test_callback1(func1) == "func1" assert m.test_callback1(func1) == "func1"
assert test_callback2(func2) == ("func2", "Hello", "x", True, 5) assert m.test_callback2(func2) == ("func2", "Hello", "x", True, 5)
assert test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4) assert m.test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4)
assert test_callback1(partial(func3, "partial")) == "func3(partial)" assert m.test_callback1(partial(func3, "partial")) == "func3(partial)"
assert test_callback3(lambda i: i + 1) == "func(43) = 44" assert m.test_callback3(lambda i: i + 1) == "func(43) = 44"
f = test_callback4() f = m.test_callback4()
assert f(43) == 44 assert f(43) == 44
f = test_callback5() f = m.test_callback5()
assert f(number=43) == 44 assert f(number=43) == 44
def test_bound_method_callback(): def test_bound_method_callback():
from pybind11_tests import test_callback3, CppBoundMethodTest
# Bound Python method: # Bound Python method:
class MyClass: class MyClass:
def double(self, val): def double(self, val):
return 2 * val return 2 * val
z = MyClass() z = MyClass()
assert test_callback3(z.double) == "func(43) = 86" assert m.test_callback3(z.double) == "func(43) = 86"
z = CppBoundMethodTest() z = m.CppBoundMethodTest()
assert test_callback3(z.triple) == "func(43) = 129" assert m.test_callback3(z.triple) == "func(43) = 129"
def test_keyword_args_and_generalized_unpacking(): def test_keyword_args_and_generalized_unpacking():
from pybind11_tests import (test_tuple_unpacking, test_dict_unpacking, test_keyword_args,
test_unpacking_and_keywords1, test_unpacking_and_keywords2,
test_unpacking_error1, test_unpacking_error2,
test_arg_conversion_error1, test_arg_conversion_error2)
def f(*args, **kwargs): def f(*args, **kwargs):
return args, kwargs return args, kwargs
assert test_tuple_unpacking(f) == (("positional", 1, 2, 3, 4, 5, 6), {}) assert m.test_tuple_unpacking(f) == (("positional", 1, 2, 3, 4, 5, 6), {})
assert test_dict_unpacking(f) == (("positional", 1), {"key": "value", "a": 1, "b": 2}) assert m.test_dict_unpacking(f) == (("positional", 1), {"key": "value", "a": 1, "b": 2})
assert test_keyword_args(f) == ((), {"x": 10, "y": 20}) assert m.test_keyword_args(f) == ((), {"x": 10, "y": 20})
assert test_unpacking_and_keywords1(f) == ((1, 2), {"c": 3, "d": 4}) assert m.test_unpacking_and_keywords1(f) == ((1, 2), {"c": 3, "d": 4})
assert test_unpacking_and_keywords2(f) == ( assert m.test_unpacking_and_keywords2(f) == (
("positional", 1, 2, 3, 4, 5), ("positional", 1, 2, 3, 4, 5),
{"key": "value", "a": 1, "b": 2, "c": 3, "d": 4, "e": 5} {"key": "value", "a": 1, "b": 2, "c": 3, "d": 4, "e": 5}
) )
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
test_unpacking_error1(f) m.test_unpacking_error1(f)
assert "Got multiple values for keyword argument" in str(excinfo.value) assert "Got multiple values for keyword argument" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
test_unpacking_error2(f) m.test_unpacking_error2(f)
assert "Got multiple values for keyword argument" in str(excinfo.value) assert "Got multiple values for keyword argument" in str(excinfo.value)
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
test_arg_conversion_error1(f) m.test_arg_conversion_error1(f)
assert "Unable to convert call argument" in str(excinfo.value) assert "Unable to convert call argument" in str(excinfo.value)
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
test_arg_conversion_error2(f) m.test_arg_conversion_error2(f)
assert "Unable to convert call argument" in str(excinfo.value) assert "Unable to convert call argument" in str(excinfo.value)
def test_lambda_closure_cleanup(): def test_lambda_closure_cleanup():
from pybind11_tests import test_cleanup, payload_cstats m.test_cleanup()
cstats = m.payload_cstats()
test_cleanup()
cstats = payload_cstats()
assert cstats.alive() == 0 assert cstats.alive() == 0
assert cstats.copy_constructions == 1 assert cstats.copy_constructions == 1
assert cstats.move_constructions >= 1 assert cstats.move_constructions >= 1
...@@ -89,31 +80,28 @@ def test_lambda_closure_cleanup(): ...@@ -89,31 +80,28 @@ def test_lambda_closure_cleanup():
def test_cpp_function_roundtrip(): def test_cpp_function_roundtrip():
"""Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer""" """Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer"""
from pybind11_tests import dummy_function, dummy_function2, test_dummy_function, roundtrip
assert test_dummy_function(dummy_function) == "matches dummy_function: eval(1) = 2" assert m.test_dummy_function(m.dummy_function) == "matches dummy_function: eval(1) = 2"
assert test_dummy_function(roundtrip(dummy_function)) == "matches dummy_function: eval(1) = 2" assert (m.test_dummy_function(m.roundtrip(m.dummy_function)) ==
assert roundtrip(None, expect_none=True) is None "matches dummy_function: eval(1) = 2")
assert test_dummy_function(lambda x: x + 2) == "can't convert to function pointer: eval(1) = 3" assert m.roundtrip(None, expect_none=True) is None
assert (m.test_dummy_function(lambda x: x + 2) ==
"can't convert to function pointer: eval(1) = 3")
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
test_dummy_function(dummy_function2) m.test_dummy_function(m.dummy_function2)
assert "incompatible function arguments" in str(excinfo.value) assert "incompatible function arguments" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
test_dummy_function(lambda x, y: x + y) m.test_dummy_function(lambda x, y: x + y)
assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument", assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument",
"takes exactly 2 arguments")) "takes exactly 2 arguments"))
def test_function_signatures(doc): def test_function_signatures(doc):
from pybind11_tests import test_callback3, test_callback4 assert doc(m.test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str"
assert doc(m.test_callback4) == "test_callback4() -> Callable[[int], int]"
assert doc(test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str"
assert doc(test_callback4) == "test_callback4() -> Callable[[int], int]"
def test_movable_object(): def test_movable_object():
from pybind11_tests import callback_with_movable assert m.callback_with_movable(lambda _: None) is True
assert callback_with_movable(lambda _: None) is True
...@@ -8,58 +8,40 @@ ...@@ -8,58 +8,40 @@
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_tests.h"
#include "constructor_stats.h"
#include <pybind11/chrono.h> #include <pybind11/chrono.h>
// Return the current time off the wall clock TEST_SUBMODULE(chrono, m) {
std::chrono::system_clock::time_point test_chrono1() { using system_time = std::chrono::system_clock::time_point;
return std::chrono::system_clock::now(); using steady_time = std::chrono::steady_clock::time_point;
} // test_chrono_system_clock
// Return the current time off the wall clock
m.def("test_chrono1", []() { return std::chrono::system_clock::now(); });
// Round trip the passed in system clock time // test_chrono_system_clock_roundtrip
std::chrono::system_clock::time_point test_chrono2(std::chrono::system_clock::time_point t) { // Round trip the passed in system clock time
return t; m.def("test_chrono2", [](system_time t) { return t; });
}
// Round trip the passed in duration
std::chrono::system_clock::duration test_chrono3(std::chrono::system_clock::duration d) {
return d;
}
// Difference between two passed in time_points // test_chrono_duration_roundtrip
std::chrono::system_clock::duration test_chrono4(std::chrono::system_clock::time_point a, std::chrono::system_clock::time_point b) { // Round trip the passed in duration
return a - b; m.def("test_chrono3", [](std::chrono::system_clock::duration d) { return d; });
}
// Return the current time off the steady_clock // test_chrono_duration_subtraction_equivalence
std::chrono::steady_clock::time_point test_chrono5() { // Difference between two passed in time_points
return std::chrono::steady_clock::now(); m.def("test_chrono4", [](system_time a, system_time b) { return a - b; });
}
// Round trip a steady clock timepoint // test_chrono_steady_clock
std::chrono::steady_clock::time_point test_chrono6(std::chrono::steady_clock::time_point t) { // Return the current time off the steady_clock
return t; m.def("test_chrono5", []() { return std::chrono::steady_clock::now(); });
}
// Roundtrip a duration in microseconds from a float argument // test_chrono_steady_clock_roundtrip
std::chrono::microseconds test_chrono7(std::chrono::microseconds t) { // Round trip a steady clock timepoint
return t; m.def("test_chrono6", [](steady_time t) { return t; });
}
// Float durations (issue #719) // test_floating_point_duration
std::chrono::duration<double> test_chrono_float_diff(std::chrono::duration<float> a, std::chrono::duration<float> b) { // Roundtrip a duration in microseconds from a float argument
return a - b; m.def("test_chrono7", [](std::chrono::microseconds t) { return t; });
// Float durations (issue #719)
m.def("test_chrono_float_diff", [](std::chrono::duration<float> a, std::chrono::duration<float> b) {
return a - b; });
} }
test_initializer chrono([] (py::module &m) {
m.def("test_chrono1", &test_chrono1);
m.def("test_chrono2", &test_chrono2);
m.def("test_chrono3", &test_chrono3);
m.def("test_chrono4", &test_chrono4);
m.def("test_chrono5", &test_chrono5);
m.def("test_chrono6", &test_chrono6);
m.def("test_chrono7", &test_chrono7);
m.def("test_chrono_float_diff", &test_chrono_float_diff);
});
from pybind11_tests import chrono as m
import datetime
def test_chrono_system_clock(): def test_chrono_system_clock():
from pybind11_tests import test_chrono1
import datetime
# Get the time from both c++ and datetime # Get the time from both c++ and datetime
date1 = test_chrono1() date1 = m.test_chrono1()
date2 = datetime.datetime.today() date2 = datetime.datetime.today()
# The returned value should be a datetime # The returned value should be a datetime
...@@ -25,13 +25,10 @@ def test_chrono_system_clock(): ...@@ -25,13 +25,10 @@ def test_chrono_system_clock():
def test_chrono_system_clock_roundtrip(): def test_chrono_system_clock_roundtrip():
from pybind11_tests import test_chrono2
import datetime
date1 = datetime.datetime.today() date1 = datetime.datetime.today()
# Roundtrip the time # Roundtrip the time
date2 = test_chrono2(date1) date2 = m.test_chrono2(date1)
# The returned value should be a datetime # The returned value should be a datetime
assert isinstance(date2, datetime.datetime) assert isinstance(date2, datetime.datetime)
...@@ -44,8 +41,6 @@ def test_chrono_system_clock_roundtrip(): ...@@ -44,8 +41,6 @@ def test_chrono_system_clock_roundtrip():
def test_chrono_duration_roundtrip(): def test_chrono_duration_roundtrip():
from pybind11_tests import test_chrono3
import datetime
# Get the difference between two times (a timedelta) # Get the difference between two times (a timedelta)
date1 = datetime.datetime.today() date1 = datetime.datetime.today()
...@@ -55,7 +50,7 @@ def test_chrono_duration_roundtrip(): ...@@ -55,7 +50,7 @@ def test_chrono_duration_roundtrip():
# Make sure this is a timedelta # Make sure this is a timedelta
assert isinstance(diff, datetime.timedelta) assert isinstance(diff, datetime.timedelta)
cpp_diff = test_chrono3(diff) cpp_diff = m.test_chrono3(diff)
assert cpp_diff.days == diff.days assert cpp_diff.days == diff.days
assert cpp_diff.seconds == diff.seconds assert cpp_diff.seconds == diff.seconds
...@@ -63,14 +58,12 @@ def test_chrono_duration_roundtrip(): ...@@ -63,14 +58,12 @@ def test_chrono_duration_roundtrip():
def test_chrono_duration_subtraction_equivalence(): def test_chrono_duration_subtraction_equivalence():
from pybind11_tests import test_chrono4
import datetime
date1 = datetime.datetime.today() date1 = datetime.datetime.today()
date2 = datetime.datetime.today() date2 = datetime.datetime.today()
diff = date2 - date1 diff = date2 - date1
cpp_diff = test_chrono4(date2, date1) cpp_diff = m.test_chrono4(date2, date1)
assert cpp_diff.days == diff.days assert cpp_diff.days == diff.days
assert cpp_diff.seconds == diff.seconds assert cpp_diff.seconds == diff.seconds
...@@ -78,22 +71,13 @@ def test_chrono_duration_subtraction_equivalence(): ...@@ -78,22 +71,13 @@ def test_chrono_duration_subtraction_equivalence():
def test_chrono_steady_clock(): def test_chrono_steady_clock():
from pybind11_tests import test_chrono5 time1 = m.test_chrono5()
import datetime
time1 = test_chrono5()
time2 = test_chrono5()
assert isinstance(time1, datetime.timedelta) assert isinstance(time1, datetime.timedelta)
assert isinstance(time2, datetime.timedelta)
def test_chrono_steady_clock_roundtrip(): def test_chrono_steady_clock_roundtrip():
from pybind11_tests import test_chrono6
import datetime
time1 = datetime.timedelta(days=10, seconds=10, microseconds=100) time1 = datetime.timedelta(days=10, seconds=10, microseconds=100)
time2 = test_chrono6(time1) time2 = m.test_chrono6(time1)
assert isinstance(time2, datetime.timedelta) assert isinstance(time2, datetime.timedelta)
...@@ -104,17 +88,14 @@ def test_chrono_steady_clock_roundtrip(): ...@@ -104,17 +88,14 @@ def test_chrono_steady_clock_roundtrip():
def test_floating_point_duration(): def test_floating_point_duration():
from pybind11_tests import test_chrono7, test_chrono_float_diff # Test using a floating point number in seconds
import datetime time = m.test_chrono7(35.525123)
# Test using 35.525123 seconds as an example floating point number in seconds
time = test_chrono7(35.525123)
assert isinstance(time, datetime.timedelta) assert isinstance(time, datetime.timedelta)
assert time.seconds == 35 assert time.seconds == 35
assert 525122 <= time.microseconds <= 525123 assert 525122 <= time.microseconds <= 525123
diff = test_chrono_float_diff(43.789012, 1.123456) diff = m.test_chrono_float_diff(43.789012, 1.123456)
assert diff.seconds == 42 assert diff.seconds == 42
assert 665556 <= diff.microseconds <= 665557 assert 665556 <= diff.microseconds <= 665557
...@@ -35,7 +35,7 @@ def test_docstrings(doc): ...@@ -35,7 +35,7 @@ def test_docstrings(doc):
Get value using a method Get value using a method
""" """
assert doc(UserType.value) == "Get value using a property" assert doc(UserType.value) == "Get/set value using a property"
assert doc(m.NoConstructor.new_instance) == """ assert doc(m.NoConstructor.new_instance) == """
new_instance() -> m.class_.NoConstructor new_instance() -> m.class_.NoConstructor
......
...@@ -23,6 +23,8 @@ std::string test_function3(int i) { ...@@ -23,6 +23,8 @@ 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(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)"; }
...@@ -61,17 +63,23 @@ struct C { ...@@ -61,17 +63,23 @@ struct C {
} }
test_initializer constants_and_functions([](py::module &m) { TEST_SUBMODULE(constants_and_functions, m) {
// test_constants
m.attr("some_constant") = py::int_(14); m.attr("some_constant") = py::int_(14);
// test_function_overloading
m.def("test_function", &test_function1); m.def("test_function", &test_function1);
m.def("test_function", &test_function2); m.def("test_function", &test_function2);
m.def("test_function", &test_function3); m.def("test_function", &test_function3);
#if defined(PYBIND11_OVERLOAD_CAST) #if defined(PYBIND11_OVERLOAD_CAST)
m.def("test_function", py::overload_cast<>(&test_function4));
m.def("test_function", py::overload_cast<char *>(&test_function4));
m.def("test_function", py::overload_cast<int, float>(&test_function4)); m.def("test_function", py::overload_cast<int, float>(&test_function4));
m.def("test_function", py::overload_cast<float, int>(&test_function4)); m.def("test_function", py::overload_cast<float, int>(&test_function4));
#else #else
m.def("test_function", static_cast<py::str (*)()>(&test_function4));
m.def("test_function", static_cast<py::str (*)(char *)>(&test_function4));
m.def("test_function", static_cast<py::str (*)(int, float)>(&test_function4)); m.def("test_function", static_cast<py::str (*)(int, float)>(&test_function4));
m.def("test_function", static_cast<py::str (*)(float, int)>(&test_function4)); m.def("test_function", static_cast<py::str (*)(float, int)>(&test_function4));
#endif #endif
...@@ -81,12 +89,13 @@ test_initializer constants_and_functions([](py::module &m) { ...@@ -81,12 +89,13 @@ test_initializer constants_and_functions([](py::module &m) {
.value("ESecondEntry", ESecondEntry) .value("ESecondEntry", ESecondEntry)
.export_values(); .export_values();
// test_bytes
m.def("return_bytes", &return_bytes); m.def("return_bytes", &return_bytes);
m.def("print_bytes", &print_bytes); m.def("print_bytes", &print_bytes);
// test_exception_specifiers
using namespace test_exc_sp; using namespace test_exc_sp;
py::module m2 = m.def_submodule("exc_sp"); py::class_<C>(m, "C")
py::class_<C>(m2, "C")
.def(py::init<>()) .def(py::init<>())
.def("m1", &C::m1) .def("m1", &C::m1)
.def("m2", &C::m2) .def("m2", &C::m2)
...@@ -97,8 +106,8 @@ test_initializer constants_and_functions([](py::module &m) { ...@@ -97,8 +106,8 @@ test_initializer constants_and_functions([](py::module &m) {
.def("m7", &C::m7) .def("m7", &C::m7)
.def("m8", &C::m8) .def("m8", &C::m8)
; ;
m2.def("f1", f1); m.def("f1", f1);
m2.def("f2", f2); m.def("f2", f2);
m2.def("f3", f3); m.def("f3", f3);
m2.def("f4", f4); m.def("f4", f4);
}); }
from pybind11_tests import constants_and_functions as m
def test_constants(): def test_constants():
from pybind11_tests import some_constant assert m.some_constant == 14
assert some_constant == 14
def test_function_overloading(): def test_function_overloading():
from pybind11_tests import MyEnum, test_function assert m.test_function() == "test_function()"
assert m.test_function(7) == "test_function(7)"
assert test_function() == "test_function()" assert m.test_function(m.MyEnum.EFirstEntry) == "test_function(enum=1)"
assert test_function(7) == "test_function(7)" assert m.test_function(m.MyEnum.ESecondEntry) == "test_function(enum=2)"
assert test_function(MyEnum.EFirstEntry) == "test_function(enum=1)"
assert test_function(MyEnum.ESecondEntry) == "test_function(enum=2)"
assert test_function(1, 1.0) == "test_function(int, float)" assert m.test_function() == "test_function()"
assert test_function(2.0, 2) == "test_function(float, int)" assert m.test_function("abcd") == "test_function(char *)"
assert m.test_function(1, 1.0) == "test_function(int, float)"
assert m.test_function(1, 1.0) == "test_function(int, float)"
assert m.test_function(2.0, 2) == "test_function(float, int)"
def test_bytes(): def test_bytes():
from pybind11_tests import return_bytes, print_bytes assert m.print_bytes(m.return_bytes()) == "bytes[1 0 2 0]"
assert print_bytes(return_bytes()) == "bytes[1 0 2 0]"
def test_exception_specifiers(): def test_exception_specifiers():
from pybind11_tests.exc_sp import C, f1, f2, f3, f4 c = m.C()
c = C()
assert c.m1(2) == 1 assert c.m1(2) == 1
assert c.m2(3) == 1 assert c.m2(3) == 1
assert c.m3(5) == 2 assert c.m3(5) == 2
...@@ -37,7 +33,7 @@ def test_exception_specifiers(): ...@@ -37,7 +33,7 @@ def test_exception_specifiers():
assert c.m7(20) == 13 assert c.m7(20) == 13
assert c.m8(29) == 21 assert c.m8(29) == 21
assert f1(33) == 34 assert m.f1(33) == 34
assert f2(53) == 55 assert m.f2(53) == 55
assert f3(86) == 89 assert m.f3(86) == 89
assert f4(140) == 144 assert m.f4(140) == 144
...@@ -68,7 +68,8 @@ public: ...@@ -68,7 +68,8 @@ public:
int value; int value;
}; };
namespace pybind11 { namespace detail { NAMESPACE_BEGIN(pybind11)
NAMESPACE_BEGIN(detail)
template <> struct type_caster<MoveOnlyInt> { template <> struct type_caster<MoveOnlyInt> {
PYBIND11_TYPE_CASTER(MoveOnlyInt, _("MoveOnlyInt")); PYBIND11_TYPE_CASTER(MoveOnlyInt, _("MoveOnlyInt"));
bool load(handle src, bool) { value = MoveOnlyInt(src.cast<int>()); return true; } bool load(handle src, bool) { value = MoveOnlyInt(src.cast<int>()); return true; }
...@@ -96,32 +97,20 @@ public: ...@@ -96,32 +97,20 @@ public:
operator CopyOnlyInt&() { return value; } 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>;
}; };
}} NAMESPACE_END(detail)
NAMESPACE_END(pybind11)
struct PrivateOpNew { TEST_SUBMODULE(copy_move_policies, m) {
int value = 1; // test_lacking_copy_ctor
private:
void *operator new(size_t bytes);
};
test_initializer copy_move_policies([](py::module &m) {
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
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);
m.def("move_only", [](MoveOnlyInt m) { // test_move_and_copy_casts
return m.value;
});
m.def("move_or_copy", [](MoveOrCopyInt m) {
return m.value;
});
m.def("copy_only", [](CopyOnlyInt m) {
return m.value;
});
m.def("move_and_copy_casts", [](py::object o) { m.def("move_and_copy_casts", [](py::object o) {
int r = 0; int r = 0;
r += py::cast<MoveOrCopyInt>(o).value; /* moves */ r += py::cast<MoveOrCopyInt>(o).value; /* moves */
...@@ -134,6 +123,11 @@ test_initializer copy_move_policies([](py::module &m) { ...@@ -134,6 +123,11 @@ test_initializer copy_move_policies([](py::module &m) {
return r; return r;
}); });
// test_move_and_copy_loads
m.def("move_only", [](MoveOnlyInt m) { return m.value; });
m.def("move_or_copy", [](MoveOrCopyInt 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", [](std::pair<MoveOnlyInt, MoveOrCopyInt> p) {
return p.first.value + p.second.value; return p.first.value + p.second.value;
}); });
...@@ -163,6 +157,7 @@ test_initializer copy_move_policies([](py::module &m) { ...@@ -163,6 +157,7 @@ test_initializer copy_move_policies([](py::module &m) {
return d; return d;
}); });
#ifdef PYBIND11_HAS_OPTIONAL #ifdef PYBIND11_HAS_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;
...@@ -181,6 +176,14 @@ test_initializer copy_move_policies([](py::module &m) { ...@@ -181,6 +176,14 @@ test_initializer copy_move_policies([](py::module &m) {
#endif #endif
// #70 compilation issue if operator new is not public // #70 compilation issue if operator new is not public
struct PrivateOpNew {
int value = 1;
private:
#if defined(_MSC_VER)
# pragma warning(disable: 4822) // warning C4822: local class member function does not have a body
#endif
void *operator new(size_t bytes);
};
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("private_op_new_reference", []() -> const PrivateOpNew & {
...@@ -188,6 +191,7 @@ test_initializer copy_move_policies([](py::module &m) { ...@@ -188,6 +191,7 @@ test_initializer copy_move_policies([](py::module &m) {
return x; return x;
}, py::return_value_policy::reference); }, py::return_value_policy::reference);
// 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
struct MoveIssue1 { struct MoveIssue1 {
int v; int v;
...@@ -195,15 +199,15 @@ test_initializer copy_move_policies([](py::module &m) { ...@@ -195,15 +199,15 @@ test_initializer copy_move_policies([](py::module &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);
struct MoveIssue2 { struct MoveIssue2 {
int v; int v;
MoveIssue2(int v) : v{v} {} MoveIssue2(int v) : v{v} {}
MoveIssue2(MoveIssue2 &&) = default; 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); 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_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); m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
}); }
import pytest import pytest
from pybind11_tests import has_optional from pybind11_tests import copy_move_policies as m
def test_lacking_copy_ctor(): def test_lacking_copy_ctor():
from pybind11_tests import lacking_copy_ctor
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
lacking_copy_ctor.get_one() m.lacking_copy_ctor.get_one()
assert "the object is non-copyable!" in str(excinfo.value) assert "the object is non-copyable!" in str(excinfo.value)
def test_lacking_move_ctor(): def test_lacking_move_ctor():
from pybind11_tests import lacking_move_ctor
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
lacking_move_ctor.get_one() m.lacking_move_ctor.get_one()
assert "the object is neither movable nor copyable!" in str(excinfo.value) assert "the object is neither movable nor copyable!" in str(excinfo.value)
def test_move_and_copy_casts(): def test_move_and_copy_casts():
"""Cast some values in C++ via custom type casters and count the number of moves/copies.""" """Cast some values in C++ via custom type casters and count the number of moves/copies."""
from pybind11_tests import move_and_copy_casts, move_and_copy_cstats
cstats = move_and_copy_cstats() cstats = m.move_and_copy_cstats()
c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"] c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"]
# The type move constructions/assignments below each get incremented: the move assignment comes # The type move constructions/assignments below each get incremented: the move assignment comes
# from the type_caster load; the move construction happens when extracting that via a cast or # from the type_caster load; the move construction happens when extracting that via a cast or
# loading into an argument. # loading into an argument.
assert move_and_copy_casts(3) == 18 assert m.move_and_copy_casts(3) == 18
assert c_m.copy_assignments + c_m.copy_constructions == 0 assert c_m.copy_assignments + c_m.copy_constructions == 0
assert c_m.move_assignments == 2 assert c_m.move_assignments == 2
assert c_m.move_constructions >= 2 assert c_m.move_constructions >= 2
...@@ -43,21 +40,19 @@ def test_move_and_copy_casts(): ...@@ -43,21 +40,19 @@ def test_move_and_copy_casts():
def test_move_and_copy_loads(): def test_move_and_copy_loads():
"""Call some functions that load arguments via custom type casters and count the number of """Call some functions that load arguments via custom type casters and count the number of
moves/copies.""" moves/copies."""
from pybind11_tests import (move_and_copy_cstats, move_only, move_or_copy, copy_only,
move_pair, move_tuple, copy_tuple, move_copy_nested)
cstats = move_and_copy_cstats() cstats = m.move_and_copy_cstats()
c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"] c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"]
assert move_only(10) == 10 # 1 move, c_m assert m.move_only(10) == 10 # 1 move, c_m
assert move_or_copy(11) == 11 # 1 move, c_mc assert m.move_or_copy(11) == 11 # 1 move, c_mc
assert copy_only(12) == 12 # 1 copy, c_c assert m.copy_only(12) == 12 # 1 copy, c_c
assert move_pair((13, 14)) == 27 # 1 c_m move, 1 c_mc move assert m.move_pair((13, 14)) == 27 # 1 c_m move, 1 c_mc move
assert move_tuple((15, 16, 17)) == 48 # 2 c_m moves, 1 c_mc move assert m.move_tuple((15, 16, 17)) == 48 # 2 c_m moves, 1 c_mc move
assert copy_tuple((18, 19)) == 37 # 2 c_c copies assert m.copy_tuple((18, 19)) == 37 # 2 c_c copies
# Direct constructions: 2 c_m moves, 2 c_mc moves, 1 c_c copy # Direct constructions: 2 c_m moves, 2 c_mc moves, 1 c_c copy
# Extra moves/copies when moving pairs/tuples: 3 c_m, 3 c_mc, 2 c_c # Extra moves/copies when moving pairs/tuples: 3 c_m, 3 c_mc, 2 c_c
assert move_copy_nested((1, ((2, 3, (4,)), 5))) == 15 assert m.move_copy_nested((1, ((2, 3, (4,)), 5))) == 15
assert c_m.copy_assignments + c_m.copy_constructions == 0 assert c_m.copy_assignments + c_m.copy_constructions == 0
assert c_m.move_assignments == 6 assert c_m.move_assignments == 6
...@@ -70,24 +65,22 @@ def test_move_and_copy_loads(): ...@@ -70,24 +65,22 @@ def test_move_and_copy_loads():
assert c_m.alive() + c_mc.alive() + c_c.alive() == 0 assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
@pytest.mark.skipif(not has_optional, reason='no <optional>') @pytest.mark.skipif(not m.has_optional, reason='no <optional>')
def test_move_and_copy_load_optional(): def test_move_and_copy_load_optional():
"""Tests move/copy loads of std::optional arguments""" """Tests move/copy loads of std::optional arguments"""
from pybind11_tests import (move_and_copy_cstats, move_optional, move_or_copy_optional,
copy_optional, move_optional_tuple)
cstats = move_and_copy_cstats() cstats = m.move_and_copy_cstats()
c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"] c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"]
# The extra move/copy constructions below come from the std::optional move (which has to move # The extra move/copy constructions below come from the std::optional move (which has to move
# its arguments): # its arguments):
assert move_optional(10) == 10 # c_m: 1 move assign, 2 move construct assert m.move_optional(10) == 10 # c_m: 1 move assign, 2 move construct
assert move_or_copy_optional(11) == 11 # c_mc: 1 move assign, 2 move construct assert m.move_or_copy_optional(11) == 11 # c_mc: 1 move assign, 2 move construct
assert copy_optional(12) == 12 # c_c: 1 copy assign, 2 copy construct assert m.copy_optional(12) == 12 # c_c: 1 copy assign, 2 copy construct
# 1 move assign + move construct moves each of c_m, c_mc, 1 c_c copy # 1 move assign + move construct moves each of c_m, c_mc, 1 c_c copy
# +1 move/copy construct each from moving the tuple # +1 move/copy construct each from moving the tuple
# +1 move/copy construct each from moving the optional (which moves the tuple again) # +1 move/copy construct each from moving the optional (which moves the tuple again)
assert move_optional_tuple((3, 4, 5)) == 12 assert m.move_optional_tuple((3, 4, 5)) == 12
assert c_m.copy_assignments + c_m.copy_constructions == 0 assert c_m.copy_assignments + c_m.copy_constructions == 0
assert c_m.move_assignments == 2 assert c_m.move_assignments == 2
...@@ -102,7 +95,6 @@ def test_move_and_copy_load_optional(): ...@@ -102,7 +95,6 @@ def test_move_and_copy_load_optional():
def test_private_op_new(): def test_private_op_new():
"""An object with a private `operator new` cannot be returned by value""" """An object with a private `operator new` cannot be returned by value"""
import pybind11_tests as m
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.private_op_new_value() m.private_op_new_value()
...@@ -113,9 +105,8 @@ def test_private_op_new(): ...@@ -113,9 +105,8 @@ def test_private_op_new():
def test_move_fallback(): def 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"""
from pybind11_tests import get_moveissue1, get_moveissue2
m2 = get_moveissue2(2) m2 = m.get_moveissue2(2)
assert m2.value == 2 assert m2.value == 2
m1 = get_moveissue1(1) m1 = m.get_moveissue1(1)
assert m1.value == 1 assert m1.value == 1
...@@ -9,14 +9,8 @@ ...@@ -9,14 +9,8 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
struct DocstringTestFoo { TEST_SUBMODULE(docstring_options, m) {
int value; // test_docstring_options
void setValue(int v) { value = v; }
int getValue() const { return value; }
};
test_initializer docstring_generation([](py::module &m) {
{ {
py::options options; py::options options;
options.disable_function_signatures(); options.disable_function_signatures();
...@@ -55,8 +49,13 @@ test_initializer docstring_generation([](py::module &m) { ...@@ -55,8 +49,13 @@ test_initializer docstring_generation([](py::module &m) {
py::options options; py::options options;
options.disable_user_defined_docstrings(); options.disable_user_defined_docstrings();
struct DocstringTestFoo {
int value;
void setValue(int v) { value = v; }
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")
; ;
} }
}); }
from pybind11_tests import docstring_options as m
def test_docstring_options(): def test_docstring_options():
from pybind11_tests import (test_function1, test_function2, test_function3,
test_function4, test_function5, test_function6,
test_function7, DocstringTestFoo,
test_overloaded1, test_overloaded2, test_overloaded3)
# options.disable_function_signatures() # options.disable_function_signatures()
assert not test_function1.__doc__ assert not m.test_function1.__doc__
assert test_function2.__doc__ == "A custom docstring" assert m.test_function2.__doc__ == "A custom docstring"
# docstring specified on just the first overload definition: # docstring specified on just the first overload definition:
assert test_overloaded1.__doc__ == "Overload docstring" assert m.test_overloaded1.__doc__ == "Overload docstring"
# docstring on both overloads: # docstring on both overloads:
assert test_overloaded2.__doc__ == "overload docstring 1\noverload docstring 2" assert m.test_overloaded2.__doc__ == "overload docstring 1\noverload docstring 2"
# docstring on only second overload: # docstring on only second overload:
assert test_overloaded3.__doc__ == "Overload docstr" assert m.test_overloaded3.__doc__ == "Overload docstr"
# options.enable_function_signatures() # options.enable_function_signatures()
assert test_function3.__doc__ .startswith("test_function3(a: int, b: int) -> None") assert m.test_function3.__doc__ .startswith("test_function3(a: int, b: int) -> None")
assert test_function4.__doc__ .startswith("test_function4(a: int, b: int) -> None") assert m.test_function4.__doc__ .startswith("test_function4(a: int, b: int) -> None")
assert test_function4.__doc__ .endswith("A custom docstring\n") assert m.test_function4.__doc__ .endswith("A custom docstring\n")
# options.disable_function_signatures() # options.disable_function_signatures()
# options.disable_user_defined_docstrings() # options.disable_user_defined_docstrings()
assert not test_function5.__doc__ assert not m.test_function5.__doc__
# nested options.enable_user_defined_docstrings() # nested options.enable_user_defined_docstrings()
assert test_function6.__doc__ == "A custom docstring" assert m.test_function6.__doc__ == "A custom docstring"
# RAII destructor # RAII destructor
assert test_function7.__doc__ .startswith("test_function7(a: int, b: int) -> None") assert m.test_function7.__doc__ .startswith("test_function7(a: int, b: int) -> None")
assert test_function7.__doc__ .endswith("A custom docstring\n") assert m.test_function7.__doc__ .endswith("A custom docstring\n")
# Suppression of user-defined docstrings for non-function objects # Suppression of user-defined docstrings for non-function objects
assert not DocstringTestFoo.__doc__ assert not m.DocstringTestFoo.__doc__
assert not DocstringTestFoo.value_prop.__doc__ assert not m.DocstringTestFoo.value_prop.__doc__
...@@ -70,20 +70,21 @@ struct CustomOperatorNew { ...@@ -70,20 +70,21 @@ struct CustomOperatorNew {
EIGEN_MAKE_ALIGNED_OPERATOR_NEW; EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
}; };
test_initializer eigen([](py::module &m) { TEST_SUBMODULE(eigen, m) {
typedef Eigen::Matrix<float, 5, 6, Eigen::RowMajor> FixedMatrixR; using FixedMatrixR = Eigen::Matrix<float, 5, 6, Eigen::RowMajor>;
typedef Eigen::Matrix<float, 5, 6> FixedMatrixC; using FixedMatrixC = Eigen::Matrix<float, 5, 6>;
typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> DenseMatrixR; using DenseMatrixR = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> DenseMatrixC; using DenseMatrixC = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic>;
typedef Eigen::Matrix<float, 4, Eigen::Dynamic> FourRowMatrixC; using FourRowMatrixC = Eigen::Matrix<float, 4, Eigen::Dynamic>;
typedef Eigen::Matrix<float, Eigen::Dynamic, 4> FourColMatrixC; using FourColMatrixC = Eigen::Matrix<float, Eigen::Dynamic, 4>;
typedef Eigen::Matrix<float, 4, Eigen::Dynamic> FourRowMatrixR; using FourRowMatrixR = Eigen::Matrix<float, 4, Eigen::Dynamic>;
typedef Eigen::Matrix<float, Eigen::Dynamic, 4> FourColMatrixR; using FourColMatrixR = Eigen::Matrix<float, Eigen::Dynamic, 4>;
typedef Eigen::SparseMatrix<float, Eigen::RowMajor> SparseMatrixR; using SparseMatrixR = Eigen::SparseMatrix<float, Eigen::RowMajor>;
typedef Eigen::SparseMatrix<float> SparseMatrixC; using SparseMatrixC = Eigen::SparseMatrix<float>;
m.attr("have_eigen") = true; m.attr("have_eigen") = true;
// 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", [](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_complex", [](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; });
...@@ -92,12 +93,14 @@ test_initializer eigen([](py::module &m) { ...@@ -92,12 +93,14 @@ test_initializer eigen([](py::module &m) {
m.def("double_mat_cm", [](Eigen::MatrixXf x) -> Eigen::MatrixXf { return 2.0f * x; }); m.def("double_mat_cm", [](Eigen::MatrixXf x) -> Eigen::MatrixXf { return 2.0f * x; });
m.def("double_mat_rm", [](DenseMatrixR x) -> DenseMatrixR { return 2.0f * x; }); m.def("double_mat_rm", [](DenseMatrixR x) -> DenseMatrixR { return 2.0f * x; });
// test_eigen_ref_to_python
// 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", [](Eigen::Ref<MatrixXdR> x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky1", [](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 { return x.llt().matrixL(); });
m.def("cholesky3", [](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky3", [](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
m.def("cholesky4", [](Eigen::Ref<const MatrixXdR> x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky4", [](Eigen::Ref<const MatrixXdR> x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
// 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 into
// the numpy array data and so the result should show up there. There are three versions: one that // the numpy array data and so the result should show up there. There are three versions: one that
// works on a contiguous-row matrix (numpy's default), one for a contiguous-column matrix, and one // works on a contiguous-row matrix (numpy's default), one for a contiguous-column matrix, and one
...@@ -122,19 +125,6 @@ test_initializer eigen([](py::module &m) { ...@@ -122,19 +125,6 @@ test_initializer eigen([](py::module &m) {
// The same references, but non-mutable (numpy maps into eigen variables, but is !writeable) // The same references, but non-mutable (numpy maps into eigen variables, but is !writeable)
m.def("get_cm_const_ref", []() { return Eigen::Ref<const Eigen::MatrixXd>(get_cm()); }); m.def("get_cm_const_ref", []() { return Eigen::Ref<const Eigen::MatrixXd>(get_cm()); });
m.def("get_rm_const_ref", []() { return Eigen::Ref<const MatrixXdR>(get_rm()); }); m.def("get_rm_const_ref", []() { return Eigen::Ref<const MatrixXdR>(get_rm()); });
// Just the corners (via a Map instead of a Ref):
m.def("get_cm_corners", []() {
auto &x = get_cm();
return py::EigenDMap<Eigen::Matrix2d>(
x.data(),
py::EigenDStride(x.outerStride() * (x.rows() - 1), x.innerStride() * (x.cols() - 1)));
});
m.def("get_cm_corners_const", []() {
const auto &x = get_cm();
return py::EigenDMap<const Eigen::Matrix2d>(
x.data(),
py::EigenDStride(x.outerStride() * (x.rows() - 1), x.innerStride() * (x.cols() - 1)));
});
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
...@@ -174,6 +164,7 @@ test_initializer eigen([](py::module &m) { ...@@ -174,6 +164,7 @@ test_initializer eigen([](py::module &m) {
return x.block(start_row, start_col, block_rows, block_cols); return x.block(start_row, start_col, block_rows, block_cols);
}); });
// 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();
...@@ -220,6 +211,7 @@ test_initializer eigen([](py::module &m) { ...@@ -220,6 +211,7 @@ test_initializer eigen([](py::module &m) {
.def("corners_const", &ReturnTester::cornersConst, rvp::reference_internal) .def("corners_const", &ReturnTester::cornersConst, rvp::reference_internal)
; ;
// test_special_matrix_objects
// Returns a DiagonalMatrix with diagonal (1,2,3,...) // Returns a DiagonalMatrix with diagonal (1,2,3,...)
m.def("incr_diag", [](int k) { m.def("incr_diag", [](int k) {
Eigen::DiagonalMatrix<int, Eigen::Dynamic> m(k); Eigen::DiagonalMatrix<int, Eigen::Dynamic> m(k);
...@@ -244,27 +236,33 @@ test_initializer eigen([](py::module &m) { ...@@ -244,27 +236,33 @@ test_initializer eigen([](py::module &m) {
0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 11,
0, 0, 14, 0, 8, 11; 0, 0, 14, 0, 8, 11;
// test_fixed, and various other tests
m.def("fixed_r", [mat]() -> FixedMatrixR { return FixedMatrixR(mat); }); m.def("fixed_r", [mat]() -> FixedMatrixR { return FixedMatrixR(mat); });
m.def("fixed_r_const", [mat]() -> const FixedMatrixR { return FixedMatrixR(mat); }); m.def("fixed_r_const", [mat]() -> const FixedMatrixR { return FixedMatrixR(mat); });
m.def("fixed_c", [mat]() -> FixedMatrixC { return FixedMatrixC(mat); }); m.def("fixed_c", [mat]() -> FixedMatrixC { return FixedMatrixC(mat); });
m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; }); m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; });
m.def("fixed_copy_c", [](const FixedMatrixC &m) -> FixedMatrixC { return m; }); m.def("fixed_copy_c", [](const FixedMatrixC &m) -> FixedMatrixC { return m; });
// test_mutator_descriptors
m.def("fixed_mutator_r", [](Eigen::Ref<FixedMatrixR>) {}); m.def("fixed_mutator_r", [](Eigen::Ref<FixedMatrixR>) {});
m.def("fixed_mutator_c", [](Eigen::Ref<FixedMatrixC>) {}); m.def("fixed_mutator_c", [](Eigen::Ref<FixedMatrixC>) {});
m.def("fixed_mutator_a", [](py::EigenDRef<FixedMatrixC>) {}); m.def("fixed_mutator_a", [](py::EigenDRef<FixedMatrixC>) {});
// test_dense
m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); }); m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); });
m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); }); m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); });
m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; }); m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; });
m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; }); m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; });
// test_sparse, test_sparse_signature
m.def("sparse_r", [mat]() -> SparseMatrixR { return Eigen::SparseView<Eigen::MatrixXf>(mat); }); m.def("sparse_r", [mat]() -> SparseMatrixR { 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
m.def("partial_copy_four_rm_r", [](const FourRowMatrixR &m) -> FourRowMatrixR { return m; }); m.def("partial_copy_four_rm_r", [](const FourRowMatrixR &m) -> FourRowMatrixR { return m; });
m.def("partial_copy_four_rm_c", [](const FourColMatrixR &m) -> FourColMatrixR { return m; }); m.def("partial_copy_four_rm_c", [](const FourColMatrixR &m) -> FourColMatrixR { return m; });
m.def("partial_copy_four_cm_r", [](const FourRowMatrixC &m) -> FourRowMatrixC { return m; }); m.def("partial_copy_four_cm_r", [](const FourRowMatrixC &m) -> FourRowMatrixC { return m; });
m.def("partial_copy_four_cm_c", [](const FourColMatrixC &m) -> FourColMatrixC { return m; }); m.def("partial_copy_four_cm_c", [](const FourColMatrixC &m) -> FourColMatrixC { return m; });
// test_cpp_casting
// Test that we can cast a numpy object to a Eigen::MatrixXd explicitly // Test that we can cast a numpy object to a Eigen::MatrixXd explicitly
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); });
...@@ -272,6 +270,7 @@ test_initializer eigen([](py::module &m) { ...@@ -272,6 +270,7 @@ test_initializer eigen([](py::module &m) {
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); });
// test_nocopy_wrapper
// Test that we can prevent copying into an argument that would normally copy: First a version // Test that we can prevent copying into an argument that would normally copy: First a version
// that would allow copying (if types or strides don't match) for comparison: // that would allow copying (if types or strides don't match) for comparison:
m.def("get_elem", &get_elem); m.def("get_elem", &get_elem);
...@@ -282,12 +281,14 @@ test_initializer eigen([](py::module &m) { ...@@ -282,12 +281,14 @@ test_initializer eigen([](py::module &m) {
m.def("get_elem_rm_nocopy", [](Eigen::Ref<const Eigen::Matrix<long, -1, -1, Eigen::RowMajor>> &m) -> long { return m(2, 1); }, m.def("get_elem_rm_nocopy", [](Eigen::Ref<const Eigen::Matrix<long, -1, -1, Eigen::RowMajor>> &m) -> long { return m(2, 1); },
py::arg().noconvert()); py::arg().noconvert());
// 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", &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()); m.def("iss738_f2", &adjust_matrix<const Eigen::Ref<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>> &>, py::arg().noconvert());
// test_named_arguments
// Make sure named arguments are working properly: // Make sure named arguments are working properly:
m.def("matrix_multiply", [](const py::EigenDRef<const Eigen::MatrixXd> A, const py::EigenDRef<const Eigen::MatrixXd> B) m.def("matrix_multiply", [](const py::EigenDRef<const Eigen::MatrixXd> A, const py::EigenDRef<const Eigen::MatrixXd> B)
-> Eigen::MatrixXd { -> Eigen::MatrixXd {
...@@ -295,6 +296,7 @@ test_initializer eigen([](py::module &m) { ...@@ -295,6 +296,7 @@ test_initializer eigen([](py::module &m) {
return A * B; return A * B;
}, py::arg("A"), py::arg("B")); }, py::arg("A"), py::arg("B"));
// test_custom_operator_new
py::class_<CustomOperatorNew>(m, "CustomOperatorNew") py::class_<CustomOperatorNew>(m, "CustomOperatorNew")
.def(py::init<>()) .def(py::init<>())
.def_readonly("a", &CustomOperatorNew::a) .def_readonly("a", &CustomOperatorNew::a)
...@@ -312,4 +314,4 @@ test_initializer eigen([](py::module &m) { ...@@ -312,4 +314,4 @@ test_initializer eigen([](py::module &m) {
py::module::import("numpy").attr("ones")(10); py::module::import("numpy").attr("ones")(10);
return v[0](5); return v[0](5);
}); });
}); }
...@@ -9,56 +9,54 @@ ...@@ -9,56 +9,54 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
enum UnscopedEnum { TEST_SUBMODULE(enums, m) {
EOne = 1, // test_unscoped_enum
ETwo enum UnscopedEnum {
}; EOne = 1,
ETwo
enum class ScopedEnum {
Two = 2,
Three
};
enum Flags {
Read = 4,
Write = 2,
Execute = 1
};
class ClassWithUnscopedEnum {
public:
enum EMode {
EFirstMode = 1,
ESecondMode
}; };
static EMode test_function(EMode mode) {
return mode;
}
};
std::string test_scoped_enum(ScopedEnum z) {
return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three");
}
test_initializer enums([](py::module &m) {
m.def("test_scoped_enum", &test_scoped_enum);
py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic()) py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic())
.value("EOne", EOne) .value("EOne", EOne)
.value("ETwo", ETwo) .value("ETwo", ETwo)
.export_values(); .export_values();
// test_scoped_enum
enum class ScopedEnum {
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);
m.def("test_scoped_enum", [](ScopedEnum z) {
return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three");
});
// test_binary_operators
enum Flags {
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)
.value("Execute", Flags::Execute) .value("Execute", Flags::Execute)
.export_values(); .export_values();
// test_implicit_conversion
class ClassWithUnscopedEnum {
public:
enum EMode {
EFirstMode = 1,
ESecondMode
};
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);
py::enum_<ClassWithUnscopedEnum::EMode>(exenum_class, "EMode") py::enum_<ClassWithUnscopedEnum::EMode>(exenum_class, "EMode")
...@@ -66,7 +64,8 @@ test_initializer enums([](py::module &m) { ...@@ -66,7 +64,8 @@ test_initializer enums([](py::module &m) {
.value("ESecondMode", ClassWithUnscopedEnum::ESecondMode) .value("ESecondMode", ClassWithUnscopedEnum::ESecondMode)
.export_values(); .export_values();
// 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) { });
}); }
import pytest import pytest
from pybind11_tests import enums as m
def test_unscoped_enum(): def test_unscoped_enum():
from pybind11_tests import UnscopedEnum, EOne assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne"
assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
assert str(UnscopedEnum.EOne) == "UnscopedEnum.EOne" assert str(m.EOne) == "UnscopedEnum.EOne"
assert str(UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
assert str(EOne) == "UnscopedEnum.EOne"
# __members__ property # __members__ property
assert UnscopedEnum.__members__ == {"EOne": UnscopedEnum.EOne, "ETwo": UnscopedEnum.ETwo} assert m.UnscopedEnum.__members__ == \
{"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo}
# __members__ readonly # __members__ readonly
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
UnscopedEnum.__members__ = {} m.UnscopedEnum.__members__ = {}
# __members__ returns a copy # __members__ returns a copy
foo = UnscopedEnum.__members__ foo = m.UnscopedEnum.__members__
foo["bar"] = "baz" foo["bar"] = "baz"
assert UnscopedEnum.__members__ == {"EOne": UnscopedEnum.EOne, "ETwo": UnscopedEnum.ETwo} assert m.UnscopedEnum.__members__ == \
{"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo}
# no TypeError exception for unscoped enum ==/!= int comparisons # no TypeError exception for unscoped enum ==/!= int comparisons
y = UnscopedEnum.ETwo y = m.UnscopedEnum.ETwo
assert y == 2 assert y == 2
assert y != 3 assert y != 3
assert int(UnscopedEnum.ETwo) == 2 assert int(m.UnscopedEnum.ETwo) == 2
assert str(UnscopedEnum(2)) == "UnscopedEnum.ETwo" assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo"
# order # order
assert UnscopedEnum.EOne < UnscopedEnum.ETwo assert m.UnscopedEnum.EOne < m.UnscopedEnum.ETwo
assert UnscopedEnum.EOne < 2 assert m.UnscopedEnum.EOne < 2
assert UnscopedEnum.ETwo > UnscopedEnum.EOne assert m.UnscopedEnum.ETwo > m.UnscopedEnum.EOne
assert UnscopedEnum.ETwo > 1 assert m.UnscopedEnum.ETwo > 1
assert UnscopedEnum.ETwo <= 2 assert m.UnscopedEnum.ETwo <= 2
assert UnscopedEnum.ETwo >= 2 assert m.UnscopedEnum.ETwo >= 2
assert UnscopedEnum.EOne <= UnscopedEnum.ETwo assert m.UnscopedEnum.EOne <= m.UnscopedEnum.ETwo
assert UnscopedEnum.EOne <= 2 assert m.UnscopedEnum.EOne <= 2
assert UnscopedEnum.ETwo >= UnscopedEnum.EOne assert m.UnscopedEnum.ETwo >= m.UnscopedEnum.EOne
assert UnscopedEnum.ETwo >= 1 assert m.UnscopedEnum.ETwo >= 1
assert not (UnscopedEnum.ETwo < UnscopedEnum.EOne) assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne)
assert not (2 < UnscopedEnum.EOne) assert not (2 < m.UnscopedEnum.EOne)
def test_scoped_enum(): def test_scoped_enum():
from pybind11_tests import ScopedEnum, test_scoped_enum assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three"
z = m.ScopedEnum.Two
assert test_scoped_enum(ScopedEnum.Three) == "ScopedEnum::Three" assert m.test_scoped_enum(z) == "ScopedEnum::Two"
z = ScopedEnum.Two
assert test_scoped_enum(z) == "ScopedEnum::Two"
# expected TypeError exceptions for scoped enum ==/!= int comparisons # expected TypeError exceptions for scoped enum ==/!= int comparisons
with pytest.raises(TypeError): with pytest.raises(TypeError):
...@@ -54,23 +53,21 @@ def test_scoped_enum(): ...@@ -54,23 +53,21 @@ def test_scoped_enum():
assert z != 3 assert z != 3
# order # order
assert ScopedEnum.Two < ScopedEnum.Three assert m.ScopedEnum.Two < m.ScopedEnum.Three
assert ScopedEnum.Three > ScopedEnum.Two assert m.ScopedEnum.Three > m.ScopedEnum.Two
assert ScopedEnum.Two <= ScopedEnum.Three assert m.ScopedEnum.Two <= m.ScopedEnum.Three
assert ScopedEnum.Two <= ScopedEnum.Two assert m.ScopedEnum.Two <= m.ScopedEnum.Two
assert ScopedEnum.Two >= ScopedEnum.Two assert m.ScopedEnum.Two >= m.ScopedEnum.Two
assert ScopedEnum.Three >= ScopedEnum.Two assert m.ScopedEnum.Three >= m.ScopedEnum.Two
def test_implicit_conversion(): def test_implicit_conversion():
from pybind11_tests import ClassWithUnscopedEnum assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"
assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
assert str(ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"
assert str(ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
f = ClassWithUnscopedEnum.test_function f = m.ClassWithUnscopedEnum.test_function
first = ClassWithUnscopedEnum.EFirstMode first = m.ClassWithUnscopedEnum.EFirstMode
second = ClassWithUnscopedEnum.ESecondMode second = m.ClassWithUnscopedEnum.ESecondMode
assert f(first) == 1 assert f(first) == 1
...@@ -95,21 +92,19 @@ def test_implicit_conversion(): ...@@ -95,21 +92,19 @@ def test_implicit_conversion():
def test_binary_operators(): def test_binary_operators():
from pybind11_tests import Flags assert int(m.Flags.Read) == 4
assert int(m.Flags.Write) == 2
assert int(Flags.Read) == 4 assert int(m.Flags.Execute) == 1
assert int(Flags.Write) == 2 assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7
assert int(Flags.Execute) == 1 assert int(m.Flags.Read | m.Flags.Write) == 6
assert int(Flags.Read | Flags.Write | Flags.Execute) == 7 assert int(m.Flags.Read | m.Flags.Execute) == 5
assert int(Flags.Read | Flags.Write) == 6 assert int(m.Flags.Write | m.Flags.Execute) == 3
assert int(Flags.Read | Flags.Execute) == 5 assert int(m.Flags.Write | 1) == 3
assert int(Flags.Write | Flags.Execute) == 3
assert int(Flags.Write | 1) == 3 state = m.Flags.Read | m.Flags.Write
assert (state & m.Flags.Read) != 0
state = Flags.Read | Flags.Write assert (state & m.Flags.Write) != 0
assert (state & Flags.Read) != 0 assert (state & m.Flags.Execute) == 0
assert (state & Flags.Write) != 0
assert (state & Flags.Execute) == 0
assert (state & 1) == 0 assert (state & 1) == 0
state2 = ~state state2 = ~state
...@@ -118,12 +113,9 @@ def test_binary_operators(): ...@@ -118,12 +113,9 @@ def test_binary_operators():
def test_enum_to_int(): def test_enum_to_int():
from pybind11_tests import Flags, ClassWithUnscopedEnum m.test_enum_to_int(m.Flags.Read)
from pybind11_tests import test_enum_to_int, test_enum_to_uint, test_enum_to_long_long m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode)
m.test_enum_to_uint(m.Flags.Read)
test_enum_to_int(Flags.Read) m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode)
test_enum_to_int(ClassWithUnscopedEnum.EMode.EFirstMode) m.test_enum_to_long_long(m.Flags.Read)
test_enum_to_uint(Flags.Read) m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode)
test_enum_to_uint(ClassWithUnscopedEnum.EMode.EFirstMode)
test_enum_to_long_long(Flags.Read)
test_enum_to_long_long(ClassWithUnscopedEnum.EMode.EFirstMode)
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
#include <pybind11/eval.h> #include <pybind11/eval.h>
#include "pybind11_tests.h" #include "pybind11_tests.h"
test_initializer eval([](py::module &m) { TEST_SUBMODULE(eval_, m) {
// test_evals
auto global = py::dict(py::module::import("__main__").attr("__dict__")); auto global = py::dict(py::module::import("__main__").attr("__dict__"));
m.def("test_eval_statements", [global]() { m.def("test_eval_statements", [global]() {
...@@ -86,4 +88,4 @@ test_initializer eval([](py::module &m) { ...@@ -86,4 +88,4 @@ test_initializer eval([](py::module &m) {
} }
return false; return false;
}); });
}); }
import os import os
from pybind11_tests import eval_ as m
def test_evals(capture): def test_evals(capture):
from pybind11_tests import (test_eval_statements, test_eval, test_eval_single_statement,
test_eval_file, test_eval_failure, test_eval_file_failure)
with capture: with capture:
assert test_eval_statements() assert m.test_eval_statements()
assert capture == "Hello World!" assert capture == "Hello World!"
assert test_eval() assert m.test_eval()
assert test_eval_single_statement() assert m.test_eval_single_statement()
filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py") filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
assert test_eval_file(filename) assert m.test_eval_file(filename)
assert test_eval_failure() assert m.test_eval_failure()
assert test_eval_file_failure() assert m.test_eval_file_failure()
...@@ -10,84 +10,62 @@ ...@@ -10,84 +10,62 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <pybind11/stl.h> #include <pybind11/stl.h>
std::string kw_func(int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); } TEST_SUBMODULE(kwargs_and_defaults, m) {
auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); };
std::string kw_func4(const std::vector<int> &entries) { // test_named_arguments
std::string ret = "{"; m.def("kw_func0", kw_func);
for (int i : entries) m.def("kw_func1", kw_func, py::arg("x"), py::arg("y"));
ret += std::to_string(i) + " "; m.def("kw_func2", kw_func, py::arg("x") = 100, py::arg("y") = 200);
ret.back() = '}';
return ret;
}
py::tuple args_function(py::args args) {
return args;
}
py::tuple args_kwargs_function(py::args args, py::kwargs kwargs) {
return py::make_tuple(args, kwargs);
}
py::tuple mixed_plus_args(int i, double j, py::args args) {
return py::make_tuple(i, j, args);
}
py::tuple mixed_plus_kwargs(int i, double j, py::kwargs kwargs) {
return py::make_tuple(i, j, kwargs);
}
py::tuple mixed_plus_args_kwargs(int i, double j, py::args args, py::kwargs kwargs) {
return py::make_tuple(i, j, args, kwargs);
}
// pybind11 won't allow these to be bound: args and kwargs, if present, must be at the end.
void bad_args1(py::args, int) {}
void bad_args2(py::kwargs, int) {}
void bad_args3(py::kwargs, py::args) {}
void bad_args4(py::args, int, py::kwargs) {}
void bad_args5(py::args, py::kwargs, int) {}
void bad_args6(py::args, py::args) {}
void bad_args7(py::kwargs, py::kwargs) {}
struct KWClass {
void foo(int, float) {}
};
test_initializer arg_keywords_and_defaults([](py::module &m) {
m.def("kw_func0", &kw_func);
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_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; std::vector<int> list{{13, 17}};
list.push_back(13); m.def("kw_func4", [](const std::vector<int> &entries) {
list.push_back(17); std::string ret = "{";
m.def("kw_func4", &kw_func4, py::arg("myList") = list); for (int i : entries)
ret += std::to_string(i) + " ";
m.def("args_function", &args_function); ret.back() = '}';
m.def("args_kwargs_function", &args_kwargs_function); return ret;
}, py::arg("myList") = list);
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", kw_func, "x"_a, "y"_a=300);
m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a=0);
// test_args_and_kwargs
m.def("args_function", [](py::args args) -> py::tuple { return args; });
m.def("args_kwargs_function", [](py::args args, py::kwargs kwargs) {
return py::make_tuple(args, kwargs);
});
// test_mixed_args_and_kwargs
m.def("mixed_plus_args", [](int i, double j, py::args args) {
return py::make_tuple(i, j, args);
});
m.def("mixed_plus_kwargs", [](int i, double j, py::kwargs kwargs) {
return py::make_tuple(i, j, kwargs);
});
auto mixed_plus_both = [](int i, double j, py::args args, py::kwargs kwargs) {
return py::make_tuple(i, j, args, kwargs);
};
m.def("mixed_plus_args_kwargs", mixed_plus_both);
m.def("mixed_plus_args_kwargs_defaults", mixed_plus_both,
py::arg("i") = 1, py::arg("j") = 3.14159);
// 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:
// m.def("bad_args1", [](py::args, int) {});
// m.def("bad_args2", [](py::kwargs, int) {});
// m.def("bad_args3", [](py::kwargs, py::args) {});
// m.def("bad_args4", [](py::args, int, py::kwargs) {});
// m.def("bad_args5", [](py::args, py::kwargs, int) {});
// m.def("bad_args6", [](py::args, py::args) {});
// m.def("bad_args7", [](py::kwargs, py::kwargs) {});
// test_function_signatures (along with most of the above)
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);
}
m.def("mixed_plus_args", &mixed_plus_args);
m.def("mixed_plus_kwargs", &mixed_plus_kwargs);
m.def("mixed_plus_args_kwargs", &mixed_plus_args_kwargs);
m.def("mixed_plus_args_kwargs_defaults", &mixed_plus_args_kwargs,
py::arg("i") = 1, py::arg("j") = 3.14159);
// Uncomment these to test that the static_assert is indeed working:
// m.def("bad_args1", &bad_args1);
// m.def("bad_args2", &bad_args2);
// m.def("bad_args3", &bad_args3);
// m.def("bad_args4", &bad_args4);
// m.def("bad_args5", &bad_args5);
// m.def("bad_args6", &bad_args6);
// m.def("bad_args7", &bad_args7);
});
import pytest import pytest
from pybind11_tests import (kw_func0, kw_func1, kw_func2, kw_func3, kw_func4, args_function, from pybind11_tests import kwargs_and_defaults as m
args_kwargs_function, kw_func_udl, kw_func_udl_z, KWClass)
def test_function_signatures(doc): def test_function_signatures(doc):
assert doc(kw_func0) == "kw_func0(arg0: int, arg1: int) -> str" assert doc(m.kw_func0) == "kw_func0(arg0: int, arg1: int) -> str"
assert doc(kw_func1) == "kw_func1(x: int, y: int) -> str" assert doc(m.kw_func1) == "kw_func1(x: int, y: int) -> str"
assert doc(kw_func2) == "kw_func2(x: int=100, y: int=200) -> str" assert doc(m.kw_func2) == "kw_func2(x: int=100, y: int=200) -> str"
assert doc(kw_func3) == "kw_func3(data: str='Hello world!') -> None" assert doc(m.kw_func3) == "kw_func3(data: str='Hello world!') -> None"
assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> str" assert doc(m.kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> str"
assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> str" assert doc(m.kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> str"
assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> str" assert doc(m.kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> str"
assert doc(args_function) == "args_function(*args) -> tuple" assert doc(m.args_function) == "args_function(*args) -> tuple"
assert doc(args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple" assert doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple"
assert doc(KWClass.foo0) == "foo0(self: m.KWClass, arg0: int, arg1: float) -> None" assert doc(m.KWClass.foo0) == \
assert doc(KWClass.foo1) == "foo1(self: m.KWClass, x: int, y: float) -> None" "foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None"
assert doc(m.KWClass.foo1) == \
"foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None"
def test_named_arguments(msg): def test_named_arguments(msg):
assert kw_func0(5, 10) == "x=5, y=10" assert m.kw_func0(5, 10) == "x=5, y=10"
assert kw_func1(5, 10) == "x=5, y=10" assert m.kw_func1(5, 10) == "x=5, y=10"
assert kw_func1(5, y=10) == "x=5, y=10" assert m.kw_func1(5, y=10) == "x=5, y=10"
assert kw_func1(y=10, x=5) == "x=5, y=10" assert m.kw_func1(y=10, x=5) == "x=5, y=10"
assert kw_func2() == "x=100, y=200" assert m.kw_func2() == "x=100, y=200"
assert kw_func2(5) == "x=5, y=200" assert m.kw_func2(5) == "x=5, y=200"
assert kw_func2(x=5) == "x=5, y=200" assert m.kw_func2(x=5) == "x=5, y=200"
assert kw_func2(y=10) == "x=100, y=10" assert m.kw_func2(y=10) == "x=100, y=10"
assert kw_func2(5, 10) == "x=5, y=10" assert m.kw_func2(5, 10) == "x=5, y=10"
assert kw_func2(x=5, y=10) == "x=5, y=10" assert m.kw_func2(x=5, y=10) == "x=5, y=10"
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
# noinspection PyArgumentList # noinspection PyArgumentList
kw_func2(x=5, y=10, z=12) m.kw_func2(x=5, y=10, z=12)
assert excinfo.match( assert excinfo.match(
r'(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))' + '{3}$') r'(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))' + '{3}$')
assert kw_func4() == "{13 17}" assert m.kw_func4() == "{13 17}"
assert kw_func4(myList=[1, 2, 3]) == "{1 2 3}" assert m.kw_func4(myList=[1, 2, 3]) == "{1 2 3}"
assert kw_func_udl(x=5, y=10) == "x=5, y=10" assert m.kw_func_udl(x=5, y=10) == "x=5, y=10"
assert kw_func_udl_z(x=5) == "x=5, y=0" assert m.kw_func_udl_z(x=5) == "x=5, y=0"
def test_arg_and_kwargs(): def test_arg_and_kwargs():
args = 'arg1_value', 'arg2_value', 3 args = 'arg1_value', 'arg2_value', 3
assert args_function(*args) == args assert m.args_function(*args) == args
args = 'a1', 'a2' args = 'a1', 'a2'
kwargs = dict(arg3='a3', arg4=4) kwargs = dict(arg3='a3', arg4=4)
assert args_kwargs_function(*args, **kwargs) == (args, kwargs) assert m.args_kwargs_function(*args, **kwargs) == (args, kwargs)
def test_mixed_args_and_kwargs(msg): def test_mixed_args_and_kwargs(msg):
from pybind11_tests import (mixed_plus_args, mixed_plus_kwargs, mixed_plus_args_kwargs, mpa = m.mixed_plus_args
mixed_plus_args_kwargs_defaults) mpk = m.mixed_plus_kwargs
mpa = mixed_plus_args mpak = m.mixed_plus_args_kwargs
mpk = mixed_plus_kwargs mpakd = m.mixed_plus_args_kwargs_defaults
mpak = mixed_plus_args_kwargs
mpakd = mixed_plus_args_kwargs_defaults
assert mpa(1, 2.5, 4, 99.5, None) == (1, 2.5, (4, 99.5, None)) assert mpa(1, 2.5, 4, 99.5, None) == (1, 2.5, (4, 99.5, None))
assert mpa(1, 2.5) == (1, 2.5, ()) assert mpa(1, 2.5) == (1, 2.5, ())
......
...@@ -11,42 +11,38 @@ ...@@ -11,42 +11,38 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include "constructor_stats.h" #include "constructor_stats.h"
std::string submodule_func() { TEST_SUBMODULE(modules, m) {
return "submodule_func()"; // test_nested_modules
} py::module m_sub = m.def_submodule("subsubmodule");
m_sub.def("submodule_func", []() { return "submodule_func()"; });
class A {
public: // test_reference_internal
A(int v) : v(v) { print_created(this, v); } class A {
~A() { print_destroyed(this); } public:
A(const A&) { print_copy_created(this); } A(int v) : v(v) { print_created(this, v); }
A& operator=(const A &copy) { print_copy_assigned(this); v = copy.v; return *this; } ~A() { print_destroyed(this); }
std::string toString() { return "A[" + std::to_string(v) + "]"; } A(const A&) { print_copy_created(this); }
private: A& operator=(const A &copy) { print_copy_assigned(this); v = copy.v; return *this; }
int v; std::string toString() { return "A[" + std::to_string(v) + "]"; }
}; private:
int v;
class B { };
public:
B() { print_default_created(this); }
~B() { print_destroyed(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; }
A &get_a1() { return a1; }
A &get_a2() { return a2; }
A a1{1};
A a2{2};
};
test_initializer modules([](py::module &m) {
py::module m_sub = m.def_submodule("submodule");
m_sub.def("submodule_func", &submodule_func);
py::class_<A>(m_sub, "A") py::class_<A>(m_sub, "A")
.def(py::init<int>()) .def(py::init<int>())
.def("__repr__", &A::toString); .def("__repr__", &A::toString);
class B {
public:
B() { print_default_created(this); }
~B() { print_destroyed(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; }
A &get_a1() { return a1; }
A &get_a2() { return a2; }
A a1{1};
A a2{2};
};
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", &B::get_a1, "Return the internal A 1", py::return_value_policy::reference_internal)
...@@ -56,6 +52,7 @@ test_initializer modules([](py::module &m) { ...@@ -56,6 +52,7 @@ test_initializer modules([](py::module &m) {
m.attr("OD") = py::module::import("collections").attr("OrderedDict"); m.attr("OD") = py::module::import("collections").attr("OrderedDict");
// 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 { };
...@@ -98,4 +95,4 @@ test_initializer modules([](py::module &m) { ...@@ -98,4 +95,4 @@ test_initializer modules([](py::module &m) {
return failures; return failures;
}); });
}); }
from pybind11_tests import modules as m
from pybind11_tests.modules import subsubmodule as ms
from pybind11_tests import ConstructorStats
def test_nested_modules(): def test_nested_modules():
import pybind11_tests import pybind11_tests
from pybind11_tests.submodule import submodule_func
assert pybind11_tests.__name__ == "pybind11_tests" assert pybind11_tests.__name__ == "pybind11_tests"
assert pybind11_tests.submodule.__name__ == "pybind11_tests.submodule" assert pybind11_tests.modules.__name__ == "pybind11_tests.modules"
assert pybind11_tests.modules.subsubmodule.__name__ == "pybind11_tests.modules.subsubmodule"
assert m.__name__ == "pybind11_tests.modules"
assert ms.__name__ == "pybind11_tests.modules.subsubmodule"
assert submodule_func() == "submodule_func()" assert ms.submodule_func() == "submodule_func()"
def test_reference_internal(): def test_reference_internal():
from pybind11_tests import ConstructorStats b = ms.B()
from pybind11_tests.submodule import A, B
b = B()
assert str(b.get_a1()) == "A[1]" assert str(b.get_a1()) == "A[1]"
assert str(b.a1) == "A[1]" assert str(b.a1) == "A[1]"
assert str(b.get_a2()) == "A[2]" assert str(b.get_a2()) == "A[2]"
assert str(b.a2) == "A[2]" assert str(b.a2) == "A[2]"
b.a1 = A(42) b.a1 = ms.A(42)
b.a2 = A(43) b.a2 = ms.A(43)
assert str(b.get_a1()) == "A[42]" assert str(b.get_a1()) == "A[42]"
assert str(b.a1) == "A[42]" assert str(b.a1) == "A[42]"
assert str(b.get_a2()) == "A[43]" assert str(b.get_a2()) == "A[43]"
assert str(b.a2) == "A[43]" assert str(b.a2) == "A[43]"
astats, bstats = ConstructorStats.get(A), ConstructorStats.get(B) astats, bstats = ConstructorStats.get(ms.A), ConstructorStats.get(ms.B)
assert astats.alive() == 2 assert astats.alive() == 2
assert bstats.alive() == 1 assert bstats.alive() == 1
del b del b
...@@ -47,7 +49,7 @@ def test_reference_internal(): ...@@ -47,7 +49,7 @@ def test_reference_internal():
def test_importing(): def test_importing():
from pybind11_tests import OD from pybind11_tests.modules import OD
from collections import OrderedDict from collections import OrderedDict
assert OD is OrderedDict assert OD is OrderedDict
...@@ -66,6 +68,5 @@ def test_pydoc(): ...@@ -66,6 +68,5 @@ def test_pydoc():
def test_duplicate_registration(): def test_duplicate_registration():
"""Registering two things with the same name""" """Registering two things with the same name"""
from pybind11_tests import duplicate_registration
assert duplicate_registration() == [] assert m.duplicate_registration() == []
...@@ -26,20 +26,6 @@ template<typename... Ix> arr data_t(const arr_t& a, Ix... index) { ...@@ -26,20 +26,6 @@ template<typename... Ix> arr data_t(const arr_t& a, Ix... index) {
return arr(a.size() - a.index_at(index...), a.data(index...)); return arr(a.size() - a.index_at(index...), a.data(index...));
} }
arr& mutate_data(arr& a) {
auto ptr = (uint8_t *) a.mutable_data();
for (ssize_t i = 0; i < a.nbytes(); i++)
ptr[i] = (uint8_t) (ptr[i] * 2);
return a;
}
arr_t& mutate_data_t(arr_t& a) {
auto ptr = a.mutable_data();
for (ssize_t i = 0; i < a.size(); i++)
ptr[i]++;
return a;
}
template<typename... Ix> arr& mutate_data(arr& a, Ix... index) { template<typename... Ix> arr& mutate_data(arr& a, Ix... index) {
auto ptr = (uint8_t *) a.mutable_data(index...); auto ptr = (uint8_t *) a.mutable_data(index...);
for (ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++) for (ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++)
...@@ -82,9 +68,11 @@ template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) { ...@@ -82,9 +68,11 @@ template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) {
return l.release(); return l.release();
} }
test_initializer numpy_array([](py::module &m) { TEST_SUBMODULE(numpy_array, sm) {
auto sm = m.def_submodule("array"); try { py::module::import("numpy"); }
catch (...) { return; }
// test_array_attributes
sm.def("ndim", [](const arr& a) { return a.ndim(); }); sm.def("ndim", [](const arr& a) { return a.ndim(); });
sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); }); sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); });
sm.def("shape", [](const arr& a, ssize_t dim) { return a.shape(dim); }); sm.def("shape", [](const arr& a, ssize_t dim) { return a.shape(dim); });
...@@ -96,25 +84,25 @@ test_initializer numpy_array([](py::module &m) { ...@@ -96,25 +84,25 @@ test_initializer numpy_array([](py::module &m) {
sm.def("nbytes", [](const arr& a) { return a.nbytes(); }); sm.def("nbytes", [](const arr& a) { return a.nbytes(); });
sm.def("owndata", [](const arr& a) { return a.owndata(); }); sm.def("owndata", [](const arr& a) { return a.owndata(); });
def_index_fn(data, const arr&); // test_index_offset
def_index_fn(data_t, const arr_t&);
def_index_fn(index_at, const arr&); def_index_fn(index_at, const arr&);
def_index_fn(index_at_t, const arr_t&); def_index_fn(index_at_t, const arr_t&);
def_index_fn(offset_at, const arr&); def_index_fn(offset_at, const arr&);
def_index_fn(offset_at_t, const arr_t&); def_index_fn(offset_at_t, const arr_t&);
// test_data
def_index_fn(data, const arr&);
def_index_fn(data_t, const arr_t&);
// test_mutate_data, test_mutate_readonly
def_index_fn(mutate_data, arr&); def_index_fn(mutate_data, arr&);
def_index_fn(mutate_data_t, arr_t&); def_index_fn(mutate_data_t, arr_t&);
def_index_fn(at_t, const arr_t&); def_index_fn(at_t, const arr_t&);
def_index_fn(mutate_at_t, arr_t&); def_index_fn(mutate_at_t, arr_t&);
sm.def("make_f_array", [] { // test_make_c_f_array
return py::array_t<float>({ 2, 2 }, { 4, 8 }); sm.def("make_f_array", [] { return py::array_t<float>({ 2, 2 }, { 4, 8 }); });
}); sm.def("make_c_array", [] { return py::array_t<float>({ 2, 2 }, { 8, 4 }); });
sm.def("make_c_array", [] {
return py::array_t<float>({ 2, 2 }, { 8, 4 });
});
// test_wrap
sm.def("wrap", [](py::array a) { sm.def("wrap", [](py::array a) {
return py::array( return py::array(
a.dtype(), a.dtype(),
...@@ -125,12 +113,12 @@ test_initializer numpy_array([](py::module &m) { ...@@ -125,12 +113,12 @@ test_initializer numpy_array([](py::module &m) {
); );
}); });
// test_numpy_view
struct ArrayClass { struct ArrayClass {
int data[2] = { 1, 2 }; int data[2] = { 1, 2 };
ArrayClass() { py::print("ArrayClass()"); } ArrayClass() { py::print("ArrayClass()"); }
~ArrayClass() { py::print("~ArrayClass()"); } ~ArrayClass() { py::print("~ArrayClass()"); }
}; };
py::class_<ArrayClass>(sm, "ArrayClass") py::class_<ArrayClass>(sm, "ArrayClass")
.def(py::init<>()) .def(py::init<>())
.def("numpy_view", [](py::object &obj) { .def("numpy_view", [](py::object &obj) {
...@@ -140,16 +128,18 @@ test_initializer numpy_array([](py::module &m) { ...@@ -140,16 +128,18 @@ test_initializer numpy_array([](py::module &m) {
} }
); );
// test_cast_numpy_int64_to_uint64
sm.def("function_taking_uint64", [](uint64_t) { }); sm.def("function_taking_uint64", [](uint64_t) { });
// test_isinstance
sm.def("isinstance_untyped", [](py::object yes, py::object no) { sm.def("isinstance_untyped", [](py::object yes, py::object no) {
return py::isinstance<py::array>(yes) && !py::isinstance<py::array>(no); return py::isinstance<py::array>(yes) && !py::isinstance<py::array>(no);
}); });
sm.def("isinstance_typed", [](py::object o) { sm.def("isinstance_typed", [](py::object o) {
return py::isinstance<py::array_t<double>>(o) && !py::isinstance<py::array_t<int>>(o); return py::isinstance<py::array_t<double>>(o) && !py::isinstance<py::array_t<int>>(o);
}); });
// test_constructors
sm.def("default_constructors", []() { sm.def("default_constructors", []() {
return py::dict( return py::dict(
"array"_a=py::array(), "array"_a=py::array(),
...@@ -157,7 +147,6 @@ test_initializer numpy_array([](py::module &m) { ...@@ -157,7 +147,6 @@ test_initializer numpy_array([](py::module &m) {
"array_t<double>"_a=py::array_t<double>() "array_t<double>"_a=py::array_t<double>()
); );
}); });
sm.def("converting_constructors", [](py::object o) { sm.def("converting_constructors", [](py::object o) {
return py::dict( return py::dict(
"array"_a=py::array(o), "array"_a=py::array(o),
...@@ -166,7 +155,7 @@ test_initializer numpy_array([](py::module &m) { ...@@ -166,7 +155,7 @@ test_initializer numpy_array([](py::module &m) {
); );
}); });
// Overload resolution tests: // test_overload_resolution
sm.def("overloaded", [](py::array_t<double>) { return "double"; }); sm.def("overloaded", [](py::array_t<double>) { return "double"; });
sm.def("overloaded", [](py::array_t<float>) { return "float"; }); sm.def("overloaded", [](py::array_t<float>) { return "float"; });
sm.def("overloaded", [](py::array_t<int>) { return "int"; }); sm.def("overloaded", [](py::array_t<int>) { return "int"; });
...@@ -194,11 +183,13 @@ test_initializer numpy_array([](py::module &m) { ...@@ -194,11 +183,13 @@ test_initializer numpy_array([](py::module &m) {
sm.def("overloaded5", [](py::array_t<unsigned int>) { return "unsigned int"; }); sm.def("overloaded5", [](py::array_t<unsigned int>) { return "unsigned int"; });
sm.def("overloaded5", [](py::array_t<double>) { return "double"; }); sm.def("overloaded5", [](py::array_t<double>) { return "double"; });
// test_greedy_string_overload
// Issue 685: ndarray shouldn't go to std::string overload // Issue 685: ndarray shouldn't go to std::string overload
sm.def("issue685", [](std::string) { return "string"; }); sm.def("issue685", [](std::string) { return "string"; });
sm.def("issue685", [](py::array) { return "array"; }); sm.def("issue685", [](py::array) { return "array"; });
sm.def("issue685", [](py::object) { return "other"; }); sm.def("issue685", [](py::object) { return "other"; });
// test_array_unchecked_fixed_dims
sm.def("proxy_add2", [](py::array_t<double> a, double v) { sm.def("proxy_add2", [](py::array_t<double> a, double v) {
auto r = a.mutable_unchecked<2>(); auto r = a.mutable_unchecked<2>();
for (ssize_t i = 0; i < r.shape(0); i++) for (ssize_t i = 0; i < r.shape(0); i++)
...@@ -238,6 +229,7 @@ test_initializer numpy_array([](py::module &m) { ...@@ -238,6 +229,7 @@ test_initializer numpy_array([](py::module &m) {
return auxiliaries(r, r2); return auxiliaries(r, r2);
}); });
// test_array_unchecked_dyn_dims
// Same as the above, but without a compile-time dimensions specification: // Same as the above, but without a compile-time dimensions specification:
sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) { sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) {
auto r = a.mutable_unchecked(); auto r = a.mutable_unchecked();
...@@ -264,19 +256,21 @@ test_initializer numpy_array([](py::module &m) { ...@@ -264,19 +256,21 @@ test_initializer numpy_array([](py::module &m) {
return auxiliaries(a, a); return auxiliaries(a, a);
}); });
// test_array_failures
// Issue #785: Uninformative "Unknown internal error" exception when constructing array from empty object: // Issue #785: Uninformative "Unknown internal error" exception when constructing array from empty object:
sm.def("array_fail_test", []() { return py::array(py::object()); }); sm.def("array_fail_test", []() { return py::array(py::object()); });
sm.def("array_t_fail_test", []() { return py::array_t<double>(py::object()); }); sm.def("array_t_fail_test", []() { return py::array_t<double>(py::object()); });
// Make sure the error from numpy is being passed through: // Make sure the error from numpy is being passed through:
sm.def("array_fail_test_negative_size", []() { int c = 0; return py::array(-1, &c); }); sm.def("array_fail_test_negative_size", []() { int c = 0; return py::array(-1, &c); });
// test_initializer_list
// Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous // Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous
sm.def("array_initializer_list", []() { return py::array_t<float>(1); }); // { 1 } also works, but clang warns about it sm.def("array_initializer_list1", []() { return py::array_t<float>(1); }); // { 1 } also works, but clang warns about it
sm.def("array_initializer_list", []() { return py::array_t<float>({ 1, 2 }); }); sm.def("array_initializer_list2", []() { return py::array_t<float>({ 1, 2 }); });
sm.def("array_initializer_list", []() { return py::array_t<float>({ 1, 2, 3 }); }); sm.def("array_initializer_list3", []() { return py::array_t<float>({ 1, 2, 3 }); });
sm.def("array_initializer_list", []() { return py::array_t<float>({ 1, 2, 3, 4 }); }); sm.def("array_initializer_list4", []() { return py::array_t<float>({ 1, 2, 3, 4 }); });
// test_array_resize
// reshape array to 2D without changing size // reshape array to 2D without changing size
sm.def("array_reshape2", [](py::array_t<double> a) { sm.def("array_reshape2", [](py::array_t<double> a) {
const ssize_t dim_sz = (ssize_t)std::sqrt(a.size()); const ssize_t dim_sz = (ssize_t)std::sqrt(a.size());
...@@ -290,6 +284,7 @@ test_initializer numpy_array([](py::module &m) { ...@@ -290,6 +284,7 @@ test_initializer numpy_array([](py::module &m) {
a.resize({N, N, N}, refcheck); a.resize({N, N, N}, refcheck);
}); });
// test_array_create_and_resize
// return 2D array with Nrows = Ncols = N // return 2D array with Nrows = Ncols = N
sm.def("create_and_resize", [](size_t N) { sm.def("create_and_resize", [](size_t N) {
py::array_t<double> a; py::array_t<double> a;
...@@ -297,4 +292,4 @@ test_initializer numpy_array([](py::module &m) { ...@@ -297,4 +292,4 @@ test_initializer numpy_array([](py::module &m) {
std::fill(a.mutable_data(), a.mutable_data() + a.size(), 42.); std::fill(a.mutable_data(), a.mutable_data() + a.size(), 42.);
return a; return a;
}); });
}); }
...@@ -16,22 +16,11 @@ double my_func(int x, float y, double z) { ...@@ -16,22 +16,11 @@ double my_func(int x, float y, double z) {
return (float) x*y*z; return (float) x*y*z;
} }
std::complex<double> my_func3(std::complex<double> c) { TEST_SUBMODULE(numpy_vectorize, m) {
return c * std::complex<double>(2.f); try { py::module::import("numpy"); }
} catch (...) { return; }
struct VectorizeTestClass {
VectorizeTestClass(int v) : value{v} {};
float method(int x, float y) { return y + (float) (x + value); }
int value = 0;
};
struct NonPODClass {
NonPODClass(int v) : value{v} {}
int value;
};
test_initializer numpy_vectorize([](py::module &m) { // test_vectorize, test_docs, test_array_collapse
// Vectorize all arguments of a function (though non-vector arguments are also allowed) // Vectorize all arguments of a function (though non-vector arguments are also allowed)
m.def("vectorized_func", py::vectorize(my_func)); m.def("vectorized_func", py::vectorize(my_func));
...@@ -43,16 +32,24 @@ test_initializer numpy_vectorize([](py::module &m) { ...@@ -43,16 +32,24 @@ test_initializer numpy_vectorize([](py::module &m) {
); );
// Vectorize a complex-valued function // Vectorize a complex-valued function
m.def("vectorized_func3", py::vectorize(my_func3)); m.def("vectorized_func3", py::vectorize(
[](std::complex<double> c) { return c * std::complex<double>(2.f); }
));
/// Numpy function which only accepts specific data types // test_type_selection
// Numpy function which only accepts specific data types
m.def("selective_func", [](py::array_t<int, py::array::c_style>) { return "Int branch taken."; }); m.def("selective_func", [](py::array_t<int, py::array::c_style>) { return "Int branch taken."; });
m.def("selective_func", [](py::array_t<float, py::array::c_style>) { return "Float branch taken."; }); m.def("selective_func", [](py::array_t<float, py::array::c_style>) { return "Float branch taken."; });
m.def("selective_func", [](py::array_t<std::complex<float>, py::array::c_style>) { return "Complex float branch taken."; }); m.def("selective_func", [](py::array_t<std::complex<float>, py::array::c_style>) { return "Complex float branch taken."; });
// test_passthrough_arguments
// Passthrough test: references and non-pod types should be automatically passed through (in the // Passthrough test: references and non-pod types should be automatically passed through (in the
// function definition below, only `b`, `d`, and `g` are vectorized): // function definition below, only `b`, `d`, and `g` are vectorized):
struct NonPODClass {
NonPODClass(int v) : value{v} {}
int value;
};
py::class_<NonPODClass>(m, "NonPODClass").def(py::init<int>()); py::class_<NonPODClass>(m, "NonPODClass").def(py::init<int>());
m.def("vec_passthrough", py::vectorize( m.def("vec_passthrough", py::vectorize(
[](double *a, double b, py::array_t<double> c, const int &d, int &e, NonPODClass f, const double g) { [](double *a, double b, py::array_t<double> c, const int &d, int &e, NonPODClass f, const double g) {
...@@ -60,6 +57,12 @@ test_initializer numpy_vectorize([](py::module &m) { ...@@ -60,6 +57,12 @@ test_initializer numpy_vectorize([](py::module &m) {
} }
)); ));
// test_method_vectorization
struct VectorizeTestClass {
VectorizeTestClass(int v) : value{v} {};
float method(int x, float y) { return y + (float) (x + value); }
int value = 0;
};
py::class_<VectorizeTestClass> vtc(m, "VectorizeTestClass"); py::class_<VectorizeTestClass> vtc(m, "VectorizeTestClass");
vtc .def(py::init<int>()) vtc .def(py::init<int>())
.def_readwrite("value", &VectorizeTestClass::value); .def_readwrite("value", &VectorizeTestClass::value);
...@@ -67,6 +70,7 @@ test_initializer numpy_vectorize([](py::module &m) { ...@@ -67,6 +70,7 @@ test_initializer numpy_vectorize([](py::module &m) {
// Automatic vectorizing of methods // Automatic vectorizing of methods
vtc.def("method", py::vectorize(&VectorizeTestClass::method)); vtc.def("method", py::vectorize(&VectorizeTestClass::method));
// test_trivial_broadcasting
// Internal optimization test for whether the input is trivially broadcastable: // Internal optimization test for whether the input is trivially broadcastable:
py::enum_<py::detail::broadcast_trivial>(m, "trivial") py::enum_<py::detail::broadcast_trivial>(m, "trivial")
.value("f_trivial", py::detail::broadcast_trivial::f_trivial) .value("f_trivial", py::detail::broadcast_trivial::f_trivial)
...@@ -82,4 +86,4 @@ test_initializer numpy_vectorize([](py::module &m) { ...@@ -82,4 +86,4 @@ test_initializer numpy_vectorize([](py::module &m) {
std::array<py::buffer_info, 3> buffers {{ arg1.request(), arg2.request(), arg3.request() }}; std::array<py::buffer_info, 3> buffers {{ arg1.request(), arg2.request(), arg3.request() }};
return py::detail::broadcast(buffers, ndim, shape); return py::detail::broadcast(buffers, ndim, shape);
}); });
}); }
import pytest import pytest
from pybind11_tests import numpy_vectorize as m
pytestmark = pytest.requires_numpy pytestmark = pytest.requires_numpy
...@@ -7,11 +8,9 @@ with pytest.suppress(ImportError): ...@@ -7,11 +8,9 @@ with pytest.suppress(ImportError):
def test_vectorize(capture): def test_vectorize(capture):
from pybind11_tests import vectorized_func, vectorized_func2, vectorized_func3 assert np.isclose(m.vectorized_func3(np.array(3 + 7j)), [6 + 14j])
assert np.isclose(vectorized_func3(np.array(3 + 7j)), [6 + 14j]) for f in [m.vectorized_func, m.vectorized_func2]:
for f in [vectorized_func, vectorized_func2]:
with capture: with capture:
assert np.isclose(f(1, 2, 3), 6) assert np.isclose(f(1, 2, 3), 6)
assert capture == "my_func(x:int=1, y:float=2, z:float=3)" assert capture == "my_func(x:int=1, y:float=2, z:float=3)"
...@@ -103,23 +102,19 @@ def test_vectorize(capture): ...@@ -103,23 +102,19 @@ def test_vectorize(capture):
def test_type_selection(): def test_type_selection():
from pybind11_tests import selective_func assert m.selective_func(np.array([1], dtype=np.int32)) == "Int branch taken."
assert m.selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken."
assert selective_func(np.array([1], dtype=np.int32)) == "Int branch taken." assert m.selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken."
assert selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken."
assert selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken."
def test_docs(doc): def test_docs(doc):
from pybind11_tests import vectorized_func assert doc(m.vectorized_func) == """
assert doc(vectorized_func) == """
vectorized_func(arg0: numpy.ndarray[int32], arg1: numpy.ndarray[float32], arg2: numpy.ndarray[float64]) -> object vectorized_func(arg0: numpy.ndarray[int32], arg1: numpy.ndarray[float32], arg2: numpy.ndarray[float64]) -> object
""" # noqa: E501 line too long """ # noqa: E501 line too long
def test_trivial_broadcasting(): def test_trivial_broadcasting():
from pybind11_tests import vectorized_is_trivial, trivial, vectorized_func trivial, vectorized_is_trivial = m.trivial, m.vectorized_is_trivial
assert vectorized_is_trivial(1, 2, 3) == trivial.c_trivial assert vectorized_is_trivial(1, 2, 3) == trivial.c_trivial
assert vectorized_is_trivial(np.array(1), np.array(2), 3) == trivial.c_trivial assert vectorized_is_trivial(np.array(1), np.array(2), 3) == trivial.c_trivial
...@@ -153,51 +148,49 @@ def test_trivial_broadcasting(): ...@@ -153,51 +148,49 @@ def test_trivial_broadcasting():
assert vectorized_is_trivial(z1[1::4, 1::4], y2, 1) == trivial.f_trivial assert vectorized_is_trivial(z1[1::4, 1::4], y2, 1) == trivial.f_trivial
assert vectorized_is_trivial(y1[1::4, 1::4], z2, 1) == trivial.c_trivial assert vectorized_is_trivial(y1[1::4, 1::4], z2, 1) == trivial.c_trivial
assert vectorized_func(z1, z2, z3).flags.c_contiguous assert m.vectorized_func(z1, z2, z3).flags.c_contiguous
assert vectorized_func(y1, y2, y3).flags.f_contiguous assert m.vectorized_func(y1, y2, y3).flags.f_contiguous
assert vectorized_func(z1, 1, 1).flags.c_contiguous assert m.vectorized_func(z1, 1, 1).flags.c_contiguous
assert vectorized_func(1, y2, 1).flags.f_contiguous assert m.vectorized_func(1, y2, 1).flags.f_contiguous
assert vectorized_func(z1[1::4, 1::4], y2, 1).flags.f_contiguous assert m.vectorized_func(z1[1::4, 1::4], y2, 1).flags.f_contiguous
assert vectorized_func(y1[1::4, 1::4], z2, 1).flags.c_contiguous assert m.vectorized_func(y1[1::4, 1::4], z2, 1).flags.c_contiguous
def test_passthrough_arguments(doc): def test_passthrough_arguments(doc):
from pybind11_tests import vec_passthrough, NonPODClass assert doc(m.vec_passthrough) == (
"vec_passthrough(" + ", ".join([
assert doc(vec_passthrough) == ( "arg0: float",
"vec_passthrough(" "arg1: numpy.ndarray[float64]",
"arg0: float, arg1: numpy.ndarray[float64], arg2: numpy.ndarray[float64], " "arg2: numpy.ndarray[float64]",
"arg3: numpy.ndarray[int32], arg4: int, arg5: m.NonPODClass, arg6: numpy.ndarray[float64]" "arg3: numpy.ndarray[int32]",
") -> object") "arg4: int",
"arg5: m.numpy_vectorize.NonPODClass",
"arg6: numpy.ndarray[float64]"]) + ") -> object")
b = np.array([[10, 20, 30]], dtype='float64') b = np.array([[10, 20, 30]], dtype='float64')
c = np.array([100, 200]) # NOT a vectorized argument c = np.array([100, 200]) # NOT a vectorized argument
d = np.array([[1000], [2000], [3000]], dtype='int') d = np.array([[1000], [2000], [3000]], dtype='int')
g = np.array([[1000000, 2000000, 3000000]], dtype='int') # requires casting g = np.array([[1000000, 2000000, 3000000]], dtype='int') # requires casting
assert np.all( assert np.all(
vec_passthrough(1, b, c, d, 10000, NonPODClass(100000), g) == m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g) ==
np.array([[1111111, 2111121, 3111131], np.array([[1111111, 2111121, 3111131],
[1112111, 2112121, 3112131], [1112111, 2112121, 3112131],
[1113111, 2113121, 3113131]])) [1113111, 2113121, 3113131]]))
def test_method_vectorization(): def test_method_vectorization():
from pybind11_tests import VectorizeTestClass o = m.VectorizeTestClass(3)
o = VectorizeTestClass(3)
x = np.array([1, 2], dtype='int') x = np.array([1, 2], dtype='int')
y = np.array([[10], [20]], dtype='float32') y = np.array([[10], [20]], dtype='float32')
assert np.all(o.method(x, y) == [[14, 15], [24, 25]]) assert np.all(o.method(x, y) == [[14, 15], [24, 25]])
def test_array_collapse(): def test_array_collapse():
from pybind11_tests import vectorized_func assert not isinstance(m.vectorized_func(1, 2, 3), np.ndarray)
assert not isinstance(m.vectorized_func(np.array(1), 2, 3), np.ndarray)
assert not isinstance(vectorized_func(1, 2, 3), np.ndarray) z = m.vectorized_func([1], 2, 3)
assert not isinstance(vectorized_func(np.array(1), 2, 3), np.ndarray)
z = vectorized_func([1], 2, 3)
assert isinstance(z, np.ndarray) assert isinstance(z, np.ndarray)
assert z.shape == (1, ) assert z.shape == (1, )
z = vectorized_func(1, [[[2]]], 3) z = m.vectorized_func(1, [[[2]]], 3)
assert isinstance(z, np.ndarray) assert isinstance(z, np.ndarray)
assert z.shape == (1, 1, 1) assert z.shape == (1, 1, 1)
...@@ -11,17 +11,13 @@ ...@@ -11,17 +11,13 @@
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include <vector> #include <vector>
typedef std::vector<std::string> StringList; using StringList = std::vector<std::string>;
class ClassWithSTLVecProperty {
public:
StringList stringList;
};
/* IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures */ /* IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures */
PYBIND11_MAKE_OPAQUE(StringList); PYBIND11_MAKE_OPAQUE(StringList);
test_initializer opaque_types([](py::module &m) { TEST_SUBMODULE(opaque_types, m) {
// test_string_list
py::class_<StringList>(m, "StringList") py::class_<StringList>(m, "StringList")
.def(py::init<>()) .def(py::init<>())
.def("pop_back", &StringList::pop_back) .def("pop_back", &StringList::pop_back)
...@@ -33,6 +29,10 @@ test_initializer opaque_types([](py::module &m) { ...@@ -33,6 +29,10 @@ test_initializer opaque_types([](py::module &m) {
return py::make_iterator(v.begin(), v.end()); return py::make_iterator(v.begin(), v.end());
}, py::keep_alive<0, 1>()); }, py::keep_alive<0, 1>());
class ClassWithSTLVecProperty {
public:
StringList stringList;
};
py::class_<ClassWithSTLVecProperty>(m, "ClassWithSTLVecProperty") py::class_<ClassWithSTLVecProperty>(m, "ClassWithSTLVecProperty")
.def(py::init<>()) .def(py::init<>())
.def_readwrite("stringList", &ClassWithSTLVecProperty::stringList); .def_readwrite("stringList", &ClassWithSTLVecProperty::stringList);
...@@ -49,6 +49,7 @@ test_initializer opaque_types([](py::module &m) { ...@@ -49,6 +49,7 @@ test_initializer opaque_types([](py::module &m) {
return ret + "]"; return ret + "]";
}); });
// test_pointers
m.def("return_void_ptr", []() { return (void *) 0x1234; }); m.def("return_void_ptr", []() { return (void *) 0x1234; });
m.def("get_void_ptr_value", [](void *ptr) { return reinterpret_cast<std::intptr_t>(ptr); }); m.def("get_void_ptr_value", [](void *ptr) { return reinterpret_cast<std::intptr_t>(ptr); });
m.def("return_null_str", []() { return (char *) nullptr; }); m.def("return_null_str", []() { return (char *) nullptr; });
...@@ -59,4 +60,4 @@ test_initializer opaque_types([](py::module &m) { ...@@ -59,4 +60,4 @@ test_initializer opaque_types([](py::module &m) {
result->push_back("some value"); result->push_back("some value");
return std::unique_ptr<StringList>(result); return std::unique_ptr<StringList>(result);
}); });
}); }
import pytest import pytest
from pybind11_tests import opaque_types as m
from pybind11_tests import ConstructorStats, UserType
def test_string_list(): def test_string_list():
from pybind11_tests import StringList, ClassWithSTLVecProperty, print_opaque_list l = m.StringList()
l = StringList()
l.push_back("Element 1") l.push_back("Element 1")
l.push_back("Element 2") l.push_back("Element 2")
assert print_opaque_list(l) == "Opaque list: [Element 1, Element 2]" assert m.print_opaque_list(l) == "Opaque list: [Element 1, Element 2]"
assert l.back() == "Element 2" assert l.back() == "Element 2"
for i, k in enumerate(l, start=1): for i, k in enumerate(l, start=1):
assert k == "Element {}".format(i) assert k == "Element {}".format(i)
l.pop_back() l.pop_back()
assert print_opaque_list(l) == "Opaque list: [Element 1]" assert m.print_opaque_list(l) == "Opaque list: [Element 1]"
cvp = ClassWithSTLVecProperty() cvp = m.ClassWithSTLVecProperty()
assert print_opaque_list(cvp.stringList) == "Opaque list: []" assert m.print_opaque_list(cvp.stringList) == "Opaque list: []"
cvp.stringList = l cvp.stringList = l
cvp.stringList.push_back("Element 3") cvp.stringList.push_back("Element 3")
assert print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]" assert m.print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]"
def test_pointers(msg): def test_pointers(msg):
from pybind11_tests import (return_void_ptr, get_void_ptr_value, ExampleMandA, living_before = ConstructorStats.get(UserType).alive()
print_opaque_list, return_null_str, get_null_str_value, assert m.get_void_ptr_value(m.return_void_ptr()) == 0x1234
return_unique_ptr, ConstructorStats) assert m.get_void_ptr_value(UserType()) # Should also work for other C++ types
assert ConstructorStats.get(UserType).alive() == living_before
living_before = ConstructorStats.get(ExampleMandA).alive()
assert get_void_ptr_value(return_void_ptr()) == 0x1234
assert get_void_ptr_value(ExampleMandA()) # Should also work for other C++ types
assert ConstructorStats.get(ExampleMandA).alive() == living_before
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
get_void_ptr_value([1, 2, 3]) # This should not work m.get_void_ptr_value([1, 2, 3]) # This should not work
assert msg(excinfo.value) == """ assert msg(excinfo.value) == """
get_void_ptr_value(): incompatible function arguments. The following argument types are supported: get_void_ptr_value(): incompatible function arguments. The following argument types are supported:
1. (arg0: capsule) -> int 1. (arg0: capsule) -> int
...@@ -42,9 +38,9 @@ def test_pointers(msg): ...@@ -42,9 +38,9 @@ def test_pointers(msg):
Invoked with: [1, 2, 3] Invoked with: [1, 2, 3]
""" # noqa: E501 line too long """ # noqa: E501 line too long
assert return_null_str() is None assert m.return_null_str() is None
assert get_null_str_value(return_null_str()) is not None assert m.get_null_str_value(m.return_null_str()) is not None
ptr = return_unique_ptr() ptr = m.return_unique_ptr()
assert "StringList" in repr(ptr) assert "StringList" in repr(ptr)
assert print_opaque_list(ptr) == "Opaque list: [some value]" assert m.print_opaque_list(ptr) == "Opaque list: [some value]"
...@@ -16,22 +16,11 @@ public: ...@@ -16,22 +16,11 @@ public:
Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); } Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); }
Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); } Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); }
Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; } Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; }
Vector2 &operator=(const Vector2 &v) { x = v.x; y = v.y; print_copy_assigned(this); return *this; }
Vector2 &operator=(Vector2 &&v) { x = v.x; y = v.y; v.x = v.y = 0; print_move_assigned(this); return *this; }
~Vector2() { print_destroyed(this); } ~Vector2() { print_destroyed(this); }
std::string toString() const { std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; }
return "[" + std::to_string(x) + ", " + std::to_string(y) + "]";
}
void operator=(const Vector2 &v) {
print_copy_assigned(this);
x = v.x;
y = v.y;
}
void operator=(Vector2 &&v) {
print_move_assigned(this);
x = v.x; y = v.y; v.x = v.y = 0;
}
Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); }
Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); } Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); }
...@@ -64,30 +53,9 @@ int operator+(const C2 &, const C2 &) { return 22; } ...@@ -64,30 +53,9 @@ int operator+(const C2 &, const C2 &) { return 22; }
int operator+(const C2 &, const C1 &) { return 21; } int operator+(const C2 &, const C1 &) { return 21; }
int operator+(const C1 &, const C2 &) { return 12; } int operator+(const C1 &, const C2 &) { return 12; }
struct NestABase { TEST_SUBMODULE(operators, m) {
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");
// test_operator_overloading
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)
...@@ -113,6 +81,7 @@ test_initializer operator_overloading([](py::module &pm) { ...@@ -113,6 +81,7 @@ test_initializer operator_overloading([](py::module &pm) {
m.attr("Vector") = m.attr("Vector2"); m.attr("Vector") = m.attr("Vector2");
// test_operators_notimplemented
// #393: need to return NotSupported to ensure correct arithmetic operator behavior // #393: need to return NotSupported to ensure correct arithmetic operator behavior
py::class_<C1>(m, "C1") py::class_<C1>(m, "C1")
.def(py::init<>()) .def(py::init<>())
...@@ -124,29 +93,44 @@ test_initializer operator_overloading([](py::module &pm) { ...@@ -124,29 +93,44 @@ test_initializer operator_overloading([](py::module &pm) {
.def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; }) .def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; })
.def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; }); .def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; });
// test_nested
// #328: first member in a class can't be used in operators // #328: first member in a class can't be used in operators
struct NestABase { int value = -2; };
py::class_<NestABase>(m, "NestABase") py::class_<NestABase>(m, "NestABase")
.def(py::init<>()) .def(py::init<>())
.def_readwrite("value", &NestABase::value); .def_readwrite("value", &NestABase::value);
struct NestA : NestABase {
int value = 3;
NestA& operator+=(int i) { value += i; return *this; }
};
py::class_<NestA>(m, "NestA") py::class_<NestA>(m, "NestA")
.def(py::init<>()) .def(py::init<>())
.def(py::self += int()) .def(py::self += int())
.def("as_base", [](NestA &a) -> NestABase& { .def("as_base", [](NestA &a) -> NestABase& {
return (NestABase&) a; return (NestABase&) a;
}, py::return_value_policy::reference_internal); }, py::return_value_policy::reference_internal);
m.def("get_NestA", [](const NestA &a) { return a.value; });
struct NestB {
NestA a;
int value = 4;
NestB& operator-=(int i) { value -= i; return *this; }
};
py::class_<NestB>(m, "NestB") py::class_<NestB>(m, "NestB")
.def(py::init<>()) .def(py::init<>())
.def(py::self -= int()) .def(py::self -= int())
.def_readwrite("a", &NestB::a); .def_readwrite("a", &NestB::a);
m.def("get_NestB", [](const NestB &b) { return b.value; });
struct NestC {
NestB b;
int value = 5;
NestC& operator*=(int i) { value *= i; return *this; }
};
py::class_<NestC>(m, "NestC") py::class_<NestC>(m, "NestC")
.def(py::init<>()) .def(py::init<>())
.def(py::self *= int()) .def(py::self *= int())
.def_readwrite("b", &NestC::b); .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; }); m.def("get_NestC", [](const NestC &c) { return c.value; });
}); }
import pytest import pytest
from pybind11_tests import operators as m
from pybind11_tests import ConstructorStats from pybind11_tests import ConstructorStats
def test_operator_overloading(): def test_operator_overloading():
from pybind11_tests.operators import Vector2, Vector v1 = m.Vector2(1, 2)
v2 = m.Vector(3, -1)
v1 = Vector2(1, 2)
v2 = Vector(3, -1)
assert str(v1) == "[1.000000, 2.000000]" assert str(v1) == "[1.000000, 2.000000]"
assert str(v2) == "[3.000000, -1.000000]" assert str(v2) == "[3.000000, -1.000000]"
...@@ -36,7 +35,7 @@ def test_operator_overloading(): ...@@ -36,7 +35,7 @@ def test_operator_overloading():
v2 /= v1 v2 /= v1
assert str(v2) == "[2.000000, 8.000000]" assert str(v2) == "[2.000000, 8.000000]"
cstats = ConstructorStats.get(Vector2) cstats = ConstructorStats.get(m.Vector2)
assert cstats.alive() == 2 assert cstats.alive() == 2
del v1 del v1
assert cstats.alive() == 1 assert cstats.alive() == 1
...@@ -59,9 +58,8 @@ def test_operator_overloading(): ...@@ -59,9 +58,8 @@ def test_operator_overloading():
def test_operators_notimplemented(): def test_operators_notimplemented():
"""#393: need to return NotSupported to ensure correct arithmetic operator behavior""" """#393: need to return NotSupported to ensure correct arithmetic operator behavior"""
from pybind11_tests.operators import C1, C2
c1, c2 = C1(), C2() c1, c2 = m.C1(), m.C2()
assert c1 + c1 == 11 assert c1 + c1 == 11
assert c2 + c2 == 22 assert c2 + c2 == 22
assert c2 + c1 == 21 assert c2 + c1 == 21
...@@ -70,24 +68,23 @@ def test_operators_notimplemented(): ...@@ -70,24 +68,23 @@ def test_operators_notimplemented():
def test_nested(): def test_nested():
"""#328: first member in a class can't be used in operators""" """#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() a = m.NestA()
b = NestB() b = m.NestB()
c = NestC() c = m.NestC()
a += 10 a += 10
assert get_NestA(a) == 13 assert m.get_NestA(a) == 13
b.a += 100 b.a += 100
assert get_NestA(b.a) == 103 assert m.get_NestA(b.a) == 103
c.b.a += 1000 c.b.a += 1000
assert get_NestA(c.b.a) == 1003 assert m.get_NestA(c.b.a) == 1003
b -= 1 b -= 1
assert get_NestB(b) == 3 assert m.get_NestB(b) == 3
c.b -= 3 c.b -= 3
assert get_NestB(c.b) == 1 assert m.get_NestB(c.b) == 1
c *= 7 c *= 7
assert get_NestC(c) == 35 assert m.get_NestC(c) == 35
abase = a.as_base() abase = a.as_base()
assert abase.value == -2 assert abase.value == -2
......
...@@ -9,30 +9,22 @@ ...@@ -9,30 +9,22 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
class Pickleable { TEST_SUBMODULE(pickling, m) {
public: // test_roundtrip
Pickleable(const std::string &value) : m_value(value) { } class Pickleable {
const std::string &value() const { return m_value; } public:
Pickleable(const std::string &value) : m_value(value) { }
const std::string &value() const { return m_value; }
void setExtra1(int extra1) { m_extra1 = extra1; } void setExtra1(int extra1) { m_extra1 = extra1; }
void setExtra2(int extra2) { m_extra2 = extra2; } void setExtra2(int extra2) { m_extra2 = extra2; }
int extra1() const { return m_extra1; } int extra1() const { return m_extra1; }
int extra2() const { return m_extra2; } int extra2() const { return m_extra2; }
private: private:
std::string m_value; std::string m_value;
int m_extra1 = 0; int m_extra1 = 0;
int m_extra2 = 0; int m_extra2 = 0;
}; };
class PickleableWithDict {
public:
PickleableWithDict(const std::string &value) : value(value) { }
std::string value;
int extra;
};
test_initializer pickling([](py::module &m) {
py::class_<Pickleable>(m, "Pickleable") py::class_<Pickleable>(m, "Pickleable")
.def(py::init<std::string>()) .def(py::init<std::string>())
.def("value", &Pickleable::value) .def("value", &Pickleable::value)
...@@ -58,6 +50,14 @@ test_initializer pickling([](py::module &m) { ...@@ -58,6 +50,14 @@ test_initializer pickling([](py::module &m) {
}); });
#if !defined(PYPY_VERSION) #if !defined(PYPY_VERSION)
// test_roundtrip_with_dict
class PickleableWithDict {
public:
PickleableWithDict(const std::string &value) : value(value) { }
std::string value;
int extra;
};
py::class_<PickleableWithDict>(m, "PickleableWithDict", py::dynamic_attr()) py::class_<PickleableWithDict>(m, "PickleableWithDict", py::dynamic_attr())
.def(py::init<std::string>()) .def(py::init<std::string>())
.def_readwrite("value", &PickleableWithDict::value) .def_readwrite("value", &PickleableWithDict::value)
...@@ -80,4 +80,4 @@ test_initializer pickling([](py::module &m) { ...@@ -80,4 +80,4 @@ test_initializer pickling([](py::module &m) {
self.attr("__dict__") = t[2]; self.attr("__dict__") = t[2];
}); });
#endif #endif
}); }
import pytest import pytest
from pybind11_tests import pickling as m
try: try:
import cPickle as pickle # Use cPickle on Python 2.7 import cPickle as pickle # Use cPickle on Python 2.7
...@@ -7,9 +8,7 @@ except ImportError: ...@@ -7,9 +8,7 @@ except ImportError:
def test_roundtrip(): def test_roundtrip():
from pybind11_tests import Pickleable p = m.Pickleable("test_value")
p = Pickleable("test_value")
p.setExtra1(15) p.setExtra1(15)
p.setExtra2(48) p.setExtra2(48)
...@@ -22,9 +21,7 @@ def test_roundtrip(): ...@@ -22,9 +21,7 @@ def test_roundtrip():
@pytest.unsupported_on_pypy @pytest.unsupported_on_pypy
def test_roundtrip_with_dict(): def test_roundtrip_with_dict():
from pybind11_tests import PickleableWithDict p = m.PickleableWithDict("test_value")
p = PickleableWithDict("test_value")
p.extra = 15 p.extra = 15
p.dynamic = "Attribute" p.dynamic = "Attribute"
......
import pytest import pytest
from pybind11_tests import sequences_and_iterators as m
from pybind11_tests import ConstructorStats
def isclose(a, b, rel_tol=1e-05, abs_tol=0.0): def isclose(a, b, rel_tol=1e-05, abs_tol=0.0):
...@@ -11,35 +13,30 @@ def allclose(a_list, b_list, rel_tol=1e-05, abs_tol=0.0): ...@@ -11,35 +13,30 @@ def allclose(a_list, b_list, rel_tol=1e-05, abs_tol=0.0):
def test_generalized_iterators(): def test_generalized_iterators():
from pybind11_tests.sequences_and_iterators import IntPairs assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero()) == [(1, 2), (3, 4)]
assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero()) == [(1, 2)]
assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero()) == []
assert list(IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero()) == [(1, 2), (3, 4)] assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_keys()) == [1, 3]
assert list(IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero()) == [(1, 2)] assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_keys()) == [1]
assert list(IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero()) == [] assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_keys()) == []
assert list(IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_keys()) == [1, 3]
assert list(IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_keys()) == [1]
assert list(IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_keys()) == []
# __next__ must continue to raise StopIteration # __next__ must continue to raise StopIteration
it = IntPairs([(0, 0)]).nonzero() it = m.IntPairs([(0, 0)]).nonzero()
for _ in range(3): for _ in range(3):
with pytest.raises(StopIteration): with pytest.raises(StopIteration):
next(it) next(it)
it = IntPairs([(0, 0)]).nonzero_keys() it = m.IntPairs([(0, 0)]).nonzero_keys()
for _ in range(3): for _ in range(3):
with pytest.raises(StopIteration): with pytest.raises(StopIteration):
next(it) next(it)
def test_sequence(): def test_sequence():
from pybind11_tests import ConstructorStats cstats = ConstructorStats.get(m.Sequence)
from pybind11_tests.sequences_and_iterators import Sequence
cstats = ConstructorStats.get(Sequence)
s = Sequence(5) s = m.Sequence(5)
assert cstats.values() == ['of size', '5'] assert cstats.values() == ['of size', '5']
assert "Sequence" in repr(s) assert "Sequence" in repr(s)
...@@ -56,7 +53,7 @@ def test_sequence(): ...@@ -56,7 +53,7 @@ def test_sequence():
rev2 = s[::-1] rev2 = s[::-1]
assert cstats.values() == ['of size', '5'] assert cstats.values() == ['of size', '5']
it = iter(Sequence(0)) it = iter(m.Sequence(0))
for _ in range(3): # __next__ must continue to raise StopIteration for _ in range(3): # __next__ must continue to raise StopIteration
with pytest.raises(StopIteration): with pytest.raises(StopIteration):
next(it) next(it)
...@@ -67,7 +64,7 @@ def test_sequence(): ...@@ -67,7 +64,7 @@ def test_sequence():
assert allclose(rev2, expected) assert allclose(rev2, expected)
assert rev == rev2 assert rev == rev2
rev[0::2] = Sequence([2.0, 2.0, 2.0]) rev[0::2] = m.Sequence([2.0, 2.0, 2.0])
assert cstats.values() == ['of size', '3', 'from std::vector'] assert cstats.values() == ['of size', '3', 'from std::vector']
assert allclose(rev, [2, 56.78, 2, 0, 2]) assert allclose(rev, [2, 56.78, 2, 0, 2])
...@@ -91,33 +88,29 @@ def test_sequence(): ...@@ -91,33 +88,29 @@ def test_sequence():
def test_map_iterator(): def test_map_iterator():
from pybind11_tests.sequences_and_iterators import StringMap sm = m.StringMap({'hi': 'bye', 'black': 'white'})
assert sm['hi'] == 'bye'
m = StringMap({'hi': 'bye', 'black': 'white'}) assert len(sm) == 2
assert m['hi'] == 'bye' assert sm['black'] == 'white'
assert len(m) == 2
assert m['black'] == 'white'
with pytest.raises(KeyError): with pytest.raises(KeyError):
assert m['orange'] assert sm['orange']
m['orange'] = 'banana' sm['orange'] = 'banana'
assert m['orange'] == 'banana' assert sm['orange'] == 'banana'
expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'} expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'}
for k in m: for k in sm:
assert m[k] == expected[k] assert sm[k] == expected[k]
for k, v in m.items(): for k, v in sm.items():
assert v == expected[k] assert v == expected[k]
it = iter(StringMap({})) it = iter(m.StringMap({}))
for _ in range(3): # __next__ must continue to raise StopIteration for _ in range(3): # __next__ must continue to raise StopIteration
with pytest.raises(StopIteration): with pytest.raises(StopIteration):
next(it) next(it)
def test_python_iterator_in_cpp(): def test_python_iterator_in_cpp():
import pybind11_tests.sequences_and_iterators as m
t = (1, 2, 3) t = (1, 2, 3)
assert m.object_to_list(t) == [1, 2, 3] assert m.object_to_list(t) == [1, 2, 3]
assert m.object_to_list(iter(t)) == [1, 2, 3] assert m.object_to_list(iter(t)) == [1, 2, 3]
......
import pytest import pytest
from pybind11_tests import smart_ptr as m
from pybind11_tests import ConstructorStats from pybind11_tests import ConstructorStats
def test_smart_ptr(capture): def test_smart_ptr(capture):
# Object1 # Object1
from pybind11_tests import (MyObject1, make_object_1, make_object_2, for i, o in enumerate([m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1):
print_object_1, print_object_2, print_object_3, print_object_4)
for i, o in enumerate([make_object_1(), make_object_2(), MyObject1(3)], start=1):
assert o.getRefCount() == 1 assert o.getRefCount() == 1
with capture: with capture:
print_object_1(o) m.print_object_1(o)
print_object_2(o) m.print_object_2(o)
print_object_3(o) m.print_object_3(o)
print_object_4(o) m.print_object_4(o)
assert capture == "MyObject1[{i}]\n".format(i=i) * 4 assert capture == "MyObject1[{i}]\n".format(i=i) * 4
from pybind11_tests import (make_myobject1_1, make_myobject1_2, for i, o in enumerate([m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7],
print_myobject1_1, print_myobject1_2, start=4):
print_myobject1_3, print_myobject1_4)
for i, o in enumerate([make_myobject1_1(), make_myobject1_2(), MyObject1(6), 7], start=4):
print(o) print(o)
with capture: with capture:
if not isinstance(o, int): if not isinstance(o, int):
print_object_1(o) m.print_object_1(o)
print_object_2(o) m.print_object_2(o)
print_object_3(o) m.print_object_3(o)
print_object_4(o) m.print_object_4(o)
print_myobject1_1(o) m.print_myobject1_1(o)
print_myobject1_2(o) m.print_myobject1_2(o)
print_myobject1_3(o) m.print_myobject1_3(o)
print_myobject1_4(o) m.print_myobject1_4(o)
assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8) assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8)
cstats = ConstructorStats.get(MyObject1) cstats = ConstructorStats.get(m.MyObject1)
assert cstats.alive() == 0 assert cstats.alive() == 0
expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4 expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4
assert cstats.values() == expected_values assert cstats.values() == expected_values
...@@ -45,21 +40,16 @@ def test_smart_ptr(capture): ...@@ -45,21 +40,16 @@ def test_smart_ptr(capture):
assert cstats.move_assignments == 0 assert cstats.move_assignments == 0
# Object2 # Object2
from pybind11_tests import (MyObject2, make_myobject2_1, make_myobject2_2, for i, o in zip([8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]):
make_myobject3_1, make_myobject3_2,
print_myobject2_1, print_myobject2_2,
print_myobject2_3, print_myobject2_4)
for i, o in zip([8, 6, 7], [MyObject2(8), make_myobject2_1(), make_myobject2_2()]):
print(o) print(o)
with capture: with capture:
print_myobject2_1(o) m.print_myobject2_1(o)
print_myobject2_2(o) m.print_myobject2_2(o)
print_myobject2_3(o) m.print_myobject2_3(o)
print_myobject2_4(o) m.print_myobject2_4(o)
assert capture == "MyObject2[{i}]\n".format(i=i) * 4 assert capture == "MyObject2[{i}]\n".format(i=i) * 4
cstats = ConstructorStats.get(MyObject2) cstats = ConstructorStats.get(m.MyObject2)
assert cstats.alive() == 1 assert cstats.alive() == 1
o = None o = None
assert cstats.alive() == 0 assert cstats.alive() == 0
...@@ -71,19 +61,16 @@ def test_smart_ptr(capture): ...@@ -71,19 +61,16 @@ def test_smart_ptr(capture):
assert cstats.move_assignments == 0 assert cstats.move_assignments == 0
# Object3 # Object3
from pybind11_tests import (MyObject3, print_myobject3_1, print_myobject3_2, for i, o in zip([9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]):
print_myobject3_3, print_myobject3_4)
for i, o in zip([9, 8, 9], [MyObject3(9), make_myobject3_1(), make_myobject3_2()]):
print(o) print(o)
with capture: with capture:
print_myobject3_1(o) m.print_myobject3_1(o)
print_myobject3_2(o) m.print_myobject3_2(o)
print_myobject3_3(o) m.print_myobject3_3(o)
print_myobject3_4(o) m.print_myobject3_4(o)
assert capture == "MyObject3[{i}]\n".format(i=i) * 4 assert capture == "MyObject3[{i}]\n".format(i=i) * 4
cstats = ConstructorStats.get(MyObject3) cstats = ConstructorStats.get(m.MyObject3)
assert cstats.alive() == 1 assert cstats.alive() == 1
o = None o = None
assert cstats.alive() == 0 assert cstats.alive() == 0
...@@ -94,10 +81,8 @@ def test_smart_ptr(capture): ...@@ -94,10 +81,8 @@ def test_smart_ptr(capture):
assert cstats.copy_assignments == 0 assert cstats.copy_assignments == 0
assert cstats.move_assignments == 0 assert cstats.move_assignments == 0
# Object and ref # Object
from pybind11_tests import Object, cstats_ref cstats = ConstructorStats.get(m.Object)
cstats = ConstructorStats.get(Object)
assert cstats.alive() == 0 assert cstats.alive() == 0
assert cstats.values() == [] assert cstats.values() == []
assert cstats.default_constructions == 10 assert cstats.default_constructions == 10
...@@ -106,7 +91,8 @@ def test_smart_ptr(capture): ...@@ -106,7 +91,8 @@ def test_smart_ptr(capture):
assert cstats.copy_assignments == 0 assert cstats.copy_assignments == 0
assert cstats.move_assignments == 0 assert cstats.move_assignments == 0
cstats = cstats_ref() # ref<>
cstats = m.cstats_ref()
assert cstats.alive() == 0 assert cstats.alive() == 0
assert cstats.values() == ['from pointer'] * 10 assert cstats.values() == ['from pointer'] * 10
assert cstats.default_constructions == 30 assert cstats.default_constructions == 30
...@@ -117,36 +103,30 @@ def test_smart_ptr(capture): ...@@ -117,36 +103,30 @@ def test_smart_ptr(capture):
def test_smart_ptr_refcounting(): def test_smart_ptr_refcounting():
from pybind11_tests import test_object1_refcounting assert m.test_object1_refcounting()
assert test_object1_refcounting()
def test_unique_nodelete(): def test_unique_nodelete():
from pybind11_tests import MyObject4 o = m.MyObject4(23)
o = MyObject4(23)
assert o.value == 23 assert o.value == 23
cstats = ConstructorStats.get(MyObject4) cstats = ConstructorStats.get(m.MyObject4)
assert cstats.alive() == 1 assert cstats.alive() == 1
del o del o
cstats = ConstructorStats.get(MyObject4)
assert cstats.alive() == 1 # Leak, but that's intentional assert cstats.alive() == 1 # Leak, but that's intentional
def test_large_holder(): def test_large_holder():
from pybind11_tests import MyObject5 o = m.MyObject5(5)
o = MyObject5(5)
assert o.value == 5 assert o.value == 5
cstats = ConstructorStats.get(MyObject5) cstats = ConstructorStats.get(m.MyObject5)
assert cstats.alive() == 1 assert cstats.alive() == 1
del o del o
assert cstats.alive() == 0 assert cstats.alive() == 0
def test_shared_ptr_and_references(): def test_shared_ptr_and_references():
from pybind11_tests.smart_ptr import SharedPtrRef, A s = m.SharedPtrRef()
stats = ConstructorStats.get(m.A)
s = SharedPtrRef()
stats = ConstructorStats.get(A)
assert stats.alive() == 2 assert stats.alive() == 2
ref = s.ref # init_holder_helper(holder_ptr=false, owned=false) ref = s.ref # init_holder_helper(holder_ptr=false, owned=false)
...@@ -176,10 +156,8 @@ def test_shared_ptr_and_references(): ...@@ -176,10 +156,8 @@ def test_shared_ptr_and_references():
def test_shared_ptr_from_this_and_references(): def test_shared_ptr_from_this_and_references():
from pybind11_tests.smart_ptr import SharedFromThisRef, B, SharedFromThisVirt s = m.SharedFromThisRef()
stats = ConstructorStats.get(m.B)
s = SharedFromThisRef()
stats = ConstructorStats.get(B)
assert stats.alive() == 2 assert stats.alive() == 2
ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false) ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
...@@ -212,37 +190,31 @@ def test_shared_ptr_from_this_and_references(): ...@@ -212,37 +190,31 @@ def test_shared_ptr_from_this_and_references():
del ref, bad_wp, copy, holder_ref, holder_copy, s del ref, bad_wp, copy, holder_ref, holder_copy, s
assert stats.alive() == 0 assert stats.alive() == 0
z = SharedFromThisVirt.get() z = m.SharedFromThisVirt.get()
y = SharedFromThisVirt.get() y = m.SharedFromThisVirt.get()
assert y is z assert y is z
def test_move_only_holder(): def test_move_only_holder():
from pybind11_tests.smart_ptr import TypeWithMoveOnlyHolder a = m.TypeWithMoveOnlyHolder.make()
stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder)
a = TypeWithMoveOnlyHolder.make()
stats = ConstructorStats.get(TypeWithMoveOnlyHolder)
assert stats.alive() == 1 assert stats.alive() == 1
del a del a
assert stats.alive() == 0 assert stats.alive() == 0
def test_smart_ptr_from_default(): def test_smart_ptr_from_default():
from pybind11_tests.smart_ptr import HeldByDefaultHolder instance = m.HeldByDefaultHolder()
instance = HeldByDefaultHolder()
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
HeldByDefaultHolder.load_shared_ptr(instance) m.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(): def test_shared_ptr_gc():
"""#187: issue involving std::shared_ptr<> return value policy & garbage collection""" """#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
from pybind11_tests.smart_ptr import ElementList, ElementA el = m.ElementList()
el = ElementList()
for i in range(10): for i in range(10):
el.add(ElementA(i)) el.add(m.ElementA(i))
pytest.gc_collect() pytest.gc_collect()
for i, v in enumerate(el.get()): for i, v in enumerate(el.get()):
assert i == v.value() assert i == v.value()
...@@ -10,17 +10,6 @@ ...@@ -10,17 +10,6 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <pybind11/stl.h> #include <pybind11/stl.h>
// Class that can be move- and copy-constructed, but not assigned
struct NoAssign {
int value;
explicit NoAssign(int value = 0) : value(value) { }
NoAssign(const NoAssign &) = default;
NoAssign(NoAssign &&) = default;
NoAssign &operator=(const NoAssign &) = delete;
NoAssign &operator=(NoAssign &&) = delete;
};
/// Issue #528: templated constructor /// Issue #528: templated constructor
struct TplCtorClass { struct TplCtorClass {
...@@ -103,24 +92,34 @@ TEST_SUBMODULE(stl, m) { ...@@ -103,24 +92,34 @@ TEST_SUBMODULE(stl, m) {
return v; return v;
}); });
// test_move_out_container
struct MoveOutContainer { struct MoveOutContainer {
struct Value { int value; }; struct Value { int value; };
std::list<Value> move_list() const { return {{0}, {1}, {2}}; } std::list<Value> move_list() const { return {{0}, {1}, {2}}; }
}; };
py::class_<MoveOutContainer::Value>(m, "MoveOutContainerValue") py::class_<MoveOutContainer::Value>(m, "MoveOutContainerValue")
.def_readonly("value", &MoveOutContainer::Value::value); .def_readonly("value", &MoveOutContainer::Value::value);
py::class_<MoveOutContainer>(m, "MoveOutContainer") py::class_<MoveOutContainer>(m, "MoveOutContainer")
.def(py::init<>()) .def(py::init<>())
.def_property_readonly("move_list", &MoveOutContainer::move_list); .def_property_readonly("move_list", &MoveOutContainer::move_list);
// Class that can be move- and copy-constructed, but not assigned
struct NoAssign {
int value;
explicit NoAssign(int value = 0) : value(value) { }
NoAssign(const NoAssign &) = default;
NoAssign(NoAssign &&) = default;
NoAssign &operator=(const NoAssign &) = delete;
NoAssign &operator=(NoAssign &&) = delete;
};
py::class_<NoAssign>(m, "NoAssign", "Class with no C++ assignment operators") py::class_<NoAssign>(m, "NoAssign", "Class with no C++ assignment operators")
.def(py::init<>()) .def(py::init<>())
.def(py::init<int>()); .def(py::init<int>());
#ifdef PYBIND11_HAS_OPTIONAL #ifdef PYBIND11_HAS_OPTIONAL
// test_optional
m.attr("has_optional") = true; m.attr("has_optional") = true;
using opt_int = std::optional<int>; using opt_int = std::optional<int>;
...@@ -143,6 +142,7 @@ TEST_SUBMODULE(stl, m) { ...@@ -143,6 +142,7 @@ TEST_SUBMODULE(stl, m) {
#endif #endif
#ifdef PYBIND11_HAS_EXP_OPTIONAL #ifdef PYBIND11_HAS_EXP_OPTIONAL
// test_exp_optional
m.attr("has_exp_optional") = true; m.attr("has_exp_optional") = true;
using exp_opt_int = std::experimental::optional<int>; using exp_opt_int = std::experimental::optional<int>;
...@@ -169,21 +169,21 @@ TEST_SUBMODULE(stl, m) { ...@@ -169,21 +169,21 @@ TEST_SUBMODULE(stl, m) {
const char *operator()(std::nullptr_t) { return "std::nullptr_t"; } const char *operator()(std::nullptr_t) { return "std::nullptr_t"; }
}; };
// test_variant
m.def("load_variant", [](std::variant<int, std::string, double, std::nullptr_t> v) { m.def("load_variant", [](std::variant<int, std::string, double, std::nullptr_t> v) {
return std::visit(visitor(), v); return std::visit(visitor(), v);
}); });
m.def("load_variant_2pass", [](std::variant<double, int> v) { m.def("load_variant_2pass", [](std::variant<double, int> v) {
return std::visit(visitor(), v); return std::visit(visitor(), v);
}); });
m.def("cast_variant", []() { m.def("cast_variant", []() {
using V = std::variant<int, std::string>; using V = std::variant<int, std::string>;
return py::make_tuple(V(5), V("Hello")); return py::make_tuple(V(5), V("Hello"));
}); });
#endif #endif
/// #528: templated constructor // #528: templated constructor
// (no python tests: the test here is that this compiles)
m.def("tpl_ctor_vector", [](std::vector<TplCtorClass> &) {}); m.def("tpl_ctor_vector", [](std::vector<TplCtorClass> &) {});
m.def("tpl_ctor_map", [](std::unordered_map<TplCtorClass, TplCtorClass> &) {}); m.def("tpl_ctor_map", [](std::unordered_map<TplCtorClass, TplCtorClass> &) {});
m.def("tpl_ctor_set", [](std::unordered_set<TplCtorClass> &) {}); m.def("tpl_ctor_set", [](std::unordered_set<TplCtorClass> &) {});
......
...@@ -54,70 +54,58 @@ template <class Map> Map *times_ten(int n) { ...@@ -54,70 +54,58 @@ template <class Map> Map *times_ten(int n) {
return m; return m;
} }
struct VStruct { TEST_SUBMODULE(stl_binders, m) {
bool w;
uint32_t x;
double y;
bool z;
};
struct VUndeclStruct { //dtype not declared for this version
bool w;
uint32_t x;
double y;
bool z;
};
test_initializer stl_binder_vector([](py::module &m) { // test_vector_int
py::class_<El>(m, "El")
.def(py::init<int>());
py::bind_vector<std::vector<unsigned char>>(m, "VectorUChar", py::buffer_protocol());
py::bind_vector<std::vector<unsigned int>>(m, "VectorInt", py::buffer_protocol()); py::bind_vector<std::vector<unsigned int>>(m, "VectorInt", py::buffer_protocol());
// test_vector_bool
py::bind_vector<std::vector<bool>>(m, "VectorBool"); py::bind_vector<std::vector<bool>>(m, "VectorBool");
// test_vector_custom
py::class_<El>(m, "El")
.def(py::init<int>());
py::bind_vector<std::vector<El>>(m, "VectorEl"); py::bind_vector<std::vector<El>>(m, "VectorEl");
py::bind_vector<std::vector<std::vector<El>>>(m, "VectorVectorEl"); py::bind_vector<std::vector<std::vector<El>>>(m, "VectorVectorEl");
m.def("create_undeclstruct", [m] () mutable { // test_map_string_double
py::bind_vector<std::vector<VUndeclStruct>>(m, "VectorUndeclStruct", py::buffer_protocol());
});
try {
py::module::import("numpy");
} catch (...) {
return;
}
PYBIND11_NUMPY_DTYPE(VStruct, w, x, y, z);
py::class_<VStruct>(m, "VStruct").def_readwrite("x", &VStruct::x);
py::bind_vector<std::vector<VStruct>>(m, "VectorStruct", py::buffer_protocol());
m.def("get_vectorstruct", [] {return std::vector<VStruct> {{0, 5, 3.0, 1}, {1, 30, -1e4, 0}};});
});
test_initializer stl_binder_map([](py::module &m) {
py::bind_map<std::map<std::string, double>>(m, "MapStringDouble"); py::bind_map<std::map<std::string, double>>(m, "MapStringDouble");
py::bind_map<std::unordered_map<std::string, double>>(m, "UnorderedMapStringDouble"); py::bind_map<std::unordered_map<std::string, double>>(m, "UnorderedMapStringDouble");
// test_map_string_double_const
py::bind_map<std::map<std::string, double const>>(m, "MapStringDoubleConst"); py::bind_map<std::map<std::string, double const>>(m, "MapStringDoubleConst");
py::bind_map<std::unordered_map<std::string, double const>>(m, "UnorderedMapStringDoubleConst"); py::bind_map<std::unordered_map<std::string, double const>>(m, "UnorderedMapStringDoubleConst");
});
test_initializer stl_binder_noncopyable([](py::module &m) {
py::class_<E_nc>(m, "ENC") py::class_<E_nc>(m, "ENC")
.def(py::init<int>()) .def(py::init<int>())
.def_readwrite("value", &E_nc::value); .def_readwrite("value", &E_nc::value);
// test_noncopyable_containers
py::bind_vector<std::vector<E_nc>>(m, "VectorENC"); py::bind_vector<std::vector<E_nc>>(m, "VectorENC");
m.def("get_vnc", &one_to_n<std::vector<E_nc>>, py::return_value_policy::reference); m.def("get_vnc", &one_to_n<std::vector<E_nc>>, py::return_value_policy::reference);
py::bind_vector<std::deque<E_nc>>(m, "DequeENC"); py::bind_vector<std::deque<E_nc>>(m, "DequeENC");
m.def("get_dnc", &one_to_n<std::deque<E_nc>>, py::return_value_policy::reference); m.def("get_dnc", &one_to_n<std::deque<E_nc>>, py::return_value_policy::reference);
py::bind_map<std::map<int, E_nc>>(m, "MapENC"); py::bind_map<std::map<int, E_nc>>(m, "MapENC");
m.def("get_mnc", &times_ten<std::map<int, E_nc>>, py::return_value_policy::reference); m.def("get_mnc", &times_ten<std::map<int, E_nc>>, py::return_value_policy::reference);
py::bind_map<std::unordered_map<int, E_nc>>(m, "UmapENC"); py::bind_map<std::unordered_map<int, E_nc>>(m, "UmapENC");
m.def("get_umnc", &times_ten<std::unordered_map<int, E_nc>>, py::return_value_policy::reference); m.def("get_umnc", &times_ten<std::unordered_map<int, E_nc>>, py::return_value_policy::reference);
});
// test_vector_buffer
py::bind_vector<std::vector<unsigned char>>(m, "VectorUChar", py::buffer_protocol());
// no dtype declared for this version:
struct VUndeclStruct { bool w; uint32_t x; double y; bool z; };
m.def("create_undeclstruct", [m] () mutable {
py::bind_vector<std::vector<VUndeclStruct>>(m, "VectorUndeclStruct", py::buffer_protocol());
});
// The rest depends on numpy:
try { py::module::import("numpy"); }
catch (...) { return; }
// test_vector_buffer_numpy
struct VStruct { bool w; uint32_t x; double y; bool z; };
PYBIND11_NUMPY_DTYPE(VStruct, w, x, y, z);
py::class_<VStruct>(m, "VStruct").def_readwrite("x", &VStruct::x);
py::bind_vector<std::vector<VStruct>>(m, "VectorStruct", py::buffer_protocol());
m.def("get_vectorstruct", [] {return std::vector<VStruct> {{0, 5, 3.0, 1}, {1, 30, -1e4, 0}};});
}
import pytest import pytest
import sys import sys
from pybind11_tests import stl_binders as m
with pytest.suppress(ImportError): with pytest.suppress(ImportError):
import numpy as np import numpy as np
def test_vector_int(): def test_vector_int():
from pybind11_tests import VectorInt v_int = m.VectorInt([0, 0])
v_int = VectorInt([0, 0])
assert len(v_int) == 2 assert len(v_int) == 2
assert bool(v_int) is True assert bool(v_int) is True
v_int2 = VectorInt([0, 0]) v_int2 = m.VectorInt([0, 0])
assert v_int == v_int2 assert v_int == v_int2
v_int2[1] = 1 v_int2[1] = 1
assert v_int != v_int2 assert v_int != v_int2
...@@ -28,85 +27,66 @@ def test_vector_int(): ...@@ -28,85 +27,66 @@ def test_vector_int():
v_int.append(99) v_int.append(99)
v_int2[2:-2] = v_int v_int2[2:-2] = v_int
assert v_int2 == VectorInt([3, 2, 0, 0, 99, 2, 3]) assert v_int2 == m.VectorInt([3, 2, 0, 0, 99, 2, 3])
del v_int2[1:3] del v_int2[1:3]
assert v_int2 == VectorInt([3, 0, 99, 2, 3]) assert v_int2 == m.VectorInt([3, 0, 99, 2, 3])
del v_int2[0] del v_int2[0]
assert v_int2 == VectorInt([0, 99, 2, 3]) assert v_int2 == m.VectorInt([0, 99, 2, 3])
# As of pypy 5.7.1, running this and the next test seems to trigger a segfault
# related to the PyPy's buffer protocol. # related to the PyPy's buffer protocol.
@pytest.unsupported_on_pypy @pytest.unsupported_on_pypy
def test_vector_buffer(): def test_vector_buffer():
from pybind11_tests import VectorUChar, create_undeclstruct
b = bytearray([1, 2, 3, 4]) b = bytearray([1, 2, 3, 4])
v = VectorUChar(b) v = m.VectorUChar(b)
assert v[1] == 2 assert v[1] == 2
v[2] = 5 v[2] = 5
m = memoryview(v) # We expose the buffer interface mv = memoryview(v) # We expose the buffer interface
if sys.version_info.major > 2: if sys.version_info.major > 2:
assert m[2] == 5 assert mv[2] == 5
m[2] = 6 mv[2] = 6
else: else:
assert m[2] == '\x05' assert mv[2] == '\x05'
m[2] = '\x06' mv[2] = '\x06'
assert v[2] == 6 assert v[2] == 6
with pytest.raises(RuntimeError): with pytest.raises(RuntimeError) as excinfo:
create_undeclstruct() # Undeclared struct contents, no buffer interface m.create_undeclstruct() # Undeclared struct contents, no buffer interface
assert "NumPy type info missing for " in str(excinfo.value)
@pytest.unsupported_on_pypy @pytest.unsupported_on_pypy
@pytest.requires_numpy @pytest.requires_numpy
def test_vector_buffer_numpy(): def test_vector_buffer_numpy():
from pybind11_tests import VectorInt, VectorStruct, get_vectorstruct
a = np.array([1, 2, 3, 4], dtype=np.int32) a = np.array([1, 2, 3, 4], dtype=np.int32)
with pytest.raises(TypeError): with pytest.raises(TypeError):
VectorInt(a) m.VectorInt(a)
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], dtype=np.uintc) a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], dtype=np.uintc)
v = VectorInt(a[0, :]) v = m.VectorInt(a[0, :])
assert len(v) == 4 assert len(v) == 4
assert v[2] == 3 assert v[2] == 3
m = np.asarray(v) ma = np.asarray(v)
m[2] = 5 ma[2] = 5
assert v[2] == 5 assert v[2] == 5
v = VectorInt(a[:, 1]) v = m.VectorInt(a[:, 1])
assert len(v) == 3 assert len(v) == 3
assert v[2] == 10 assert v[2] == 10
v = get_vectorstruct() v = m.get_vectorstruct()
assert v[0].x == 5 assert v[0].x == 5
m = np.asarray(v) ma = np.asarray(v)
m[1]['x'] = 99 ma[1]['x'] = 99
assert v[1].x == 99 assert v[1].x == 99
v = VectorStruct(np.zeros(3, dtype=np.dtype([('w', 'bool'), ('x', 'I'), v = m.VectorStruct(np.zeros(3, dtype=np.dtype([('w', 'bool'), ('x', 'I'),
('y', 'float64'), ('z', 'bool')], align=True))) ('y', 'float64'), ('z', 'bool')], align=True)))
assert len(v) == 3 assert len(v) == 3
def test_vector_custom():
from pybind11_tests import El, VectorEl, VectorVectorEl
v_a = VectorEl()
v_a.append(El(1))
v_a.append(El(2))
assert str(v_a) == "VectorEl[El{1}, El{2}]"
vv_a = VectorVectorEl()
vv_a.append(v_a)
vv_b = vv_a[0]
assert str(vv_b) == "VectorEl[El{1}, El{2}]"
def test_vector_bool(): def test_vector_bool():
from pybind11_tests import VectorBool vv_c = m.VectorBool()
vv_c = VectorBool()
for i in range(10): for i in range(10):
vv_c.append(i % 2 == 0) vv_c.append(i % 2 == 0)
for i in range(10): for i in range(10):
...@@ -114,18 +94,28 @@ def test_vector_bool(): ...@@ -114,18 +94,28 @@ def test_vector_bool():
assert str(vv_c) == "VectorBool[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]" assert str(vv_c) == "VectorBool[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]"
def test_map_string_double(): def test_vector_custom():
from pybind11_tests import MapStringDouble, UnorderedMapStringDouble v_a = m.VectorEl()
v_a.append(m.El(1))
v_a.append(m.El(2))
assert str(v_a) == "VectorEl[El{1}, El{2}]"
m = MapStringDouble() vv_a = m.VectorVectorEl()
m['a'] = 1 vv_a.append(v_a)
m['b'] = 2.5 vv_b = vv_a[0]
assert str(vv_b) == "VectorEl[El{1}, El{2}]"
assert list(m) == ['a', 'b']
assert list(m.items()) == [('a', 1), ('b', 2.5)]
assert str(m) == "MapStringDouble{a: 1, b: 2.5}"
um = UnorderedMapStringDouble() def test_map_string_double():
mm = m.MapStringDouble()
mm['a'] = 1
mm['b'] = 2.5
assert list(mm) == ['a', 'b']
assert list(mm.items()) == [('a', 1), ('b', 2.5)]
assert str(mm) == "MapStringDouble{a: 1, b: 2.5}"
um = m.UnorderedMapStringDouble()
um['ua'] = 1.1 um['ua'] = 1.1
um['ub'] = 2.6 um['ub'] = 2.6
...@@ -135,35 +125,29 @@ def test_map_string_double(): ...@@ -135,35 +125,29 @@ def test_map_string_double():
def test_map_string_double_const(): def test_map_string_double_const():
from pybind11_tests import MapStringDoubleConst, UnorderedMapStringDoubleConst mc = m.MapStringDoubleConst()
mc = MapStringDoubleConst()
mc['a'] = 10 mc['a'] = 10
mc['b'] = 20.5 mc['b'] = 20.5
assert str(mc) == "MapStringDoubleConst{a: 10, b: 20.5}" assert str(mc) == "MapStringDoubleConst{a: 10, b: 20.5}"
umc = UnorderedMapStringDoubleConst() umc = m.UnorderedMapStringDoubleConst()
umc['a'] = 11 umc['a'] = 11
umc['b'] = 21.5 umc['b'] = 21.5
str(umc) str(umc)
def test_noncopyable_vector(): def test_noncopyable_containers():
from pybind11_tests import get_vnc # std::vector
vnc = m.get_vnc(5)
vnc = get_vnc(5)
for i in range(0, 5): for i in range(0, 5):
assert vnc[i].value == i + 1 assert vnc[i].value == i + 1
for i, j in enumerate(vnc, start=1): for i, j in enumerate(vnc, start=1):
assert j.value == i assert j.value == i
# std::deque
def test_noncopyable_deque(): dnc = m.get_dnc(5)
from pybind11_tests import get_dnc
dnc = get_dnc(5)
for i in range(0, 5): for i in range(0, 5):
assert dnc[i].value == i + 1 assert dnc[i].value == i + 1
...@@ -172,11 +156,8 @@ def test_noncopyable_deque(): ...@@ -172,11 +156,8 @@ def test_noncopyable_deque():
assert(j.value == i) assert(j.value == i)
i += 1 i += 1
# std::map
def test_noncopyable_map(): mnc = m.get_mnc(5)
from pybind11_tests import get_mnc
mnc = get_mnc(5)
for i in range(1, 6): for i in range(1, 6):
assert mnc[i].value == 10 * i assert mnc[i].value == 10 * i
...@@ -187,11 +168,8 @@ def test_noncopyable_map(): ...@@ -187,11 +168,8 @@ def test_noncopyable_map():
assert vsum == 150 assert vsum == 150
# std::unordered_map
def test_noncopyable_unordered_map(): mnc = m.get_umnc(5)
from pybind11_tests import get_umnc
mnc = get_umnc(5)
for i in range(1, 6): for i in range(1, 6):
assert mnc[i].value == 10 * i assert mnc[i].value == 10 * i
......
...@@ -149,7 +149,92 @@ def test_alias_delay_initialization2(capture): ...@@ -149,7 +149,92 @@ def test_alias_delay_initialization2(capture):
""" """
def test_inheriting_repeat(): # PyPy: Reference count > 1 causes call with noncopyable instance
# to fail in ncv1.print_nc()
@pytest.unsupported_on_pypy
@pytest.mark.skipif(not hasattr(m, "NCVirt"), reason="NCVirt test broken on ICPC")
def test_move_support():
class NCVirtExt(m.NCVirt):
def get_noncopyable(self, a, b):
# Constructs and returns a new instance:
nc = m.NonCopyable(a * a, b * b)
return nc
def get_movable(self, a, b):
# Return a referenced copy
self.movable = m.Movable(a, b)
return self.movable
class NCVirtExt2(m.NCVirt):
def get_noncopyable(self, a, b):
# Keep a reference: this is going to throw an exception
self.nc = m.NonCopyable(a, b)
return self.nc
def get_movable(self, a, b):
# Return a new instance without storing it
return m.Movable(a, b)
ncv1 = NCVirtExt()
assert ncv1.print_nc(2, 3) == "36"
assert ncv1.print_movable(4, 5) == "9"
ncv2 = NCVirtExt2()
assert ncv2.print_movable(7, 7) == "14"
# Don't check the exception message here because it differs under debug/non-debug mode
with pytest.raises(RuntimeError):
ncv2.print_nc(9, 9)
nc_stats = ConstructorStats.get(m.NonCopyable)
mv_stats = ConstructorStats.get(m.Movable)
assert nc_stats.alive() == 1
assert mv_stats.alive() == 1
del ncv1, ncv2
assert nc_stats.alive() == 0
assert mv_stats.alive() == 0
assert nc_stats.values() == ['4', '9', '9', '9']
assert mv_stats.values() == ['4', '5', '7', '7']
assert nc_stats.copy_constructions == 0
assert mv_stats.copy_constructions == 1
assert nc_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"""
class PyClass1(m.DispatchIssue):
def dispatch(self):
return "Yay.."
class PyClass2(m.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 m.dispatch_issue_go(p)
b = PyClass2()
assert m.dispatch_issue_go(b) == "Yay.."
def test_override_ref():
"""#392/397: overridding reference-returning functions"""
o = m.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_inherited_virtuals():
class AR(m.A_Repeat): class AR(m.A_Repeat):
def unlucky_number(self): def unlucky_number(self):
return 99 return 99
...@@ -276,88 +361,3 @@ def test_inheriting_repeat(): ...@@ -276,88 +361,3 @@ def test_inheriting_repeat():
assert obj.unlucky_number() == -7 assert obj.unlucky_number() == -7
assert obj.lucky_number() == -1.375 assert obj.lucky_number() == -1.375
assert obj.say_everything() == "BT -7" assert obj.say_everything() == "BT -7"
# PyPy: Reference count > 1 causes call with noncopyable instance
# to fail in ncv1.print_nc()
@pytest.unsupported_on_pypy
@pytest.mark.skipif(not hasattr(m, "NCVirt"), reason="NCVirt test broken on ICPC")
def test_move_support():
class NCVirtExt(m.NCVirt):
def get_noncopyable(self, a, b):
# Constructs and returns a new instance:
nc = m.NonCopyable(a * a, b * b)
return nc
def get_movable(self, a, b):
# Return a referenced copy
self.movable = m.Movable(a, b)
return self.movable
class NCVirtExt2(m.NCVirt):
def get_noncopyable(self, a, b):
# Keep a reference: this is going to throw an exception
self.nc = m.NonCopyable(a, b)
return self.nc
def get_movable(self, a, b):
# Return a new instance without storing it
return m.Movable(a, b)
ncv1 = NCVirtExt()
assert ncv1.print_nc(2, 3) == "36"
assert ncv1.print_movable(4, 5) == "9"
ncv2 = NCVirtExt2()
assert ncv2.print_movable(7, 7) == "14"
# Don't check the exception message here because it differs under debug/non-debug mode
with pytest.raises(RuntimeError):
ncv2.print_nc(9, 9)
nc_stats = ConstructorStats.get(m.NonCopyable)
mv_stats = ConstructorStats.get(m.Movable)
assert nc_stats.alive() == 1
assert mv_stats.alive() == 1
del ncv1, ncv2
assert nc_stats.alive() == 0
assert mv_stats.alive() == 0
assert nc_stats.values() == ['4', '9', '9', '9']
assert mv_stats.values() == ['4', '5', '7', '7']
assert nc_stats.copy_constructions == 0
assert mv_stats.copy_constructions == 1
assert nc_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"""
class PyClass1(m.DispatchIssue):
def dispatch(self):
return "Yay.."
class PyClass2(m.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 m.dispatch_issue_go(p)
b = PyClass2()
assert m.dispatch_issue_go(b) == "Yay.."
def test_override_ref():
"""#392/397: overridding reference-returning functions"""
o = m.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"
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