mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
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.
This commit is contained in:
parent
9866a0f994
commit
391c75447d
@ -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) {
|
|||||||
.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:
|
|||||||
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 @@
|
|||||||
#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 {
|
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
|
||||||
return m_data[(size_t) (i*m_cols + j)];
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
float &operator()(ssize_t i, ssize_t j) {
|
Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
|
||||||
return m_data[(size_t) (i*m_cols + j)];
|
print_move_created(this);
|
||||||
}
|
s.m_rows = 0;
|
||||||
|
s.m_cols = 0;
|
||||||
|
s.m_data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
float *data() { return m_data; }
|
~Matrix() {
|
||||||
|
print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
|
delete[] m_data;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t rows() const { return m_rows; }
|
Matrix &operator=(const Matrix &s) {
|
||||||
ssize_t cols() const { return m_cols; }
|
print_copy_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
private:
|
delete[] m_data;
|
||||||
ssize_t m_rows;
|
m_rows = s.m_rows;
|
||||||
ssize_t m_cols;
|
m_cols = s.m_cols;
|
||||||
float *m_data;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
class SquareMatrix : public Matrix {
|
Matrix &operator=(Matrix &&s) {
|
||||||
public:
|
print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
SquareMatrix(ssize_t n) : Matrix(n, n) { }
|
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 PTMFBuffer {
|
float operator()(ssize_t i, ssize_t j) const {
|
||||||
int32_t value = 0;
|
return m_data[(size_t) (i*m_cols + j)];
|
||||||
|
}
|
||||||
|
|
||||||
py::buffer_info get_buffer_info() {
|
float &operator()(ssize_t i, ssize_t j) {
|
||||||
return py::buffer_info(&value, sizeof(value),
|
return m_data[(size_t) (i*m_cols + j)];
|
||||||
py::format_descriptor<int32_t>::format(), 1);
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ConstPTMFBuffer {
|
float *data() { return m_data; }
|
||||||
std::unique_ptr<int32_t> value;
|
|
||||||
|
|
||||||
public:
|
ssize_t rows() const { return m_rows; }
|
||||||
int32_t get_value() const { return *value; }
|
ssize_t cols() const { return m_cols; }
|
||||||
void set_value(int32_t v) { *value = v; }
|
private:
|
||||||
|
ssize_t m_rows;
|
||||||
py::buffer_info get_buffer_info() const {
|
ssize_t m_cols;
|
||||||
return py::buffer_info(value.get(), sizeof(*value),
|
float *m_data;
|
||||||
py::format_descriptor<int32_t>::format(), 1);
|
};
|
||||||
}
|
py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
|
||||||
|
.def(py::init<ssize_t, ssize_t>())
|
||||||
ConstPTMFBuffer() : value(new int32_t{0}) { };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DerivedPTMFBuffer : public PTMFBuffer { };
|
|
||||||
|
|
||||||
test_initializer buffers([](py::module &m) {
|
|
||||||
py::class_<Matrix> mtx(m, "Matrix", py::buffer_protocol());
|
|
||||||
|
|
||||||
mtx.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) {
|
|||||||
})
|
})
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
// 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())
|
|
||||||
.def(py::init<>())
|
|
||||||
.def_readwrite("value", &PTMFBuffer::value)
|
|
||||||
.def_buffer(&PTMFBuffer::get_buffer_info);
|
|
||||||
|
|
||||||
py::class_<ConstPTMFBuffer>(m, "ConstPTMFBuffer", py::buffer_protocol())
|
|
||||||
.def(py::init<>())
|
|
||||||
.def_property("value", &ConstPTMFBuffer::get_value, &ConstPTMFBuffer::set_value)
|
|
||||||
.def_buffer(&ConstPTMFBuffer::get_buffer_info);
|
|
||||||
|
|
||||||
|
// test_pointer_to_member_fn
|
||||||
// Tests that passing a pointer to member to the base class works in
|
// Tests that passing a pointer to member to the base class works in
|
||||||
// the derived class.
|
// the derived class.
|
||||||
py::class_<DerivedPTMFBuffer>(m, "DerivedPTMFBuffer", py::buffer_protocol())
|
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", (int32_t DerivedPTMFBuffer::*) &DerivedPTMFBuffer::value)
|
.def_readwrite("value", &Buffer::value)
|
||||||
.def_buffer(&DerivedPTMFBuffer::get_buffer_info);
|
.def_buffer(&Buffer::get_buffer_info);
|
||||||
});
|
|
||||||
|
|
||||||
|
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_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value)
|
||||||
|
.def_buffer(&ConstBuffer::get_buffer_info);
|
||||||
|
|
||||||
|
struct DerivedBuffer : public Buffer { };
|
||||||
|
py::class_<DerivedBuffer>(m, "DerivedBuffer", py::buffer_protocol())
|
||||||
|
.def(py::init<>())
|
||||||
|
.def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value)
|
||||||
|
.def_buffer(&DerivedBuffer::get_buffer_info);
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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):
|
|||||||
|
|
||||||
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():
|
|||||||
# 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():
|
|||||||
@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 @@
|
|||||||
|
|
||||||
#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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
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) {
|
|||||||
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
|
||||||
});
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
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):
|
|||||||
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):
|
|||||||
|
|
||||||
|
|
||||||
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):
|
|||||||
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):
|
|||||||
# 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):
|
|||||||
|
|
||||||
|
|
||||||
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):
|
|||||||
|
|
||||||
|
|
||||||
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):
|
|||||||
|
|
||||||
|
|
||||||
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):
|
|||||||
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):
|
|||||||
|
|
||||||
|
|
||||||
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 m.multiple_guards_correct_order() == "guarded & guarded"
|
||||||
assert call_policies.guarded_call() == "guarded"
|
assert m.multiple_guards_wrong_order() == "unguarded & guarded"
|
||||||
|
|
||||||
assert call_policies.multiple_guards_correct_order() == "guarded & guarded"
|
if hasattr(m, "with_gil"):
|
||||||
assert call_policies.multiple_guards_wrong_order() == "unguarded & guarded"
|
assert m.with_gil() == "GIL held"
|
||||||
|
assert m.without_gil() == "GIL released"
|
||||||
if hasattr(call_policies, "with_gil"):
|
|
||||||
assert call_policies.with_gil() == "GIL held"
|
|
||||||
assert call_policies.without_gil() == "GIL released"
|
|
||||||
|
@ -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) {
|
|||||||
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) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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("test_dummy_function", [](const std::function<int(int)> &f) -> std::string {
|
||||||
|
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!";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
m.def("func_accepting_func_accepting_base",
|
class AbstractBase { public: virtual unsigned int func() = 0; };
|
||||||
func_accepting_func_accepting_base);
|
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; });
|
||||||
});
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
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():
|
|||||||
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():
|
|||||||
|
|
||||||
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 @@
|
|||||||
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
|
// test_chrono_duration_roundtrip
|
||||||
std::chrono::system_clock::duration test_chrono3(std::chrono::system_clock::duration d) {
|
// Round trip the passed in duration
|
||||||
return d;
|
m.def("test_chrono3", [](std::chrono::system_clock::duration d) { return d; });
|
||||||
}
|
|
||||||
|
|
||||||
// Difference between two passed in time_points
|
// test_chrono_duration_subtraction_equivalence
|
||||||
std::chrono::system_clock::duration test_chrono4(std::chrono::system_clock::time_point a, std::chrono::system_clock::time_point b) {
|
// Difference between two passed in time_points
|
||||||
return a - b;
|
m.def("test_chrono4", [](system_time a, system_time b) { return a - b; });
|
||||||
}
|
|
||||||
|
|
||||||
// Return the current time off the steady_clock
|
// test_chrono_steady_clock
|
||||||
std::chrono::steady_clock::time_point test_chrono5() {
|
// Return the current time off the steady_clock
|
||||||
return std::chrono::steady_clock::now();
|
m.def("test_chrono5", []() { return std::chrono::steady_clock::now(); });
|
||||||
}
|
|
||||||
|
|
||||||
// Round trip a steady clock timepoint
|
// test_chrono_steady_clock_roundtrip
|
||||||
std::chrono::steady_clock::time_point test_chrono6(std::chrono::steady_clock::time_point t) {
|
// Round trip a steady clock timepoint
|
||||||
return t;
|
m.def("test_chrono6", [](steady_time t) { return t; });
|
||||||
}
|
|
||||||
|
|
||||||
// Roundtrip a duration in microseconds from a float argument
|
// test_floating_point_duration
|
||||||
std::chrono::microseconds test_chrono7(std::chrono::microseconds t) {
|
// Roundtrip a duration in microseconds from a float argument
|
||||||
return t;
|
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; });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Float durations (issue #719)
|
|
||||||
std::chrono::duration<double> 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);
|
|
||||||
});
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
|
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():
|
|||||||
|
|
||||||
|
|
||||||
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():
|
|||||||
|
|
||||||
|
|
||||||
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():
|
|||||||
# 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():
|
|||||||
|
|
||||||
|
|
||||||
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():
|
|||||||
|
|
||||||
|
|
||||||
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():
|
|||||||
|
|
||||||
|
|
||||||
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):
|
|||||||
|
|
||||||
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) {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
|||||||
.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) {
|
|||||||
.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);
|
||||||
});
|
}
|
||||||
|
@ -1,33 +1,29 @@
|
|||||||
|
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 m.test_function(m.MyEnum.EFirstEntry) == "test_function(enum=1)"
|
||||||
|
assert m.test_function(m.MyEnum.ESecondEntry) == "test_function(enum=2)"
|
||||||
|
|
||||||
assert test_function() == "test_function()"
|
assert m.test_function() == "test_function()"
|
||||||
assert test_function(7) == "test_function(7)"
|
assert m.test_function("abcd") == "test_function(char *)"
|
||||||
assert test_function(MyEnum.EFirstEntry) == "test_function(enum=1)"
|
assert m.test_function(1, 1.0) == "test_function(int, float)"
|
||||||
assert test_function(MyEnum.ESecondEntry) == "test_function(enum=2)"
|
assert m.test_function(1, 1.0) == "test_function(int, float)"
|
||||||
|
assert m.test_function(2.0, 2) == "test_function(float, int)"
|
||||||
assert test_function(1, 1.0) == "test_function(int, float)"
|
|
||||||
assert 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():
|
|||||||
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:
|
|||||||
|
|
||||||
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:
|
|||||||
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) {
|
|||||||
|
|
||||||
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) {
|
|||||||
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) {
|
|||||||
#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) {
|
|||||||
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) {
|
|||||||
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);
|
||||||
});
|
}
|
||||||
|
@ -1,32 +1,29 @@
|
|||||||
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():
|
|||||||
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():
|
|||||||
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():
|
|||||||
|
|
||||||
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():
|
|||||||
|
|
||||||
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 @@
|
|||||||
|
|
||||||
#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) {
|
|||||||
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")
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
@ -1,42 +1,38 @@
|
|||||||
|
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 {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
// 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) {
|
|||||||
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) {
|
|||||||
.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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
py::module::import("numpy").attr("ones")(10);
|
py::module::import("numpy").attr("ones")(10);
|
||||||
return v[0](5);
|
return v[0](5);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
from pybind11_tests import ConstructorStats
|
||||||
|
|
||||||
pytestmark = pytest.requires_eigen_and_numpy
|
pytestmark = pytest.requires_eigen_and_numpy
|
||||||
|
|
||||||
with pytest.suppress(ImportError):
|
with pytest.suppress(ImportError):
|
||||||
|
from pybind11_tests import eigen as m
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
ref = np.array([[ 0., 3, 0, 0, 0, 11],
|
ref = np.array([[ 0., 3, 0, 0, 0, 11],
|
||||||
@ -21,51 +23,44 @@ def assert_sparse_equal_ref(sparse_mat):
|
|||||||
|
|
||||||
|
|
||||||
def test_fixed():
|
def test_fixed():
|
||||||
from pybind11_tests import fixed_r, fixed_c, fixed_copy_r, fixed_copy_c
|
assert_equal_ref(m.fixed_c())
|
||||||
|
assert_equal_ref(m.fixed_r())
|
||||||
assert_equal_ref(fixed_c())
|
assert_equal_ref(m.fixed_copy_r(m.fixed_r()))
|
||||||
assert_equal_ref(fixed_r())
|
assert_equal_ref(m.fixed_copy_c(m.fixed_c()))
|
||||||
assert_equal_ref(fixed_copy_r(fixed_r()))
|
assert_equal_ref(m.fixed_copy_r(m.fixed_c()))
|
||||||
assert_equal_ref(fixed_copy_c(fixed_c()))
|
assert_equal_ref(m.fixed_copy_c(m.fixed_r()))
|
||||||
assert_equal_ref(fixed_copy_r(fixed_c()))
|
|
||||||
assert_equal_ref(fixed_copy_c(fixed_r()))
|
|
||||||
|
|
||||||
|
|
||||||
def test_dense():
|
def test_dense():
|
||||||
from pybind11_tests import dense_r, dense_c, dense_copy_r, dense_copy_c
|
assert_equal_ref(m.dense_r())
|
||||||
|
assert_equal_ref(m.dense_c())
|
||||||
assert_equal_ref(dense_r())
|
assert_equal_ref(m.dense_copy_r(m.dense_r()))
|
||||||
assert_equal_ref(dense_c())
|
assert_equal_ref(m.dense_copy_c(m.dense_c()))
|
||||||
assert_equal_ref(dense_copy_r(dense_r()))
|
assert_equal_ref(m.dense_copy_r(m.dense_c()))
|
||||||
assert_equal_ref(dense_copy_c(dense_c()))
|
assert_equal_ref(m.dense_copy_c(m.dense_r()))
|
||||||
assert_equal_ref(dense_copy_r(dense_c()))
|
|
||||||
assert_equal_ref(dense_copy_c(dense_r()))
|
|
||||||
|
|
||||||
|
|
||||||
def test_partially_fixed():
|
def test_partially_fixed():
|
||||||
from pybind11_tests import (partial_copy_four_rm_r, partial_copy_four_rm_c,
|
|
||||||
partial_copy_four_cm_r, partial_copy_four_cm_c)
|
|
||||||
|
|
||||||
ref2 = np.array([[0., 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]])
|
ref2 = np.array([[0., 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]])
|
||||||
np.testing.assert_array_equal(partial_copy_four_rm_r(ref2), ref2)
|
np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2), ref2)
|
||||||
np.testing.assert_array_equal(partial_copy_four_rm_c(ref2), ref2)
|
np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2), ref2)
|
||||||
np.testing.assert_array_equal(partial_copy_four_rm_r(ref2[:, 1]), ref2[:, [1]])
|
np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, 1]), ref2[:, [1]])
|
||||||
np.testing.assert_array_equal(partial_copy_four_rm_c(ref2[0, :]), ref2[[0], :])
|
np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2[0, :]), ref2[[0], :])
|
||||||
np.testing.assert_array_equal(partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)])
|
np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)])
|
||||||
np.testing.assert_array_equal(
|
np.testing.assert_array_equal(
|
||||||
partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :])
|
m.partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :])
|
||||||
|
|
||||||
np.testing.assert_array_equal(partial_copy_four_cm_r(ref2), ref2)
|
np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2), ref2)
|
||||||
np.testing.assert_array_equal(partial_copy_four_cm_c(ref2), ref2)
|
np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2), ref2)
|
||||||
np.testing.assert_array_equal(partial_copy_four_cm_r(ref2[:, 1]), ref2[:, [1]])
|
np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, 1]), ref2[:, [1]])
|
||||||
np.testing.assert_array_equal(partial_copy_four_cm_c(ref2[0, :]), ref2[[0], :])
|
np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2[0, :]), ref2[[0], :])
|
||||||
np.testing.assert_array_equal(partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)])
|
np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)])
|
||||||
np.testing.assert_array_equal(
|
np.testing.assert_array_equal(
|
||||||
partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :])
|
m.partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :])
|
||||||
|
|
||||||
# TypeError should be raise for a shape mismatch
|
# TypeError should be raise for a shape mismatch
|
||||||
functions = [partial_copy_four_rm_r, partial_copy_four_rm_c,
|
functions = [m.partial_copy_four_rm_r, m.partial_copy_four_rm_c,
|
||||||
partial_copy_four_cm_r, partial_copy_four_cm_c]
|
m.partial_copy_four_cm_r, m.partial_copy_four_cm_c]
|
||||||
matrix_with_wrong_shape = [[1, 2],
|
matrix_with_wrong_shape = [[1, 2],
|
||||||
[3, 4]]
|
[3, 4]]
|
||||||
for f in functions:
|
for f in functions:
|
||||||
@ -75,159 +70,143 @@ def test_partially_fixed():
|
|||||||
|
|
||||||
|
|
||||||
def test_mutator_descriptors():
|
def test_mutator_descriptors():
|
||||||
from pybind11_tests import fixed_mutator_r, fixed_mutator_c, fixed_mutator_a
|
|
||||||
zr = np.arange(30, dtype='float32').reshape(5, 6) # row-major
|
zr = np.arange(30, dtype='float32').reshape(5, 6) # row-major
|
||||||
zc = zr.reshape(6, 5).transpose() # column-major
|
zc = zr.reshape(6, 5).transpose() # column-major
|
||||||
|
|
||||||
fixed_mutator_r(zr)
|
m.fixed_mutator_r(zr)
|
||||||
fixed_mutator_c(zc)
|
m.fixed_mutator_c(zc)
|
||||||
fixed_mutator_a(zr)
|
m.fixed_mutator_a(zr)
|
||||||
fixed_mutator_a(zc)
|
m.fixed_mutator_a(zc)
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
fixed_mutator_r(zc)
|
m.fixed_mutator_r(zc)
|
||||||
assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.c_contiguous]) -> None'
|
assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.c_contiguous]) -> None'
|
||||||
in str(excinfo.value))
|
in str(excinfo.value))
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
fixed_mutator_c(zr)
|
m.fixed_mutator_c(zr)
|
||||||
assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.f_contiguous]) -> None'
|
assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.f_contiguous]) -> None'
|
||||||
in str(excinfo.value))
|
in str(excinfo.value))
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype='float32'))
|
m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype='float32'))
|
||||||
assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable]) -> None'
|
assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable]) -> None'
|
||||||
in str(excinfo.value))
|
in str(excinfo.value))
|
||||||
zr.flags.writeable = False
|
zr.flags.writeable = False
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
fixed_mutator_r(zr)
|
m.fixed_mutator_r(zr)
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
fixed_mutator_a(zr)
|
m.fixed_mutator_a(zr)
|
||||||
|
|
||||||
|
|
||||||
def test_cpp_casting():
|
def test_cpp_casting():
|
||||||
from pybind11_tests import (cpp_copy, cpp_ref_c, cpp_ref_r, cpp_ref_any,
|
assert m.cpp_copy(m.fixed_r()) == 22.
|
||||||
fixed_r, fixed_c, get_cm_ref, get_rm_ref, ReturnTester)
|
assert m.cpp_copy(m.fixed_c()) == 22.
|
||||||
assert cpp_copy(fixed_r()) == 22.
|
|
||||||
assert cpp_copy(fixed_c()) == 22.
|
|
||||||
z = np.array([[5., 6], [7, 8]])
|
z = np.array([[5., 6], [7, 8]])
|
||||||
assert cpp_copy(z) == 7.
|
assert m.cpp_copy(z) == 7.
|
||||||
assert cpp_copy(get_cm_ref()) == 21.
|
assert m.cpp_copy(m.get_cm_ref()) == 21.
|
||||||
assert cpp_copy(get_rm_ref()) == 21.
|
assert m.cpp_copy(m.get_rm_ref()) == 21.
|
||||||
assert cpp_ref_c(get_cm_ref()) == 21.
|
assert m.cpp_ref_c(m.get_cm_ref()) == 21.
|
||||||
assert cpp_ref_r(get_rm_ref()) == 21.
|
assert m.cpp_ref_r(m.get_rm_ref()) == 21.
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
# Can't reference fixed_c: it contains floats, cpp_ref_any wants doubles
|
# Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles
|
||||||
cpp_ref_any(fixed_c())
|
m.cpp_ref_any(m.fixed_c())
|
||||||
assert 'Unable to cast Python instance' in str(excinfo.value)
|
assert 'Unable to cast Python instance' in str(excinfo.value)
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
# Can't reference fixed_r: it contains floats, cpp_ref_any wants doubles
|
# Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles
|
||||||
cpp_ref_any(fixed_r())
|
m.cpp_ref_any(m.fixed_r())
|
||||||
assert 'Unable to cast Python instance' in str(excinfo.value)
|
assert 'Unable to cast Python instance' in str(excinfo.value)
|
||||||
assert cpp_ref_any(ReturnTester.create()) == 1.
|
assert m.cpp_ref_any(m.ReturnTester.create()) == 1.
|
||||||
|
|
||||||
assert cpp_ref_any(get_cm_ref()) == 21.
|
assert m.cpp_ref_any(m.get_cm_ref()) == 21.
|
||||||
assert cpp_ref_any(get_cm_ref()) == 21.
|
assert m.cpp_ref_any(m.get_cm_ref()) == 21.
|
||||||
|
|
||||||
|
|
||||||
def test_pass_readonly_array():
|
def test_pass_readonly_array():
|
||||||
from pybind11_tests import fixed_copy_r, fixed_r, fixed_r_const
|
|
||||||
z = np.full((5, 6), 42.0)
|
z = np.full((5, 6), 42.0)
|
||||||
z.flags.writeable = False
|
z.flags.writeable = False
|
||||||
np.testing.assert_array_equal(z, fixed_copy_r(z))
|
np.testing.assert_array_equal(z, m.fixed_copy_r(z))
|
||||||
np.testing.assert_array_equal(fixed_r_const(), fixed_r())
|
np.testing.assert_array_equal(m.fixed_r_const(), m.fixed_r())
|
||||||
assert not fixed_r_const().flags.writeable
|
assert not m.fixed_r_const().flags.writeable
|
||||||
np.testing.assert_array_equal(fixed_copy_r(fixed_r_const()), fixed_r_const())
|
np.testing.assert_array_equal(m.fixed_copy_r(m.fixed_r_const()), m.fixed_r_const())
|
||||||
|
|
||||||
|
|
||||||
def test_nonunit_stride_from_python():
|
def test_nonunit_stride_from_python():
|
||||||
from pybind11_tests import (
|
|
||||||
double_row, double_col, double_complex, double_mat_cm, double_mat_rm,
|
|
||||||
double_threec, double_threer)
|
|
||||||
|
|
||||||
counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
|
counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
|
||||||
second_row = counting_mat[1, :]
|
second_row = counting_mat[1, :]
|
||||||
second_col = counting_mat[:, 1]
|
second_col = counting_mat[:, 1]
|
||||||
np.testing.assert_array_equal(double_row(second_row), 2.0 * second_row)
|
np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row)
|
||||||
np.testing.assert_array_equal(double_col(second_row), 2.0 * second_row)
|
np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row)
|
||||||
np.testing.assert_array_equal(double_complex(second_row), 2.0 * second_row)
|
np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row)
|
||||||
np.testing.assert_array_equal(double_row(second_col), 2.0 * second_col)
|
np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col)
|
||||||
np.testing.assert_array_equal(double_col(second_col), 2.0 * second_col)
|
np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col)
|
||||||
np.testing.assert_array_equal(double_complex(second_col), 2.0 * second_col)
|
np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col)
|
||||||
|
|
||||||
counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
|
counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
|
||||||
slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
|
slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
|
||||||
for slice_idx, ref_mat in enumerate(slices):
|
for slice_idx, ref_mat in enumerate(slices):
|
||||||
np.testing.assert_array_equal(double_mat_cm(ref_mat), 2.0 * ref_mat)
|
np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)
|
||||||
np.testing.assert_array_equal(double_mat_rm(ref_mat), 2.0 * ref_mat)
|
np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)
|
||||||
|
|
||||||
# Mutator:
|
# Mutator:
|
||||||
double_threer(second_row)
|
m.double_threer(second_row)
|
||||||
double_threec(second_col)
|
m.double_threec(second_col)
|
||||||
np.testing.assert_array_equal(counting_mat, [[0., 2, 2], [6, 16, 10], [6, 14, 8]])
|
np.testing.assert_array_equal(counting_mat, [[0., 2, 2], [6, 16, 10], [6, 14, 8]])
|
||||||
|
|
||||||
|
|
||||||
def test_negative_stride_from_python(msg):
|
def test_negative_stride_from_python(msg):
|
||||||
from pybind11_tests import (
|
"""Eigen doesn't support (as of yet) negative strides. When a function takes an Eigen matrix by
|
||||||
double_row, double_col, double_complex, double_mat_cm, double_mat_rm,
|
copy or const reference, we can pass a numpy array that has negative strides. Otherwise, an
|
||||||
double_threec, double_threer)
|
exception will be thrown as Eigen will not be able to map the numpy array."""
|
||||||
|
|
||||||
# Eigen doesn't support (as of yet) negative strides. When a function takes an Eigen
|
|
||||||
# matrix by copy or const reference, we can pass a numpy array that has negative strides.
|
|
||||||
# Otherwise, an exception will be thrown as Eigen will not be able to map the numpy array.
|
|
||||||
|
|
||||||
counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
|
counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
|
||||||
counting_mat = counting_mat[::-1, ::-1]
|
counting_mat = counting_mat[::-1, ::-1]
|
||||||
second_row = counting_mat[1, :]
|
second_row = counting_mat[1, :]
|
||||||
second_col = counting_mat[:, 1]
|
second_col = counting_mat[:, 1]
|
||||||
np.testing.assert_array_equal(double_row(second_row), 2.0 * second_row)
|
np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row)
|
||||||
np.testing.assert_array_equal(double_col(second_row), 2.0 * second_row)
|
np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row)
|
||||||
np.testing.assert_array_equal(double_complex(second_row), 2.0 * second_row)
|
np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row)
|
||||||
np.testing.assert_array_equal(double_row(second_col), 2.0 * second_col)
|
np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col)
|
||||||
np.testing.assert_array_equal(double_col(second_col), 2.0 * second_col)
|
np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col)
|
||||||
np.testing.assert_array_equal(double_complex(second_col), 2.0 * second_col)
|
np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col)
|
||||||
|
|
||||||
counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
|
counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
|
||||||
counting_3d = counting_3d[::-1, ::-1, ::-1]
|
counting_3d = counting_3d[::-1, ::-1, ::-1]
|
||||||
slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
|
slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
|
||||||
for slice_idx, ref_mat in enumerate(slices):
|
for slice_idx, ref_mat in enumerate(slices):
|
||||||
np.testing.assert_array_equal(double_mat_cm(ref_mat), 2.0 * ref_mat)
|
np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)
|
||||||
np.testing.assert_array_equal(double_mat_rm(ref_mat), 2.0 * ref_mat)
|
np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)
|
||||||
|
|
||||||
# Mutator:
|
# Mutator:
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
double_threer(second_row)
|
m.double_threer(second_row)
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
double_threer(): incompatible function arguments. The following argument types are supported:
|
double_threer(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: numpy.ndarray[float32[1, 3], flags.writeable]) -> None
|
1. (arg0: numpy.ndarray[float32[1, 3], flags.writeable]) -> None
|
||||||
|
|
||||||
Invoked with: array([ 5., 4., 3.], dtype=float32)
|
Invoked with: array([ 5., 4., 3.], dtype=float32)
|
||||||
"""
|
""" # noqa: E501 line too long
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
double_threec(second_col)
|
m.double_threec(second_col)
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
double_threec(): incompatible function arguments. The following argument types are supported:
|
double_threec(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: numpy.ndarray[float32[3, 1], flags.writeable]) -> None
|
1. (arg0: numpy.ndarray[float32[3, 1], flags.writeable]) -> None
|
||||||
|
|
||||||
Invoked with: array([ 7., 4., 1.], dtype=float32)
|
Invoked with: array([ 7., 4., 1.], dtype=float32)
|
||||||
"""
|
""" # noqa: E501 line too long
|
||||||
|
|
||||||
|
|
||||||
def test_nonunit_stride_to_python():
|
def test_nonunit_stride_to_python():
|
||||||
from pybind11_tests import diagonal, diagonal_1, diagonal_n, block
|
assert np.all(m.diagonal(ref) == ref.diagonal())
|
||||||
|
assert np.all(m.diagonal_1(ref) == ref.diagonal(1))
|
||||||
assert np.all(diagonal(ref) == ref.diagonal())
|
|
||||||
assert np.all(diagonal_1(ref) == ref.diagonal(1))
|
|
||||||
for i in range(-5, 7):
|
for i in range(-5, 7):
|
||||||
assert np.all(diagonal_n(ref, i) == ref.diagonal(i)), "diagonal_n({})".format(i)
|
assert np.all(m.diagonal_n(ref, i) == ref.diagonal(i)), "m.diagonal_n({})".format(i)
|
||||||
|
|
||||||
assert np.all(block(ref, 2, 1, 3, 3) == ref[2:5, 1:4])
|
assert np.all(m.block(ref, 2, 1, 3, 3) == ref[2:5, 1:4])
|
||||||
assert np.all(block(ref, 1, 4, 4, 2) == ref[1:, 4:])
|
assert np.all(m.block(ref, 1, 4, 4, 2) == ref[1:, 4:])
|
||||||
assert np.all(block(ref, 1, 4, 3, 2) == ref[1:4, 4:])
|
assert np.all(m.block(ref, 1, 4, 3, 2) == ref[1:4, 4:])
|
||||||
|
|
||||||
|
|
||||||
def test_eigen_ref_to_python():
|
def test_eigen_ref_to_python():
|
||||||
from pybind11_tests import cholesky1, cholesky2, cholesky3, cholesky4
|
chols = [m.cholesky1, m.cholesky2, m.cholesky3, m.cholesky4]
|
||||||
|
|
||||||
chols = [cholesky1, cholesky2, cholesky3, cholesky4]
|
|
||||||
for i, chol in enumerate(chols, start=1):
|
for i, chol in enumerate(chols, start=1):
|
||||||
mymat = chol(np.array([[1., 2, 4], [2, 13, 23], [4, 23, 77]]))
|
mymat = chol(np.array([[1., 2, 4], [2, 13, 23], [4, 23, 77]]))
|
||||||
assert np.all(mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])), "cholesky{}".format(i)
|
assert np.all(mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])), "cholesky{}".format(i)
|
||||||
@ -246,9 +225,9 @@ def array_copy_but_one(a, r, c, v):
|
|||||||
|
|
||||||
def test_eigen_return_references():
|
def test_eigen_return_references():
|
||||||
"""Tests various ways of returning references and non-referencing copies"""
|
"""Tests various ways of returning references and non-referencing copies"""
|
||||||
from pybind11_tests import ReturnTester
|
|
||||||
master = np.ones((10, 10))
|
master = np.ones((10, 10))
|
||||||
a = ReturnTester()
|
a = m.ReturnTester()
|
||||||
a_get1 = a.get()
|
a_get1 = a.get()
|
||||||
assert not a_get1.flags.owndata and a_get1.flags.writeable
|
assert not a_get1.flags.owndata and a_get1.flags.writeable
|
||||||
assign_both(a_get1, master, 3, 3, 5)
|
assign_both(a_get1, master, 3, 3, 5)
|
||||||
@ -358,7 +337,6 @@ def test_eigen_return_references():
|
|||||||
|
|
||||||
|
|
||||||
def assert_keeps_alive(cl, method, *args):
|
def assert_keeps_alive(cl, method, *args):
|
||||||
from pybind11_tests import ConstructorStats
|
|
||||||
cstats = ConstructorStats.get(cl)
|
cstats = ConstructorStats.get(cl)
|
||||||
start_with = cstats.alive()
|
start_with = cstats.alive()
|
||||||
a = cl()
|
a = cl()
|
||||||
@ -374,10 +352,8 @@ def assert_keeps_alive(cl, method, *args):
|
|||||||
|
|
||||||
|
|
||||||
def test_eigen_keepalive():
|
def test_eigen_keepalive():
|
||||||
from pybind11_tests import ReturnTester, ConstructorStats
|
a = m.ReturnTester()
|
||||||
a = ReturnTester()
|
cstats = ConstructorStats.get(m.ReturnTester)
|
||||||
|
|
||||||
cstats = ConstructorStats.get(ReturnTester)
|
|
||||||
assert cstats.alive() == 1
|
assert cstats.alive() == 1
|
||||||
unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)]
|
unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)]
|
||||||
copies = [a.copy_get(), a.copy_view(), a.copy_ref(), a.copy_ref_const(),
|
copies = [a.copy_get(), a.copy_view(), a.copy_ref(), a.copy_ref_const(),
|
||||||
@ -387,43 +363,43 @@ def test_eigen_keepalive():
|
|||||||
del unsafe
|
del unsafe
|
||||||
del copies
|
del copies
|
||||||
|
|
||||||
for meth in [ReturnTester.get, ReturnTester.get_ptr, ReturnTester.view,
|
for meth in [m.ReturnTester.get, m.ReturnTester.get_ptr, m.ReturnTester.view,
|
||||||
ReturnTester.view_ptr, ReturnTester.ref_safe, ReturnTester.ref_const_safe,
|
m.ReturnTester.view_ptr, m.ReturnTester.ref_safe, m.ReturnTester.ref_const_safe,
|
||||||
ReturnTester.corners, ReturnTester.corners_const]:
|
m.ReturnTester.corners, m.ReturnTester.corners_const]:
|
||||||
assert_keeps_alive(ReturnTester, meth)
|
assert_keeps_alive(m.ReturnTester, meth)
|
||||||
|
|
||||||
for meth in [ReturnTester.block_safe, ReturnTester.block_const]:
|
for meth in [m.ReturnTester.block_safe, m.ReturnTester.block_const]:
|
||||||
assert_keeps_alive(ReturnTester, meth, 4, 3, 2, 1)
|
assert_keeps_alive(m.ReturnTester, meth, 4, 3, 2, 1)
|
||||||
|
|
||||||
|
|
||||||
def test_eigen_ref_mutators():
|
def test_eigen_ref_mutators():
|
||||||
"""Tests whether Eigen can mutate numpy values"""
|
"""Tests Eigen's ability to mutate numpy values"""
|
||||||
from pybind11_tests import add_rm, add_cm, add_any, add1, add2
|
|
||||||
orig = np.array([[1., 2, 3], [4, 5, 6], [7, 8, 9]])
|
orig = np.array([[1., 2, 3], [4, 5, 6], [7, 8, 9]])
|
||||||
zr = np.array(orig)
|
zr = np.array(orig)
|
||||||
zc = np.array(orig, order='F')
|
zc = np.array(orig, order='F')
|
||||||
add_rm(zr, 1, 0, 100)
|
m.add_rm(zr, 1, 0, 100)
|
||||||
assert np.all(zr == np.array([[1., 2, 3], [104, 5, 6], [7, 8, 9]]))
|
assert np.all(zr == np.array([[1., 2, 3], [104, 5, 6], [7, 8, 9]]))
|
||||||
add_cm(zc, 1, 0, 200)
|
m.add_cm(zc, 1, 0, 200)
|
||||||
assert np.all(zc == np.array([[1., 2, 3], [204, 5, 6], [7, 8, 9]]))
|
assert np.all(zc == np.array([[1., 2, 3], [204, 5, 6], [7, 8, 9]]))
|
||||||
|
|
||||||
add_any(zr, 1, 0, 20)
|
m.add_any(zr, 1, 0, 20)
|
||||||
assert np.all(zr == np.array([[1., 2, 3], [124, 5, 6], [7, 8, 9]]))
|
assert np.all(zr == np.array([[1., 2, 3], [124, 5, 6], [7, 8, 9]]))
|
||||||
add_any(zc, 1, 0, 10)
|
m.add_any(zc, 1, 0, 10)
|
||||||
assert np.all(zc == np.array([[1., 2, 3], [214, 5, 6], [7, 8, 9]]))
|
assert np.all(zc == np.array([[1., 2, 3], [214, 5, 6], [7, 8, 9]]))
|
||||||
|
|
||||||
# Can't reference a col-major array with a row-major Ref, and vice versa:
|
# Can't reference a col-major array with a row-major Ref, and vice versa:
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
add_rm(zc, 1, 0, 1)
|
m.add_rm(zc, 1, 0, 1)
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
add_cm(zr, 1, 0, 1)
|
m.add_cm(zr, 1, 0, 1)
|
||||||
|
|
||||||
# Overloads:
|
# Overloads:
|
||||||
add1(zr, 1, 0, -100)
|
m.add1(zr, 1, 0, -100)
|
||||||
add2(zr, 1, 0, -20)
|
m.add2(zr, 1, 0, -20)
|
||||||
assert np.all(zr == orig)
|
assert np.all(zr == orig)
|
||||||
add1(zc, 1, 0, -200)
|
m.add1(zc, 1, 0, -200)
|
||||||
add2(zc, 1, 0, -10)
|
m.add2(zc, 1, 0, -10)
|
||||||
assert np.all(zc == orig)
|
assert np.all(zc == orig)
|
||||||
|
|
||||||
# a non-contiguous slice (this won't work on either the row- or
|
# a non-contiguous slice (this won't work on either the row- or
|
||||||
@ -435,15 +411,15 @@ def test_eigen_ref_mutators():
|
|||||||
assert np.all(cornersc == np.array([[1., 3], [7, 9]]))
|
assert np.all(cornersc == np.array([[1., 3], [7, 9]]))
|
||||||
|
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
add_rm(cornersr, 0, 1, 25)
|
m.add_rm(cornersr, 0, 1, 25)
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
add_cm(cornersr, 0, 1, 25)
|
m.add_cm(cornersr, 0, 1, 25)
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
add_rm(cornersc, 0, 1, 25)
|
m.add_rm(cornersc, 0, 1, 25)
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
add_cm(cornersc, 0, 1, 25)
|
m.add_cm(cornersc, 0, 1, 25)
|
||||||
add_any(cornersr, 0, 1, 25)
|
m.add_any(cornersr, 0, 1, 25)
|
||||||
add_any(cornersc, 0, 1, 44)
|
m.add_any(cornersc, 0, 1, 44)
|
||||||
assert np.all(zr == np.array([[1., 2, 28], [4, 5, 6], [7, 8, 9]]))
|
assert np.all(zr == np.array([[1., 2, 28], [4, 5, 6], [7, 8, 9]]))
|
||||||
assert np.all(zc == np.array([[1., 2, 47], [4, 5, 6], [7, 8, 9]]))
|
assert np.all(zc == np.array([[1., 2, 47], [4, 5, 6], [7, 8, 9]]))
|
||||||
|
|
||||||
@ -451,30 +427,29 @@ def test_eigen_ref_mutators():
|
|||||||
zro = zr[0:4, 0:4]
|
zro = zr[0:4, 0:4]
|
||||||
zro.flags.writeable = False
|
zro.flags.writeable = False
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
add_rm(zro, 0, 0, 0)
|
m.add_rm(zro, 0, 0, 0)
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
add_any(zro, 0, 0, 0)
|
m.add_any(zro, 0, 0, 0)
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
add1(zro, 0, 0, 0)
|
m.add1(zro, 0, 0, 0)
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
add2(zro, 0, 0, 0)
|
m.add2(zro, 0, 0, 0)
|
||||||
|
|
||||||
# integer array shouldn't be passable to a double-matrix-accepting mutating func:
|
# integer array shouldn't be passable to a double-matrix-accepting mutating func:
|
||||||
zi = np.array([[1, 2], [3, 4]])
|
zi = np.array([[1, 2], [3, 4]])
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
add_rm(zi)
|
m.add_rm(zi)
|
||||||
|
|
||||||
|
|
||||||
def test_numpy_ref_mutators():
|
def test_numpy_ref_mutators():
|
||||||
"""Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)"""
|
"""Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)"""
|
||||||
from pybind11_tests import (
|
|
||||||
get_cm_ref, get_cm_const_ref, get_rm_ref, get_rm_const_ref, reset_refs)
|
|
||||||
reset_refs() # In case another test already changed it
|
|
||||||
|
|
||||||
zc = get_cm_ref()
|
m.reset_refs() # In case another test already changed it
|
||||||
zcro = get_cm_const_ref()
|
|
||||||
zr = get_rm_ref()
|
zc = m.get_cm_ref()
|
||||||
zrro = get_rm_const_ref()
|
zcro = m.get_cm_const_ref()
|
||||||
|
zr = m.get_rm_ref()
|
||||||
|
zrro = m.get_rm_const_ref()
|
||||||
|
|
||||||
assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4
|
assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4
|
||||||
|
|
||||||
@ -488,12 +463,12 @@ def test_numpy_ref_mutators():
|
|||||||
# We should have just changed zc, of course, but also zcro and the original eigen matrix
|
# We should have just changed zc, of course, but also zcro and the original eigen matrix
|
||||||
assert np.all(zc == expect)
|
assert np.all(zc == expect)
|
||||||
assert np.all(zcro == expect)
|
assert np.all(zcro == expect)
|
||||||
assert np.all(get_cm_ref() == expect)
|
assert np.all(m.get_cm_ref() == expect)
|
||||||
|
|
||||||
zr[1, 2] = 99
|
zr[1, 2] = 99
|
||||||
assert np.all(zr == expect)
|
assert np.all(zr == expect)
|
||||||
assert np.all(zrro == expect)
|
assert np.all(zrro == expect)
|
||||||
assert np.all(get_rm_ref() == expect)
|
assert np.all(m.get_rm_ref() == expect)
|
||||||
|
|
||||||
# Make sure the readonly ones are numpy-readonly:
|
# Make sure the readonly ones are numpy-readonly:
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
@ -503,7 +478,7 @@ def test_numpy_ref_mutators():
|
|||||||
|
|
||||||
# We should be able to explicitly copy like this (and since we're copying,
|
# We should be able to explicitly copy like this (and since we're copying,
|
||||||
# the const should drop away)
|
# the const should drop away)
|
||||||
y1 = np.array(get_cm_const_ref())
|
y1 = np.array(m.get_cm_const_ref())
|
||||||
|
|
||||||
assert y1.flags.owndata and y1.flags.writeable
|
assert y1.flags.owndata and y1.flags.writeable
|
||||||
# We should get copies of the eigen data, which was modified above:
|
# We should get copies of the eigen data, which was modified above:
|
||||||
@ -515,19 +490,18 @@ def test_numpy_ref_mutators():
|
|||||||
|
|
||||||
def test_both_ref_mutators():
|
def test_both_ref_mutators():
|
||||||
"""Tests a complex chain of nested eigen/numpy references"""
|
"""Tests a complex chain of nested eigen/numpy references"""
|
||||||
from pybind11_tests import (
|
|
||||||
incr_matrix, get_cm_ref, incr_matrix_any, even_cols, even_rows, reset_refs)
|
|
||||||
reset_refs() # In case another test already changed it
|
|
||||||
|
|
||||||
z = get_cm_ref() # numpy -> eigen
|
m.reset_refs() # In case another test already changed it
|
||||||
|
|
||||||
|
z = m.get_cm_ref() # numpy -> eigen
|
||||||
z[0, 2] -= 3
|
z[0, 2] -= 3
|
||||||
z2 = incr_matrix(z, 1) # numpy -> eigen -> numpy -> eigen
|
z2 = m.incr_matrix(z, 1) # numpy -> eigen -> numpy -> eigen
|
||||||
z2[1, 1] += 6
|
z2[1, 1] += 6
|
||||||
z3 = incr_matrix(z, 2) # (numpy -> eigen)^3
|
z3 = m.incr_matrix(z, 2) # (numpy -> eigen)^3
|
||||||
z3[2, 2] += -5
|
z3[2, 2] += -5
|
||||||
z4 = incr_matrix(z, 3) # (numpy -> eigen)^4
|
z4 = m.incr_matrix(z, 3) # (numpy -> eigen)^4
|
||||||
z4[1, 1] -= 1
|
z4[1, 1] -= 1
|
||||||
z5 = incr_matrix(z, 4) # (numpy -> eigen)^5
|
z5 = m.incr_matrix(z, 4) # (numpy -> eigen)^5
|
||||||
z5[0, 0] = 0
|
z5[0, 0] = 0
|
||||||
assert np.all(z == z2)
|
assert np.all(z == z2)
|
||||||
assert np.all(z == z3)
|
assert np.all(z == z3)
|
||||||
@ -537,11 +511,11 @@ def test_both_ref_mutators():
|
|||||||
assert np.all(z == expect)
|
assert np.all(z == expect)
|
||||||
|
|
||||||
y = np.array(range(100), dtype='float64').reshape(10, 10)
|
y = np.array(range(100), dtype='float64').reshape(10, 10)
|
||||||
y2 = incr_matrix_any(y, 10) # np -> eigen -> np
|
y2 = m.incr_matrix_any(y, 10) # np -> eigen -> np
|
||||||
y3 = incr_matrix_any(y2[0::2, 0::2], -33) # np -> eigen -> np slice -> np -> eigen -> np
|
y3 = m.incr_matrix_any(y2[0::2, 0::2], -33) # np -> eigen -> np slice -> np -> eigen -> np
|
||||||
y4 = even_rows(y3) # numpy -> eigen slice -> (... y3)
|
y4 = m.even_rows(y3) # numpy -> eigen slice -> (... y3)
|
||||||
y5 = even_cols(y4) # numpy -> eigen slice -> (... y4)
|
y5 = m.even_cols(y4) # numpy -> eigen slice -> (... y4)
|
||||||
y6 = incr_matrix_any(y5, 1000) # numpy -> eigen -> (... y5)
|
y6 = m.incr_matrix_any(y5, 1000) # numpy -> eigen -> (... y5)
|
||||||
|
|
||||||
# Apply same mutations using just numpy:
|
# Apply same mutations using just numpy:
|
||||||
yexpect = np.array(range(100), dtype='float64').reshape(10, 10)
|
yexpect = np.array(range(100), dtype='float64').reshape(10, 10)
|
||||||
@ -557,7 +531,6 @@ def test_both_ref_mutators():
|
|||||||
|
|
||||||
|
|
||||||
def test_nocopy_wrapper():
|
def test_nocopy_wrapper():
|
||||||
from pybind11_tests import get_elem, get_elem_nocopy, get_elem_rm_nocopy
|
|
||||||
# get_elem requires a column-contiguous matrix reference, but should be
|
# get_elem requires a column-contiguous matrix reference, but should be
|
||||||
# callable with other types of matrix (via copying):
|
# callable with other types of matrix (via copying):
|
||||||
int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order='F')
|
int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order='F')
|
||||||
@ -566,38 +539,38 @@ def test_nocopy_wrapper():
|
|||||||
dbl_matrix_rowmajor = np.array(int_matrix_rowmajor, dtype='double', order='C', copy=True)
|
dbl_matrix_rowmajor = np.array(int_matrix_rowmajor, dtype='double', order='C', copy=True)
|
||||||
|
|
||||||
# All should be callable via get_elem:
|
# All should be callable via get_elem:
|
||||||
assert get_elem(int_matrix_colmajor) == 8
|
assert m.get_elem(int_matrix_colmajor) == 8
|
||||||
assert get_elem(dbl_matrix_colmajor) == 8
|
assert m.get_elem(dbl_matrix_colmajor) == 8
|
||||||
assert get_elem(int_matrix_rowmajor) == 8
|
assert m.get_elem(int_matrix_rowmajor) == 8
|
||||||
assert get_elem(dbl_matrix_rowmajor) == 8
|
assert m.get_elem(dbl_matrix_rowmajor) == 8
|
||||||
|
|
||||||
# All but the second should fail with get_elem_nocopy:
|
# All but the second should fail with m.get_elem_nocopy:
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
get_elem_nocopy(int_matrix_colmajor)
|
m.get_elem_nocopy(int_matrix_colmajor)
|
||||||
assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and
|
assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and
|
||||||
', flags.f_contiguous' in str(excinfo.value))
|
', flags.f_contiguous' in str(excinfo.value))
|
||||||
assert get_elem_nocopy(dbl_matrix_colmajor) == 8
|
assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
get_elem_nocopy(int_matrix_rowmajor)
|
m.get_elem_nocopy(int_matrix_rowmajor)
|
||||||
assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and
|
assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and
|
||||||
', flags.f_contiguous' in str(excinfo.value))
|
', flags.f_contiguous' in str(excinfo.value))
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
get_elem_nocopy(dbl_matrix_rowmajor)
|
m.get_elem_nocopy(dbl_matrix_rowmajor)
|
||||||
assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and
|
assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and
|
||||||
', flags.f_contiguous' in str(excinfo.value))
|
', flags.f_contiguous' in str(excinfo.value))
|
||||||
|
|
||||||
# For the row-major test, we take a long matrix in row-major, so only the third is allowed:
|
# For the row-major test, we take a long matrix in row-major, so only the third is allowed:
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
get_elem_rm_nocopy(int_matrix_colmajor)
|
m.get_elem_rm_nocopy(int_matrix_colmajor)
|
||||||
assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and
|
assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and
|
||||||
', flags.c_contiguous' in str(excinfo.value))
|
', flags.c_contiguous' in str(excinfo.value))
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
get_elem_rm_nocopy(dbl_matrix_colmajor)
|
m.get_elem_rm_nocopy(dbl_matrix_colmajor)
|
||||||
assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and
|
assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and
|
||||||
', flags.c_contiguous' in str(excinfo.value))
|
', flags.c_contiguous' in str(excinfo.value))
|
||||||
assert get_elem_rm_nocopy(int_matrix_rowmajor) == 8
|
assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
get_elem_rm_nocopy(dbl_matrix_rowmajor)
|
m.get_elem_rm_nocopy(dbl_matrix_rowmajor)
|
||||||
assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and
|
assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and
|
||||||
', flags.c_contiguous' in str(excinfo.value))
|
', flags.c_contiguous' in str(excinfo.value))
|
||||||
|
|
||||||
@ -608,19 +581,16 @@ def test_eigen_ref_life_support():
|
|||||||
The `Ref` caster sometimes creates a copy which needs to stay alive. This needs to
|
The `Ref` caster sometimes creates a copy which needs to stay alive. This needs to
|
||||||
happen both for directs casts (just the array) or indirectly (e.g. list of arrays).
|
happen both for directs casts (just the array) or indirectly (e.g. list of arrays).
|
||||||
"""
|
"""
|
||||||
from pybind11_tests import get_elem_direct, get_elem_indirect
|
|
||||||
|
|
||||||
a = np.full(shape=10, fill_value=8, dtype=np.int8)
|
a = np.full(shape=10, fill_value=8, dtype=np.int8)
|
||||||
assert get_elem_direct(a) == 8
|
assert m.get_elem_direct(a) == 8
|
||||||
|
|
||||||
list_of_a = [a]
|
list_of_a = [a]
|
||||||
assert get_elem_indirect(list_of_a) == 8
|
assert m.get_elem_indirect(list_of_a) == 8
|
||||||
|
|
||||||
|
|
||||||
def test_special_matrix_objects():
|
def test_special_matrix_objects():
|
||||||
from pybind11_tests import incr_diag, symmetric_upper, symmetric_lower
|
assert np.all(m.incr_diag(7) == np.diag([1., 2, 3, 4, 5, 6, 7]))
|
||||||
|
|
||||||
assert np.all(incr_diag(7) == np.diag([1., 2, 3, 4, 5, 6, 7]))
|
|
||||||
|
|
||||||
asymm = np.array([[ 1., 2, 3, 4],
|
asymm = np.array([[ 1., 2, 3, 4],
|
||||||
[ 5, 6, 7, 8],
|
[ 5, 6, 7, 8],
|
||||||
@ -633,89 +603,79 @@ def test_special_matrix_objects():
|
|||||||
symm_lower[i, j] = symm_lower[j, i]
|
symm_lower[i, j] = symm_lower[j, i]
|
||||||
symm_upper[j, i] = symm_upper[i, j]
|
symm_upper[j, i] = symm_upper[i, j]
|
||||||
|
|
||||||
assert np.all(symmetric_lower(asymm) == symm_lower)
|
assert np.all(m.symmetric_lower(asymm) == symm_lower)
|
||||||
assert np.all(symmetric_upper(asymm) == symm_upper)
|
assert np.all(m.symmetric_upper(asymm) == symm_upper)
|
||||||
|
|
||||||
|
|
||||||
def test_dense_signature(doc):
|
def test_dense_signature(doc):
|
||||||
from pybind11_tests import double_col, double_row, double_complex, double_mat_rm
|
assert doc(m.double_col) == """
|
||||||
|
|
||||||
assert doc(double_col) == """
|
|
||||||
double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]]
|
double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]]
|
||||||
"""
|
"""
|
||||||
assert doc(double_row) == """
|
assert doc(m.double_row) == """
|
||||||
double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]]
|
double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]]
|
||||||
"""
|
"""
|
||||||
assert doc(double_complex) == """
|
assert doc(m.double_complex) == """
|
||||||
double_complex(arg0: numpy.ndarray[complex64[m, 1]]) -> numpy.ndarray[complex64[m, 1]]
|
double_complex(arg0: numpy.ndarray[complex64[m, 1]]) -> numpy.ndarray[complex64[m, 1]]
|
||||||
"""
|
"""
|
||||||
assert doc(double_mat_rm) == """
|
assert doc(m.double_mat_rm) == """
|
||||||
double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]]
|
double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def test_named_arguments():
|
def test_named_arguments():
|
||||||
from pybind11_tests import matrix_multiply
|
|
||||||
|
|
||||||
a = np.array([[1.0, 2], [3, 4], [5, 6]])
|
a = np.array([[1.0, 2], [3, 4], [5, 6]])
|
||||||
b = np.ones((2, 1))
|
b = np.ones((2, 1))
|
||||||
|
|
||||||
assert np.all(matrix_multiply(a, b) == np.array([[3.], [7], [11]]))
|
assert np.all(m.matrix_multiply(a, b) == np.array([[3.], [7], [11]]))
|
||||||
assert np.all(matrix_multiply(A=a, B=b) == np.array([[3.], [7], [11]]))
|
assert np.all(m.matrix_multiply(A=a, B=b) == np.array([[3.], [7], [11]]))
|
||||||
assert np.all(matrix_multiply(B=b, A=a) == np.array([[3.], [7], [11]]))
|
assert np.all(m.matrix_multiply(B=b, A=a) == np.array([[3.], [7], [11]]))
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
matrix_multiply(b, a)
|
m.matrix_multiply(b, a)
|
||||||
assert str(excinfo.value) == 'Nonconformable matrices!'
|
assert str(excinfo.value) == 'Nonconformable matrices!'
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
matrix_multiply(A=b, B=a)
|
m.matrix_multiply(A=b, B=a)
|
||||||
assert str(excinfo.value) == 'Nonconformable matrices!'
|
assert str(excinfo.value) == 'Nonconformable matrices!'
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
matrix_multiply(B=a, A=b)
|
m.matrix_multiply(B=a, A=b)
|
||||||
assert str(excinfo.value) == 'Nonconformable matrices!'
|
assert str(excinfo.value) == 'Nonconformable matrices!'
|
||||||
|
|
||||||
|
|
||||||
@pytest.requires_eigen_and_scipy
|
@pytest.requires_eigen_and_scipy
|
||||||
def test_sparse():
|
def test_sparse():
|
||||||
from pybind11_tests import sparse_r, sparse_c, sparse_copy_r, sparse_copy_c
|
assert_sparse_equal_ref(m.sparse_r())
|
||||||
|
assert_sparse_equal_ref(m.sparse_c())
|
||||||
assert_sparse_equal_ref(sparse_r())
|
assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_r()))
|
||||||
assert_sparse_equal_ref(sparse_c())
|
assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_c()))
|
||||||
assert_sparse_equal_ref(sparse_copy_r(sparse_r()))
|
assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_c()))
|
||||||
assert_sparse_equal_ref(sparse_copy_c(sparse_c()))
|
assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_r()))
|
||||||
assert_sparse_equal_ref(sparse_copy_r(sparse_c()))
|
|
||||||
assert_sparse_equal_ref(sparse_copy_c(sparse_r()))
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.requires_eigen_and_scipy
|
@pytest.requires_eigen_and_scipy
|
||||||
def test_sparse_signature(doc):
|
def test_sparse_signature(doc):
|
||||||
from pybind11_tests import sparse_copy_r, sparse_copy_c
|
assert doc(m.sparse_copy_r) == """
|
||||||
|
|
||||||
assert doc(sparse_copy_r) == """
|
|
||||||
sparse_copy_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32]
|
sparse_copy_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32]
|
||||||
""" # noqa: E501 line too long
|
""" # noqa: E501 line too long
|
||||||
assert doc(sparse_copy_c) == """
|
assert doc(m.sparse_copy_c) == """
|
||||||
sparse_copy_c(arg0: scipy.sparse.csc_matrix[float32]) -> scipy.sparse.csc_matrix[float32]
|
sparse_copy_c(arg0: scipy.sparse.csc_matrix[float32]) -> scipy.sparse.csc_matrix[float32]
|
||||||
""" # noqa: E501 line too long
|
""" # noqa: E501 line too long
|
||||||
|
|
||||||
|
|
||||||
def test_issue738():
|
def test_issue738():
|
||||||
from pybind11_tests import iss738_f1, iss738_f2
|
"""Ignore strides on a length-1 dimension (even if they would be incompatible length > 1)"""
|
||||||
|
assert np.all(m.iss738_f1(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]]))
|
||||||
|
assert np.all(m.iss738_f1(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]]))
|
||||||
|
|
||||||
assert np.all(iss738_f1(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]]))
|
assert np.all(m.iss738_f2(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]]))
|
||||||
assert np.all(iss738_f1(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]]))
|
assert np.all(m.iss738_f2(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]]))
|
||||||
|
|
||||||
assert np.all(iss738_f2(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]]))
|
|
||||||
assert np.all(iss738_f2(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]]))
|
|
||||||
|
|
||||||
|
|
||||||
def test_custom_operator_new():
|
def test_custom_operator_new():
|
||||||
"""Using Eigen types as member variables requires a class-specific
|
"""Using Eigen types as member variables requires a class-specific
|
||||||
operator new with proper alignment"""
|
operator new with proper alignment"""
|
||||||
from pybind11_tests import CustomOperatorNew
|
|
||||||
|
|
||||||
o = CustomOperatorNew()
|
o = m.CustomOperatorNew()
|
||||||
np.testing.assert_allclose(o.a, 0.0)
|
np.testing.assert_allclose(o.a, 0.0)
|
||||||
np.testing.assert_allclose(o.b.diagonal(), 1.0)
|
np.testing.assert_allclose(o.b.diagonal(), 1.0)
|
||||||
|
@ -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) {
|
|||||||
.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) { });
|
||||||
});
|
}
|
||||||
|
@ -1,51 +1,50 @@
|
|||||||
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():
|
|||||||
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"
|
f = m.ClassWithUnscopedEnum.test_function
|
||||||
assert str(ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
|
first = m.ClassWithUnscopedEnum.EFirstMode
|
||||||
|
second = m.ClassWithUnscopedEnum.ESecondMode
|
||||||
f = ClassWithUnscopedEnum.test_function
|
|
||||||
first = ClassWithUnscopedEnum.EFirstMode
|
|
||||||
second = ClassWithUnscopedEnum.ESecondMode
|
|
||||||
|
|
||||||
assert f(first) == 1
|
assert f(first) == 1
|
||||||
|
|
||||||
@ -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(m.Flags.Execute) == 1
|
||||||
|
assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7
|
||||||
|
assert int(m.Flags.Read | m.Flags.Write) == 6
|
||||||
|
assert int(m.Flags.Read | m.Flags.Execute) == 5
|
||||||
|
assert int(m.Flags.Write | m.Flags.Execute) == 3
|
||||||
|
assert int(m.Flags.Write | 1) == 3
|
||||||
|
|
||||||
assert int(Flags.Read) == 4
|
state = m.Flags.Read | m.Flags.Write
|
||||||
assert int(Flags.Write) == 2
|
assert (state & m.Flags.Read) != 0
|
||||||
assert int(Flags.Execute) == 1
|
assert (state & m.Flags.Write) != 0
|
||||||
assert int(Flags.Read | Flags.Write | Flags.Execute) == 7
|
assert (state & m.Flags.Execute) == 0
|
||||||
assert int(Flags.Read | Flags.Write) == 6
|
|
||||||
assert int(Flags.Read | Flags.Execute) == 5
|
|
||||||
assert int(Flags.Write | Flags.Execute) == 3
|
|
||||||
assert int(Flags.Write | 1) == 3
|
|
||||||
|
|
||||||
state = Flags.Read | Flags.Write
|
|
||||||
assert (state & Flags.Read) != 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():
|
|||||||
|
|
||||||
|
|
||||||
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 @@
|
|||||||
#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) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
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 @@
|
|||||||
#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) + " ";
|
||||||
|
ret.back() = '}';
|
||||||
|
return ret;
|
||||||
|
}, py::arg("myList") = list);
|
||||||
|
|
||||||
m.def("args_function", &args_function);
|
m.def("kw_func_udl", kw_func, "x"_a, "y"_a=300);
|
||||||
m.def("args_kwargs_function", &args_kwargs_function);
|
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);
|
// test_args_and_kwargs
|
||||||
m.def("kw_func_udl_z", &kw_func, "x"_a, "y"_a=0);
|
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);
|
|
||||||
});
|
|
||||||
|
@ -1,65 +1,64 @@
|
|||||||
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, ())
|
||||||
|
@ -26,40 +26,43 @@ public:
|
|||||||
void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; }
|
void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; }
|
||||||
void operator=(ExampleMandA &&e) { print_move_assigned(this); value = e.value; }
|
void operator=(ExampleMandA &&e) { print_move_assigned(this); value = e.value; }
|
||||||
|
|
||||||
void add1(ExampleMandA other) { value += other.value; } // passing by value
|
void add1(ExampleMandA other) { value += other.value; } // passing by value
|
||||||
void add2(ExampleMandA &other) { value += other.value; } // passing by reference
|
void add2(ExampleMandA &other) { value += other.value; } // passing by reference
|
||||||
void add3(const ExampleMandA &other) { value += other.value; } // passing by const reference
|
void add3(const ExampleMandA &other) { value += other.value; } // passing by const reference
|
||||||
void add4(ExampleMandA *other) { value += other->value; } // passing by pointer
|
void add4(ExampleMandA *other) { value += other->value; } // passing by pointer
|
||||||
void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer
|
void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer
|
||||||
|
|
||||||
void add6(int other) { value += other; } // passing by value
|
void add6(int other) { value += other; } // passing by value
|
||||||
void add7(int &other) { value += other; } // passing by reference
|
void add7(int &other) { value += other; } // passing by reference
|
||||||
void add8(const int &other) { value += other; } // passing by const reference
|
void add8(const int &other) { value += other; } // passing by const reference
|
||||||
void add9(int *other) { value += *other; } // passing by pointer
|
void add9(int *other) { value += *other; } // passing by pointer
|
||||||
void add10(const int *other) { value += *other; } // passing by const pointer
|
void add10(const int *other) { value += *other; } // passing by const pointer
|
||||||
|
|
||||||
ExampleMandA self1() { return *this; } // return by value
|
ExampleMandA self1() { return *this; } // return by value
|
||||||
ExampleMandA &self2() { return *this; } // return by reference
|
ExampleMandA &self2() { return *this; } // return by reference
|
||||||
const ExampleMandA &self3() { return *this; } // return by const reference
|
const ExampleMandA &self3() { return *this; } // return by const reference
|
||||||
ExampleMandA *self4() { return this; } // return by pointer
|
ExampleMandA *self4() { return this; } // return by pointer
|
||||||
const ExampleMandA *self5() { return this; } // return by const pointer
|
const ExampleMandA *self5() { return this; } // return by const pointer
|
||||||
|
|
||||||
int internal1() { return value; } // return by value
|
int internal1() { return value; } // return by value
|
||||||
int &internal2() { return value; } // return by reference
|
int &internal2() { return value; } // return by reference
|
||||||
const int &internal3() { return value; } // return by const reference
|
const int &internal3() { return value; } // return by const reference
|
||||||
int *internal4() { return &value; } // return by pointer
|
int *internal4() { return &value; } // return by pointer
|
||||||
const int *internal5() { return &value; } // return by const pointer
|
const int *internal5() { return &value; } // return by const pointer
|
||||||
|
|
||||||
|
py::str overloaded() { return "()"; }
|
||||||
|
py::str overloaded(int) { return "(int)"; }
|
||||||
py::str overloaded(int, float) { return "(int, float)"; }
|
py::str overloaded(int, float) { return "(int, float)"; }
|
||||||
py::str overloaded(float, int) { return "(float, int)"; }
|
py::str overloaded(float, int) { return "(float, int)"; }
|
||||||
py::str overloaded(int, int) { return "(int, int)"; }
|
py::str overloaded(int, int) { return "(int, int)"; }
|
||||||
py::str overloaded(float, float) { return "(float, float)"; }
|
py::str overloaded(float, float) { return "(float, float)"; }
|
||||||
|
py::str overloaded(int) const { return "(int) const"; }
|
||||||
py::str overloaded(int, float) const { return "(int, float) const"; }
|
py::str overloaded(int, float) const { return "(int, float) const"; }
|
||||||
py::str overloaded(float, int) const { return "(float, int) const"; }
|
py::str overloaded(float, int) const { return "(float, int) const"; }
|
||||||
py::str overloaded(int, int) const { return "(int, int) const"; }
|
py::str overloaded(int, int) const { return "(int, int) const"; }
|
||||||
py::str overloaded(float, float) const { return "(float, float) const"; }
|
py::str overloaded(float, float) const { return "(float, float) const"; }
|
||||||
|
|
||||||
static py::str overloaded() { return "static"; }
|
static py::str overloaded(float) { return "static float"; }
|
||||||
|
|
||||||
int value = 0;
|
int value = 0;
|
||||||
};
|
};
|
||||||
@ -74,41 +77,28 @@ struct TestProperties {
|
|||||||
static int static_get() { return static_value; }
|
static int static_get() { return static_value; }
|
||||||
static void static_set(int v) { static_value = v; }
|
static void static_set(int v) { static_value = v; }
|
||||||
};
|
};
|
||||||
|
|
||||||
int TestProperties::static_value = 1;
|
int TestProperties::static_value = 1;
|
||||||
|
|
||||||
struct TestPropertiesOverride : TestProperties {
|
struct TestPropertiesOverride : TestProperties {
|
||||||
int value = 99;
|
int value = 99;
|
||||||
static int static_value;
|
static int static_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
int TestPropertiesOverride::static_value = 99;
|
int TestPropertiesOverride::static_value = 99;
|
||||||
|
|
||||||
struct SimpleValue { int value = 1; };
|
|
||||||
|
|
||||||
struct TestPropRVP {
|
struct TestPropRVP {
|
||||||
SimpleValue v1;
|
UserType v1{1};
|
||||||
SimpleValue v2;
|
UserType v2{1};
|
||||||
static SimpleValue sv1;
|
static UserType sv1;
|
||||||
static SimpleValue sv2;
|
static UserType sv2;
|
||||||
|
|
||||||
const SimpleValue &get1() const { return v1; }
|
const UserType &get1() const { return v1; }
|
||||||
const SimpleValue &get2() const { return v2; }
|
const UserType &get2() const { return v2; }
|
||||||
SimpleValue get_rvalue() const { return v2; }
|
UserType get_rvalue() const { return v2; }
|
||||||
void set1(int v) { v1.value = v; }
|
void set1(int v) { v1.set(v); }
|
||||||
void set2(int v) { v2.value = v; }
|
void set2(int v) { v2.set(v); }
|
||||||
};
|
};
|
||||||
|
UserType TestPropRVP::sv1(1);
|
||||||
SimpleValue TestPropRVP::sv1{};
|
UserType TestPropRVP::sv2(1);
|
||||||
SimpleValue TestPropRVP::sv2{};
|
|
||||||
|
|
||||||
class DynamicClass {
|
|
||||||
public:
|
|
||||||
DynamicClass() { print_default_created(this); }
|
|
||||||
~DynamicClass() { print_destroyed(this); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class CppDerivedDynamicClass : public DynamicClass { };
|
|
||||||
|
|
||||||
// py::arg/py::arg_v testing: these arguments just record their argument when invoked
|
// py::arg/py::arg_v testing: these arguments just record their argument when invoked
|
||||||
class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; };
|
class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; };
|
||||||
@ -180,9 +170,6 @@ template <> struct type_caster<DestructionTester> {
|
|||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// Issue/PR #648: bad arg default debugging output
|
|
||||||
class NotRegistered {};
|
|
||||||
|
|
||||||
// Test None-allowed py::arg argument policy
|
// Test None-allowed py::arg argument policy
|
||||||
class NoneTester { public: int answer = 42; };
|
class NoneTester { public: int answer = 42; };
|
||||||
int none1(const NoneTester &obj) { return obj.answer; }
|
int none1(const NoneTester &obj) { return obj.answer; }
|
||||||
@ -215,7 +202,8 @@ public:
|
|||||||
double sum() const { return rw_value + ro_value; }
|
double sum() const { return rw_value + ro_value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
test_initializer methods_and_attributes([](py::module &m) {
|
TEST_SUBMODULE(methods_and_attributes, m) {
|
||||||
|
// test_methods_and_attributes
|
||||||
py::class_<ExampleMandA> emna(m, "ExampleMandA");
|
py::class_<ExampleMandA> emna(m, "ExampleMandA");
|
||||||
emna.def(py::init<>())
|
emna.def(py::init<>())
|
||||||
.def(py::init<int>())
|
.def(py::init<int>())
|
||||||
@ -241,43 +229,52 @@ test_initializer methods_and_attributes([](py::module &m) {
|
|||||||
.def("internal4", &ExampleMandA::internal4)
|
.def("internal4", &ExampleMandA::internal4)
|
||||||
.def("internal5", &ExampleMandA::internal5)
|
.def("internal5", &ExampleMandA::internal5)
|
||||||
#if defined(PYBIND11_OVERLOAD_CAST)
|
#if defined(PYBIND11_OVERLOAD_CAST)
|
||||||
|
.def("overloaded", py::overload_cast<>(&ExampleMandA::overloaded))
|
||||||
|
.def("overloaded", py::overload_cast<int>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded", py::overload_cast<int, float>(&ExampleMandA::overloaded))
|
.def("overloaded", py::overload_cast<int, float>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded", py::overload_cast<float, int>(&ExampleMandA::overloaded))
|
.def("overloaded", py::overload_cast<float, int>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded", py::overload_cast<int, int>(&ExampleMandA::overloaded))
|
.def("overloaded", py::overload_cast<int, int>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded", py::overload_cast<float, float>(&ExampleMandA::overloaded))
|
.def("overloaded", py::overload_cast<float, float>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded_float", py::overload_cast<float, float>(&ExampleMandA::overloaded))
|
.def("overloaded_float", py::overload_cast<float, float>(&ExampleMandA::overloaded))
|
||||||
|
.def("overloaded_const", py::overload_cast<int >(&ExampleMandA::overloaded, py::const_))
|
||||||
.def("overloaded_const", py::overload_cast<int, float>(&ExampleMandA::overloaded, py::const_))
|
.def("overloaded_const", py::overload_cast<int, float>(&ExampleMandA::overloaded, py::const_))
|
||||||
.def("overloaded_const", py::overload_cast<float, int>(&ExampleMandA::overloaded, py::const_))
|
.def("overloaded_const", py::overload_cast<float, int>(&ExampleMandA::overloaded, py::const_))
|
||||||
.def("overloaded_const", py::overload_cast<int, int>(&ExampleMandA::overloaded, py::const_))
|
.def("overloaded_const", py::overload_cast<int, int>(&ExampleMandA::overloaded, py::const_))
|
||||||
.def("overloaded_const", py::overload_cast<float, float>(&ExampleMandA::overloaded, py::const_))
|
.def("overloaded_const", py::overload_cast<float, float>(&ExampleMandA::overloaded, py::const_))
|
||||||
#else
|
#else
|
||||||
|
.def("overloaded", static_cast<py::str (ExampleMandA::*)()>(&ExampleMandA::overloaded))
|
||||||
|
.def("overloaded", static_cast<py::str (ExampleMandA::*)(int)>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded", static_cast<py::str (ExampleMandA::*)(int, float)>(&ExampleMandA::overloaded))
|
.def("overloaded", static_cast<py::str (ExampleMandA::*)(int, float)>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded", static_cast<py::str (ExampleMandA::*)(float, int)>(&ExampleMandA::overloaded))
|
.def("overloaded", static_cast<py::str (ExampleMandA::*)(float, int)>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
|
.def("overloaded", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded))
|
.def("overloaded", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded_float", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded))
|
.def("overloaded_float", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded))
|
||||||
|
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int ) const>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, float) const>(&ExampleMandA::overloaded))
|
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, float) const>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, int) const>(&ExampleMandA::overloaded))
|
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, int) const>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, int) const>(&ExampleMandA::overloaded))
|
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, int) const>(&ExampleMandA::overloaded))
|
||||||
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, float) const>(&ExampleMandA::overloaded))
|
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, float) const>(&ExampleMandA::overloaded))
|
||||||
#endif
|
#endif
|
||||||
|
// test_no_mixed_overloads
|
||||||
// Raise error if trying to mix static/non-static overloads on the same name:
|
// Raise error if trying to mix static/non-static overloads on the same name:
|
||||||
.def_static("add_mixed_overloads1", []() {
|
.def_static("add_mixed_overloads1", []() {
|
||||||
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests").attr("ExampleMandA"));
|
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
|
||||||
emna.def ("overload_mixed1", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
|
emna.def ("overload_mixed1", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
|
||||||
.def_static("overload_mixed1", static_cast<py::str ( *)( )>(&ExampleMandA::overloaded));
|
.def_static("overload_mixed1", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded));
|
||||||
})
|
})
|
||||||
.def_static("add_mixed_overloads2", []() {
|
.def_static("add_mixed_overloads2", []() {
|
||||||
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests").attr("ExampleMandA"));
|
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
|
||||||
emna.def_static("overload_mixed2", static_cast<py::str ( *)( )>(&ExampleMandA::overloaded))
|
emna.def_static("overload_mixed2", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded))
|
||||||
.def ("overload_mixed2", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded));
|
.def ("overload_mixed2", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded));
|
||||||
})
|
})
|
||||||
.def("__str__", &ExampleMandA::toString)
|
.def("__str__", &ExampleMandA::toString)
|
||||||
.def_readwrite("value", &ExampleMandA::value);
|
.def_readwrite("value", &ExampleMandA::value);
|
||||||
|
|
||||||
|
// test_copy_method
|
||||||
// Issue #443: can't call copied methods in Python 3
|
// Issue #443: can't call copied methods in Python 3
|
||||||
emna.attr("add2b") = emna.attr("add2");
|
emna.attr("add2b") = emna.attr("add2");
|
||||||
|
|
||||||
|
// test_properties, test_static_properties, test_static_cls
|
||||||
py::class_<TestProperties>(m, "TestProperties")
|
py::class_<TestProperties>(m, "TestProperties")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def_readonly("def_readonly", &TestProperties::value)
|
.def_readonly("def_readonly", &TestProperties::value)
|
||||||
@ -300,15 +297,13 @@ test_initializer methods_and_attributes([](py::module &m) {
|
|||||||
.def_readonly("def_readonly", &TestPropertiesOverride::value)
|
.def_readonly("def_readonly", &TestPropertiesOverride::value)
|
||||||
.def_readonly_static("def_readonly_static", &TestPropertiesOverride::static_value);
|
.def_readonly_static("def_readonly_static", &TestPropertiesOverride::static_value);
|
||||||
|
|
||||||
py::class_<SimpleValue>(m, "SimpleValue")
|
auto static_get1 = [](py::object) -> const UserType & { return TestPropRVP::sv1; };
|
||||||
.def_readwrite("value", &SimpleValue::value);
|
auto static_get2 = [](py::object) -> const UserType & { return TestPropRVP::sv2; };
|
||||||
|
auto static_set1 = [](py::object, int v) { TestPropRVP::sv1.set(v); };
|
||||||
auto static_get1 = [](py::object) -> const SimpleValue & { return TestPropRVP::sv1; };
|
auto static_set2 = [](py::object, int v) { TestPropRVP::sv2.set(v); };
|
||||||
auto static_get2 = [](py::object) -> const SimpleValue & { return TestPropRVP::sv2; };
|
|
||||||
auto static_set1 = [](py::object, int v) { TestPropRVP::sv1.value = v; };
|
|
||||||
auto static_set2 = [](py::object, int v) { TestPropRVP::sv2.value = v; };
|
|
||||||
auto rvp_copy = py::return_value_policy::copy;
|
auto rvp_copy = py::return_value_policy::copy;
|
||||||
|
|
||||||
|
// test_property_return_value_policies
|
||||||
py::class_<TestPropRVP>(m, "TestPropRVP")
|
py::class_<TestPropRVP>(m, "TestPropRVP")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def_property_readonly("ro_ref", &TestPropRVP::get1)
|
.def_property_readonly("ro_ref", &TestPropRVP::get1)
|
||||||
@ -323,21 +318,32 @@ test_initializer methods_and_attributes([](py::module &m) {
|
|||||||
.def_property_static("static_rw_ref", static_get1, static_set1)
|
.def_property_static("static_rw_ref", static_get1, static_set1)
|
||||||
.def_property_static("static_rw_copy", static_get2, static_set2, rvp_copy)
|
.def_property_static("static_rw_copy", static_get2, static_set2, rvp_copy)
|
||||||
.def_property_static("static_rw_func", py::cpp_function(static_get2, rvp_copy), static_set2)
|
.def_property_static("static_rw_func", py::cpp_function(static_get2, rvp_copy), static_set2)
|
||||||
|
// test_property_rvalue_policy
|
||||||
.def_property_readonly("rvalue", &TestPropRVP::get_rvalue)
|
.def_property_readonly("rvalue", &TestPropRVP::get_rvalue)
|
||||||
.def_property_readonly_static("static_rvalue", [](py::object) { return SimpleValue(); });
|
.def_property_readonly_static("static_rvalue", [](py::object) { return UserType(1); });
|
||||||
|
|
||||||
|
// test_metaclass_override
|
||||||
struct MetaclassOverride { };
|
struct MetaclassOverride { };
|
||||||
py::class_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type))
|
py::class_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type))
|
||||||
.def_property_readonly_static("readonly", [](py::object) { return 1; });
|
.def_property_readonly_static("readonly", [](py::object) { return 1; });
|
||||||
|
|
||||||
#if !defined(PYPY_VERSION)
|
#if !defined(PYPY_VERSION)
|
||||||
|
// test_dynamic_attributes
|
||||||
|
class DynamicClass {
|
||||||
|
public:
|
||||||
|
DynamicClass() { print_default_created(this); }
|
||||||
|
~DynamicClass() { print_destroyed(this); }
|
||||||
|
};
|
||||||
py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr())
|
py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr())
|
||||||
.def(py::init());
|
.def(py::init());
|
||||||
|
|
||||||
|
class CppDerivedDynamicClass : public DynamicClass { };
|
||||||
py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass")
|
py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass")
|
||||||
.def(py::init());
|
.def(py::init());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// test_noconvert_args
|
||||||
|
//
|
||||||
// Test converting. The ArgAlwaysConverts is just there to make the first no-conversion pass
|
// Test converting. The ArgAlwaysConverts is just there to make the first no-conversion pass
|
||||||
// fail so that our call always ends up happening via the second dispatch (the one that allows
|
// fail so that our call always ends up happening via the second dispatch (the one that allows
|
||||||
// some conversion).
|
// some conversion).
|
||||||
@ -363,6 +369,7 @@ test_initializer methods_and_attributes([](py::module &m) {
|
|||||||
m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i"));
|
m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i"));
|
||||||
m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert());
|
m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert());
|
||||||
|
|
||||||
|
// test_bad_arg_default
|
||||||
// Issue/PR #648: bad arg default debugging output
|
// Issue/PR #648: bad arg default debugging output
|
||||||
#if !defined(NDEBUG)
|
#if !defined(NDEBUG)
|
||||||
m.attr("debug_enabled") = true;
|
m.attr("debug_enabled") = true;
|
||||||
@ -371,13 +378,14 @@ test_initializer methods_and_attributes([](py::module &m) {
|
|||||||
#endif
|
#endif
|
||||||
m.def("bad_arg_def_named", []{
|
m.def("bad_arg_def_named", []{
|
||||||
auto m = py::module::import("pybind11_tests");
|
auto m = py::module::import("pybind11_tests");
|
||||||
m.def("should_fail", [](int, NotRegistered) {}, py::arg(), py::arg("a") = NotRegistered());
|
m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg("a") = UnregisteredType());
|
||||||
});
|
});
|
||||||
m.def("bad_arg_def_unnamed", []{
|
m.def("bad_arg_def_unnamed", []{
|
||||||
auto m = py::module::import("pybind11_tests");
|
auto m = py::module::import("pybind11_tests");
|
||||||
m.def("should_fail", [](int, NotRegistered) {}, py::arg(), py::arg() = NotRegistered());
|
m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// test_accepts_none
|
||||||
py::class_<NoneTester, std::shared_ptr<NoneTester>>(m, "NoneTester")
|
py::class_<NoneTester, std::shared_ptr<NoneTester>>(m, "NoneTester")
|
||||||
.def(py::init<>());
|
.def(py::init<>());
|
||||||
m.def("no_none1", &none1, py::arg().none(false));
|
m.def("no_none1", &none1, py::arg().none(false));
|
||||||
@ -391,6 +399,7 @@ test_initializer methods_and_attributes([](py::module &m) {
|
|||||||
m.def("ok_none4", &none4, py::arg().none(true));
|
m.def("ok_none4", &none4, py::arg().none(true));
|
||||||
m.def("ok_none5", &none5);
|
m.def("ok_none5", &none5);
|
||||||
|
|
||||||
|
// test_str_issue
|
||||||
// Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
|
// Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
|
||||||
py::class_<StrIssue>(m, "StrIssue")
|
py::class_<StrIssue>(m, "StrIssue")
|
||||||
.def(py::init<int>())
|
.def(py::init<int>())
|
||||||
@ -399,6 +408,8 @@ test_initializer methods_and_attributes([](py::module &m) {
|
|||||||
return "StrIssue[" + std::to_string(si.val) + "]"; }
|
return "StrIssue[" + std::to_string(si.val) + "]"; }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// test_unregistered_base_implementations
|
||||||
|
//
|
||||||
// Issues #854/910: incompatible function args when member function/pointer is in unregistered
|
// Issues #854/910: incompatible function args when member function/pointer is in unregistered
|
||||||
// base class The methods and member pointers below actually resolve to members/pointers in
|
// base class The methods and member pointers below actually resolve to members/pointers in
|
||||||
// UnregisteredBase; before this test/fix they would be registered via lambda with a first
|
// UnregisteredBase; before this test/fix they would be registered via lambda with a first
|
||||||
@ -410,8 +421,8 @@ test_initializer methods_and_attributes([](py::module &m) {
|
|||||||
.def_readwrite("rw_value", &RegisteredDerived::rw_value)
|
.def_readwrite("rw_value", &RegisteredDerived::rw_value)
|
||||||
.def_readonly("ro_value", &RegisteredDerived::ro_value)
|
.def_readonly("ro_value", &RegisteredDerived::ro_value)
|
||||||
// These should trigger a static_assert if uncommented
|
// These should trigger a static_assert if uncommented
|
||||||
//.def_readwrite("fails", &SimpleValue::value) // should trigger a static_assert if uncommented
|
//.def_readwrite("fails", &UserType::value) // should trigger a static_assert if uncommented
|
||||||
//.def_readonly("fails", &SimpleValue::value) // should trigger a static_assert if uncommented
|
//.def_readonly("fails", &UserType::value) // should trigger a static_assert if uncommented
|
||||||
.def_property("rw_value_prop", &RegisteredDerived::get_int, &RegisteredDerived::set_int)
|
.def_property("rw_value_prop", &RegisteredDerived::get_int, &RegisteredDerived::set_int)
|
||||||
.def_property_readonly("ro_value_prop", &RegisteredDerived::get_double)
|
.def_property_readonly("ro_value_prop", &RegisteredDerived::get_double)
|
||||||
// This one is in the registered class:
|
// This one is in the registered class:
|
||||||
@ -432,4 +443,4 @@ test_initializer methods_and_attributes([](py::module &m) {
|
|||||||
m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); },
|
m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); },
|
||||||
py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction)
|
py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction)
|
||||||
m.def("destruction_tester_cstats", &ConstructorStats::get<DestructionTester>, py::return_value_policy::reference);
|
m.def("destruction_tester_cstats", &ConstructorStats::get<DestructionTester>, py::return_value_policy::reference);
|
||||||
});
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from pybind11_tests import ExampleMandA, ConstructorStats
|
from pybind11_tests import methods_and_attributes as m
|
||||||
|
from pybind11_tests import ConstructorStats
|
||||||
|
|
||||||
|
|
||||||
def test_methods_and_attributes():
|
def test_methods_and_attributes():
|
||||||
instance1 = ExampleMandA()
|
instance1 = m.ExampleMandA()
|
||||||
instance2 = ExampleMandA(32)
|
instance2 = m.ExampleMandA(32)
|
||||||
|
|
||||||
instance1.add1(instance2)
|
instance1.add1(instance2)
|
||||||
instance1.add2(instance2)
|
instance1.add2(instance2)
|
||||||
@ -31,10 +32,13 @@ def test_methods_and_attributes():
|
|||||||
assert instance1.internal4() == 320
|
assert instance1.internal4() == 320
|
||||||
assert instance1.internal5() == 320
|
assert instance1.internal5() == 320
|
||||||
|
|
||||||
|
assert instance1.overloaded() == "()"
|
||||||
|
assert instance1.overloaded(0) == "(int)"
|
||||||
assert instance1.overloaded(1, 1.0) == "(int, float)"
|
assert instance1.overloaded(1, 1.0) == "(int, float)"
|
||||||
assert instance1.overloaded(2.0, 2) == "(float, int)"
|
assert instance1.overloaded(2.0, 2) == "(float, int)"
|
||||||
assert instance1.overloaded(3, 3) == "(int, int)"
|
assert instance1.overloaded(3, 3) == "(int, int)"
|
||||||
assert instance1.overloaded(4., 4.) == "(float, float)"
|
assert instance1.overloaded(4., 4.) == "(float, float)"
|
||||||
|
assert instance1.overloaded_const(-3) == "(int) const"
|
||||||
assert instance1.overloaded_const(5, 5.0) == "(int, float) const"
|
assert instance1.overloaded_const(5, 5.0) == "(int, float) const"
|
||||||
assert instance1.overloaded_const(6.0, 6) == "(float, int) const"
|
assert instance1.overloaded_const(6.0, 6) == "(float, int) const"
|
||||||
assert instance1.overloaded_const(7, 7) == "(int, int) const"
|
assert instance1.overloaded_const(7, 7) == "(int, int) const"
|
||||||
@ -48,7 +52,7 @@ def test_methods_and_attributes():
|
|||||||
instance1.value = 100
|
instance1.value = 100
|
||||||
assert str(instance1) == "ExampleMandA[value=100]"
|
assert str(instance1) == "ExampleMandA[value=100]"
|
||||||
|
|
||||||
cstats = ConstructorStats.get(ExampleMandA)
|
cstats = ConstructorStats.get(m.ExampleMandA)
|
||||||
assert cstats.alive() == 2
|
assert cstats.alive() == 2
|
||||||
del instance1, instance2
|
del instance1, instance2
|
||||||
assert cstats.alive() == 0
|
assert cstats.alive() == 0
|
||||||
@ -60,10 +64,25 @@ def test_methods_and_attributes():
|
|||||||
assert cstats.move_assignments == 0
|
assert cstats.move_assignments == 0
|
||||||
|
|
||||||
|
|
||||||
def test_properties():
|
def test_copy_method():
|
||||||
from pybind11_tests import TestProperties
|
"""Issue #443: calling copied methods fails in Python 3"""
|
||||||
|
|
||||||
instance = TestProperties()
|
m.ExampleMandA.add2c = m.ExampleMandA.add2
|
||||||
|
m.ExampleMandA.add2d = m.ExampleMandA.add2b
|
||||||
|
a = m.ExampleMandA(123)
|
||||||
|
assert a.value == 123
|
||||||
|
a.add2(m.ExampleMandA(-100))
|
||||||
|
assert a.value == 23
|
||||||
|
a.add2b(m.ExampleMandA(20))
|
||||||
|
assert a.value == 43
|
||||||
|
a.add2c(m.ExampleMandA(6))
|
||||||
|
assert a.value == 49
|
||||||
|
a.add2d(m.ExampleMandA(-7))
|
||||||
|
assert a.value == 42
|
||||||
|
|
||||||
|
|
||||||
|
def test_properties():
|
||||||
|
instance = m.TestProperties()
|
||||||
|
|
||||||
assert instance.def_readonly == 1
|
assert instance.def_readonly == 1
|
||||||
with pytest.raises(AttributeError):
|
with pytest.raises(AttributeError):
|
||||||
@ -80,122 +99,97 @@ def test_properties():
|
|||||||
assert instance.def_property == 3
|
assert instance.def_property == 3
|
||||||
|
|
||||||
|
|
||||||
def test_copy_method():
|
|
||||||
"""Issue #443: calling copied methods fails in Python 3"""
|
|
||||||
from pybind11_tests import ExampleMandA
|
|
||||||
|
|
||||||
ExampleMandA.add2c = ExampleMandA.add2
|
|
||||||
ExampleMandA.add2d = ExampleMandA.add2b
|
|
||||||
a = ExampleMandA(123)
|
|
||||||
assert a.value == 123
|
|
||||||
a.add2(ExampleMandA(-100))
|
|
||||||
assert a.value == 23
|
|
||||||
a.add2b(ExampleMandA(20))
|
|
||||||
assert a.value == 43
|
|
||||||
a.add2c(ExampleMandA(6))
|
|
||||||
assert a.value == 49
|
|
||||||
a.add2d(ExampleMandA(-7))
|
|
||||||
assert a.value == 42
|
|
||||||
|
|
||||||
|
|
||||||
def test_static_properties():
|
def test_static_properties():
|
||||||
from pybind11_tests import TestProperties as Type
|
assert m.TestProperties.def_readonly_static == 1
|
||||||
|
|
||||||
assert Type.def_readonly_static == 1
|
|
||||||
with pytest.raises(AttributeError) as excinfo:
|
with pytest.raises(AttributeError) as excinfo:
|
||||||
Type.def_readonly_static = 2
|
m.TestProperties.def_readonly_static = 2
|
||||||
assert "can't set attribute" in str(excinfo)
|
assert "can't set attribute" in str(excinfo)
|
||||||
|
|
||||||
Type.def_readwrite_static = 2
|
m.TestProperties.def_readwrite_static = 2
|
||||||
assert Type.def_readwrite_static == 2
|
assert m.TestProperties.def_readwrite_static == 2
|
||||||
|
|
||||||
assert Type.def_property_readonly_static == 2
|
assert m.TestProperties.def_property_readonly_static == 2
|
||||||
with pytest.raises(AttributeError) as excinfo:
|
with pytest.raises(AttributeError) as excinfo:
|
||||||
Type.def_property_readonly_static = 3
|
m.TestProperties.def_property_readonly_static = 3
|
||||||
assert "can't set attribute" in str(excinfo)
|
assert "can't set attribute" in str(excinfo)
|
||||||
|
|
||||||
Type.def_property_static = 3
|
m.TestProperties.def_property_static = 3
|
||||||
assert Type.def_property_static == 3
|
assert m.TestProperties.def_property_static == 3
|
||||||
|
|
||||||
# Static property read and write via instance
|
# Static property read and write via instance
|
||||||
instance = Type()
|
instance = m.TestProperties()
|
||||||
|
|
||||||
Type.def_readwrite_static = 0
|
m.TestProperties.def_readwrite_static = 0
|
||||||
assert Type.def_readwrite_static == 0
|
assert m.TestProperties.def_readwrite_static == 0
|
||||||
assert instance.def_readwrite_static == 0
|
assert instance.def_readwrite_static == 0
|
||||||
|
|
||||||
instance.def_readwrite_static = 2
|
instance.def_readwrite_static = 2
|
||||||
assert Type.def_readwrite_static == 2
|
assert m.TestProperties.def_readwrite_static == 2
|
||||||
assert instance.def_readwrite_static == 2
|
assert instance.def_readwrite_static == 2
|
||||||
|
|
||||||
# It should be possible to override properties in derived classes
|
# It should be possible to override properties in derived classes
|
||||||
from pybind11_tests import TestPropertiesOverride as TypeOverride
|
assert m.TestPropertiesOverride().def_readonly == 99
|
||||||
|
assert m.TestPropertiesOverride.def_readonly_static == 99
|
||||||
assert TypeOverride().def_readonly == 99
|
|
||||||
assert TypeOverride.def_readonly_static == 99
|
|
||||||
|
|
||||||
|
|
||||||
def test_static_cls():
|
def test_static_cls():
|
||||||
"""Static property getter and setters expect the type object as the their only argument"""
|
"""Static property getter and setters expect the type object as the their only argument"""
|
||||||
from pybind11_tests import TestProperties as Type
|
|
||||||
|
|
||||||
instance = Type()
|
instance = m.TestProperties()
|
||||||
assert Type.static_cls is Type
|
assert m.TestProperties.static_cls is m.TestProperties
|
||||||
assert instance.static_cls is Type
|
assert instance.static_cls is m.TestProperties
|
||||||
|
|
||||||
def check_self(self):
|
def check_self(self):
|
||||||
assert self is Type
|
assert self is m.TestProperties
|
||||||
|
|
||||||
Type.static_cls = check_self
|
m.TestProperties.static_cls = check_self
|
||||||
instance.static_cls = check_self
|
instance.static_cls = check_self
|
||||||
|
|
||||||
|
|
||||||
def test_metaclass_override():
|
def test_metaclass_override():
|
||||||
"""Overriding pybind11's default metaclass changes the behavior of `static_property`"""
|
"""Overriding pybind11's default metaclass changes the behavior of `static_property`"""
|
||||||
from pybind11_tests import MetaclassOverride
|
|
||||||
|
|
||||||
assert type(ExampleMandA).__name__ == "pybind11_type"
|
assert type(m.ExampleMandA).__name__ == "pybind11_type"
|
||||||
assert type(MetaclassOverride).__name__ == "type"
|
assert type(m.MetaclassOverride).__name__ == "type"
|
||||||
|
|
||||||
assert MetaclassOverride.readonly == 1
|
assert m.MetaclassOverride.readonly == 1
|
||||||
assert type(MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property"
|
assert type(m.MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property"
|
||||||
|
|
||||||
# Regular `type` replaces the property instead of calling `__set__()`
|
# Regular `type` replaces the property instead of calling `__set__()`
|
||||||
MetaclassOverride.readonly = 2
|
m.MetaclassOverride.readonly = 2
|
||||||
assert MetaclassOverride.readonly == 2
|
assert m.MetaclassOverride.readonly == 2
|
||||||
assert isinstance(MetaclassOverride.__dict__["readonly"], int)
|
assert isinstance(m.MetaclassOverride.__dict__["readonly"], int)
|
||||||
|
|
||||||
|
|
||||||
def test_no_mixed_overloads():
|
def test_no_mixed_overloads():
|
||||||
from pybind11_tests import debug_enabled
|
from pybind11_tests import debug_enabled
|
||||||
|
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
ExampleMandA.add_mixed_overloads1()
|
m.ExampleMandA.add_mixed_overloads1()
|
||||||
assert (str(excinfo.value) ==
|
assert (str(excinfo.value) ==
|
||||||
"overloading a method with both static and instance methods is not supported; " +
|
"overloading a method with both static and instance methods is not supported; " +
|
||||||
("compile in debug mode for more details" if not debug_enabled else
|
("compile in debug mode for more details" if not debug_enabled else
|
||||||
"error while attempting to bind static method ExampleMandA.overload_mixed1"
|
"error while attempting to bind static method ExampleMandA.overload_mixed1"
|
||||||
"() -> str")
|
"(arg0: float) -> str")
|
||||||
)
|
)
|
||||||
|
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
ExampleMandA.add_mixed_overloads2()
|
m.ExampleMandA.add_mixed_overloads2()
|
||||||
assert (str(excinfo.value) ==
|
assert (str(excinfo.value) ==
|
||||||
"overloading a method with both static and instance methods is not supported; " +
|
"overloading a method with both static and instance methods is not supported; " +
|
||||||
("compile in debug mode for more details" if not debug_enabled else
|
("compile in debug mode for more details" if not debug_enabled else
|
||||||
"error while attempting to bind instance method ExampleMandA.overload_mixed2"
|
"error while attempting to bind instance method ExampleMandA.overload_mixed2"
|
||||||
"(self: pybind11_tests.ExampleMandA, arg0: int, arg1: int) -> str")
|
"(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)"
|
||||||
|
" -> str")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
|
@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
|
||||||
def test_property_return_value_policies(access):
|
def test_property_return_value_policies(access):
|
||||||
from pybind11_tests import TestPropRVP
|
|
||||||
|
|
||||||
if not access.startswith("static"):
|
if not access.startswith("static"):
|
||||||
obj = TestPropRVP()
|
obj = m.TestPropRVP()
|
||||||
else:
|
else:
|
||||||
obj = TestPropRVP
|
obj = m.TestPropRVP
|
||||||
|
|
||||||
ref = getattr(obj, access + "_ref")
|
ref = getattr(obj, access + "_ref")
|
||||||
assert ref.value == 1
|
assert ref.value == 1
|
||||||
@ -216,30 +210,20 @@ def test_property_return_value_policies(access):
|
|||||||
|
|
||||||
def test_property_rvalue_policy():
|
def test_property_rvalue_policy():
|
||||||
"""When returning an rvalue, the return value policy is automatically changed from
|
"""When returning an rvalue, the return value policy is automatically changed from
|
||||||
`reference(_internal)` to `move`. The following would not work otherwise.
|
`reference(_internal)` to `move`. The following would not work otherwise."""
|
||||||
"""
|
|
||||||
from pybind11_tests import TestPropRVP
|
|
||||||
|
|
||||||
instance = TestPropRVP()
|
instance = m.TestPropRVP()
|
||||||
o = instance.rvalue
|
o = instance.rvalue
|
||||||
assert o.value == 1
|
assert o.value == 1
|
||||||
|
|
||||||
|
os = m.TestPropRVP.static_rvalue
|
||||||
def test_property_rvalue_policy_static():
|
assert os.value == 1
|
||||||
"""When returning an rvalue, the return value policy is automatically changed from
|
|
||||||
`reference(_internal)` to `move`. The following would not work otherwise.
|
|
||||||
"""
|
|
||||||
from pybind11_tests import TestPropRVP
|
|
||||||
o = TestPropRVP.static_rvalue
|
|
||||||
assert o.value == 1
|
|
||||||
|
|
||||||
|
|
||||||
# https://bitbucket.org/pypy/pypy/issues/2447
|
# https://bitbucket.org/pypy/pypy/issues/2447
|
||||||
@pytest.unsupported_on_pypy
|
@pytest.unsupported_on_pypy
|
||||||
def test_dynamic_attributes():
|
def test_dynamic_attributes():
|
||||||
from pybind11_tests import DynamicClass, CppDerivedDynamicClass
|
instance = m.DynamicClass()
|
||||||
|
|
||||||
instance = DynamicClass()
|
|
||||||
assert not hasattr(instance, "foo")
|
assert not hasattr(instance, "foo")
|
||||||
assert "foo" not in dir(instance)
|
assert "foo" not in dir(instance)
|
||||||
|
|
||||||
@ -259,16 +243,16 @@ def test_dynamic_attributes():
|
|||||||
instance.__dict__ = []
|
instance.__dict__ = []
|
||||||
assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'"
|
assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'"
|
||||||
|
|
||||||
cstats = ConstructorStats.get(DynamicClass)
|
cstats = ConstructorStats.get(m.DynamicClass)
|
||||||
assert cstats.alive() == 1
|
assert cstats.alive() == 1
|
||||||
del instance
|
del instance
|
||||||
assert cstats.alive() == 0
|
assert cstats.alive() == 0
|
||||||
|
|
||||||
# Derived classes should work as well
|
# Derived classes should work as well
|
||||||
class PythonDerivedDynamicClass(DynamicClass):
|
class PythonDerivedDynamicClass(m.DynamicClass):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for cls in CppDerivedDynamicClass, PythonDerivedDynamicClass:
|
for cls in m.CppDerivedDynamicClass, PythonDerivedDynamicClass:
|
||||||
derived = cls()
|
derived = cls()
|
||||||
derived.foobar = 100
|
derived.foobar = 100
|
||||||
assert derived.foobar == 100
|
assert derived.foobar == 100
|
||||||
@ -281,20 +265,18 @@ def test_dynamic_attributes():
|
|||||||
# https://bitbucket.org/pypy/pypy/issues/2447
|
# https://bitbucket.org/pypy/pypy/issues/2447
|
||||||
@pytest.unsupported_on_pypy
|
@pytest.unsupported_on_pypy
|
||||||
def test_cyclic_gc():
|
def test_cyclic_gc():
|
||||||
from pybind11_tests import DynamicClass
|
|
||||||
|
|
||||||
# One object references itself
|
# One object references itself
|
||||||
instance = DynamicClass()
|
instance = m.DynamicClass()
|
||||||
instance.circular_reference = instance
|
instance.circular_reference = instance
|
||||||
|
|
||||||
cstats = ConstructorStats.get(DynamicClass)
|
cstats = ConstructorStats.get(m.DynamicClass)
|
||||||
assert cstats.alive() == 1
|
assert cstats.alive() == 1
|
||||||
del instance
|
del instance
|
||||||
assert cstats.alive() == 0
|
assert cstats.alive() == 0
|
||||||
|
|
||||||
# Two object reference each other
|
# Two object reference each other
|
||||||
i1 = DynamicClass()
|
i1 = m.DynamicClass()
|
||||||
i2 = DynamicClass()
|
i2 = m.DynamicClass()
|
||||||
i1.cycle = i2
|
i1.cycle = i2
|
||||||
i2.cycle = i1
|
i2.cycle = i1
|
||||||
|
|
||||||
@ -304,8 +286,6 @@ def test_cyclic_gc():
|
|||||||
|
|
||||||
|
|
||||||
def test_noconvert_args(msg):
|
def test_noconvert_args(msg):
|
||||||
import pybind11_tests as m
|
|
||||||
|
|
||||||
a = m.ArgInspector()
|
a = m.ArgInspector()
|
||||||
assert msg(a.f("hi")) == """
|
assert msg(a.f("hi")) == """
|
||||||
loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
|
loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
|
||||||
@ -369,23 +349,23 @@ def test_noconvert_args(msg):
|
|||||||
|
|
||||||
|
|
||||||
def test_bad_arg_default(msg):
|
def test_bad_arg_default(msg):
|
||||||
from pybind11_tests import debug_enabled, bad_arg_def_named, bad_arg_def_unnamed
|
from pybind11_tests import debug_enabled
|
||||||
|
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
bad_arg_def_named()
|
m.bad_arg_def_named()
|
||||||
assert msg(excinfo.value) == (
|
assert msg(excinfo.value) == (
|
||||||
"arg(): could not convert default argument 'a: NotRegistered' in function 'should_fail' "
|
"arg(): could not convert default argument 'a: UnregisteredType' in function "
|
||||||
"into a Python object (type not registered yet?)"
|
"'should_fail' into a Python object (type not registered yet?)"
|
||||||
if debug_enabled else
|
if debug_enabled else
|
||||||
"arg(): could not convert default argument into a Python object (type not registered "
|
"arg(): could not convert default argument into a Python object (type not registered "
|
||||||
"yet?). Compile in debug mode for more information."
|
"yet?). Compile in debug mode for more information."
|
||||||
)
|
)
|
||||||
|
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
bad_arg_def_unnamed()
|
m.bad_arg_def_unnamed()
|
||||||
assert msg(excinfo.value) == (
|
assert msg(excinfo.value) == (
|
||||||
"arg(): could not convert default argument 'NotRegistered' in function 'should_fail' "
|
"arg(): could not convert default argument 'UnregisteredType' in function "
|
||||||
"into a Python object (type not registered yet?)"
|
"'should_fail' into a Python object (type not registered yet?)"
|
||||||
if debug_enabled else
|
if debug_enabled else
|
||||||
"arg(): could not convert default argument into a Python object (type not registered "
|
"arg(): could not convert default argument into a Python object (type not registered "
|
||||||
"yet?). Compile in debug mode for more information."
|
"yet?). Compile in debug mode for more information."
|
||||||
@ -393,76 +373,69 @@ def test_bad_arg_default(msg):
|
|||||||
|
|
||||||
|
|
||||||
def test_accepts_none(msg):
|
def test_accepts_none(msg):
|
||||||
from pybind11_tests import (NoneTester,
|
a = m.NoneTester()
|
||||||
no_none1, no_none2, no_none3, no_none4, no_none5,
|
assert m.no_none1(a) == 42
|
||||||
ok_none1, ok_none2, ok_none3, ok_none4, ok_none5)
|
assert m.no_none2(a) == 42
|
||||||
|
assert m.no_none3(a) == 42
|
||||||
a = NoneTester()
|
assert m.no_none4(a) == 42
|
||||||
assert no_none1(a) == 42
|
assert m.no_none5(a) == 42
|
||||||
assert no_none2(a) == 42
|
assert m.ok_none1(a) == 42
|
||||||
assert no_none3(a) == 42
|
assert m.ok_none2(a) == 42
|
||||||
assert no_none4(a) == 42
|
assert m.ok_none3(a) == 42
|
||||||
assert no_none5(a) == 42
|
assert m.ok_none4(a) == 42
|
||||||
assert ok_none1(a) == 42
|
assert m.ok_none5(a) == 42
|
||||||
assert ok_none2(a) == 42
|
|
||||||
assert ok_none3(a) == 42
|
|
||||||
assert ok_none4(a) == 42
|
|
||||||
assert ok_none5(a) == 42
|
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
no_none1(None)
|
m.no_none1(None)
|
||||||
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:
|
||||||
no_none2(None)
|
m.no_none2(None)
|
||||||
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:
|
||||||
no_none3(None)
|
m.no_none3(None)
|
||||||
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:
|
||||||
no_none4(None)
|
m.no_none4(None)
|
||||||
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:
|
||||||
no_none5(None)
|
m.no_none5(None)
|
||||||
assert "incompatible function arguments" in str(excinfo.value)
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
|
||||||
# The first one still raises because you can't pass None as a lvalue reference arg:
|
# The first one still raises because you can't pass None as a lvalue reference arg:
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
assert ok_none1(None) == -1
|
assert m.ok_none1(None) == -1
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
ok_none1(): incompatible function arguments. The following argument types are supported:
|
ok_none1(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: m.NoneTester) -> int
|
1. (arg0: m.methods_and_attributes.NoneTester) -> int
|
||||||
|
|
||||||
Invoked with: None
|
Invoked with: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The rest take the argument as pointer or holder, and accept None:
|
# The rest take the argument as pointer or holder, and accept None:
|
||||||
assert ok_none2(None) == -1
|
assert m.ok_none2(None) == -1
|
||||||
assert ok_none3(None) == -1
|
assert m.ok_none3(None) == -1
|
||||||
assert ok_none4(None) == -1
|
assert m.ok_none4(None) == -1
|
||||||
assert ok_none5(None) == -1
|
assert m.ok_none5(None) == -1
|
||||||
|
|
||||||
|
|
||||||
def test_str_issue(msg):
|
def test_str_issue(msg):
|
||||||
"""#283: __str__ called on uninitialized instance when constructor arguments invalid"""
|
"""#283: __str__ called on uninitialized instance when constructor arguments invalid"""
|
||||||
from pybind11_tests import StrIssue
|
|
||||||
|
|
||||||
assert str(StrIssue(3)) == "StrIssue[3]"
|
assert str(m.StrIssue(3)) == "StrIssue[3]"
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
str(StrIssue("no", "such", "constructor"))
|
str(m.StrIssue("no", "such", "constructor"))
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
__init__(): incompatible constructor arguments. The following argument types are supported:
|
__init__(): incompatible constructor arguments. The following argument types are supported:
|
||||||
1. m.StrIssue(arg0: int)
|
1. m.methods_and_attributes.StrIssue(arg0: int)
|
||||||
2. m.StrIssue()
|
2. m.methods_and_attributes.StrIssue()
|
||||||
|
|
||||||
Invoked with: 'no', 'such', 'constructor'
|
Invoked with: 'no', 'such', 'constructor'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def test_unregistered_base_implementations():
|
def test_unregistered_base_implementations():
|
||||||
from pybind11_tests import RegisteredDerived
|
a = m.RegisteredDerived()
|
||||||
|
|
||||||
a = RegisteredDerived()
|
|
||||||
a.do_nothing()
|
a.do_nothing()
|
||||||
assert a.rw_value == 42
|
assert a.rw_value == 42
|
||||||
assert a.ro_value == 1.25
|
assert a.ro_value == 1.25
|
||||||
@ -480,11 +453,8 @@ def test_unregistered_base_implementations():
|
|||||||
|
|
||||||
|
|
||||||
def test_custom_caster_destruction():
|
def test_custom_caster_destruction():
|
||||||
"""
|
"""Tests that returning a pointer to a type that gets converted with a custom type caster gets
|
||||||
Tests that returning a pointer to a type that gets converted with a custom type caster gets
|
destroyed when the function has py::return_value_policy::take_ownership policy applied."""
|
||||||
destroyed when the function has py::return_value_policy::take_ownership policy applied.
|
|
||||||
"""
|
|
||||||
import pybind11_tests as m
|
|
||||||
|
|
||||||
cstats = m.destruction_tester_cstats()
|
cstats = m.destruction_tester_cstats()
|
||||||
# This one *doesn't* have take_ownership: the pointer should be used but not destroyed:
|
# This one *doesn't* have take_ownership: the pointer should be used but not destroyed:
|
||||||
|
@ -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:
|
|
||||||
A(int v) : v(v) { print_created(this, v); }
|
|
||||||
~A() { print_destroyed(this); }
|
|
||||||
A(const A&) { print_copy_created(this); }
|
|
||||||
A& operator=(const A ©) { print_copy_assigned(this); v = copy.v; return *this; }
|
|
||||||
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 ©) { 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);
|
|
||||||
|
|
||||||
|
// test_reference_internal
|
||||||
|
class A {
|
||||||
|
public:
|
||||||
|
A(int v) : v(v) { print_created(this, v); }
|
||||||
|
~A() { print_destroyed(this); }
|
||||||
|
A(const A&) { print_copy_created(this); }
|
||||||
|
A& operator=(const A ©) { print_copy_assigned(this); v = copy.v; return *this; }
|
||||||
|
std::string toString() { return "A[" + std::to_string(v) + "]"; }
|
||||||
|
private:
|
||||||
|
int v;
|
||||||
|
};
|
||||||
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 ©) { 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) {
|
|||||||
|
|
||||||
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) {
|
|||||||
|
|
||||||
return failures;
|
return failures;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
@ -1,32 +1,34 @@
|
|||||||
|
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():
|
|||||||
|
|
||||||
|
|
||||||
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():
|
|||||||
|
|
||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 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) {
|
|||||||
"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) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
from pybind11_tests import numpy_array as m
|
||||||
|
|
||||||
pytestmark = pytest.requires_numpy
|
pytestmark = pytest.requires_numpy
|
||||||
|
|
||||||
@ -12,62 +13,55 @@ def arr():
|
|||||||
|
|
||||||
|
|
||||||
def test_array_attributes():
|
def test_array_attributes():
|
||||||
from pybind11_tests.array import (
|
|
||||||
ndim, shape, strides, writeable, size, itemsize, nbytes, owndata
|
|
||||||
)
|
|
||||||
|
|
||||||
a = np.array(0, 'f8')
|
a = np.array(0, 'f8')
|
||||||
assert ndim(a) == 0
|
assert m.ndim(a) == 0
|
||||||
assert all(shape(a) == [])
|
assert all(m.shape(a) == [])
|
||||||
assert all(strides(a) == [])
|
assert all(m.strides(a) == [])
|
||||||
with pytest.raises(IndexError) as excinfo:
|
with pytest.raises(IndexError) as excinfo:
|
||||||
shape(a, 0)
|
m.shape(a, 0)
|
||||||
assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)'
|
assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)'
|
||||||
with pytest.raises(IndexError) as excinfo:
|
with pytest.raises(IndexError) as excinfo:
|
||||||
strides(a, 0)
|
m.strides(a, 0)
|
||||||
assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)'
|
assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)'
|
||||||
assert writeable(a)
|
assert m.writeable(a)
|
||||||
assert size(a) == 1
|
assert m.size(a) == 1
|
||||||
assert itemsize(a) == 8
|
assert m.itemsize(a) == 8
|
||||||
assert nbytes(a) == 8
|
assert m.nbytes(a) == 8
|
||||||
assert owndata(a)
|
assert m.owndata(a)
|
||||||
|
|
||||||
a = np.array([[1, 2, 3], [4, 5, 6]], 'u2').view()
|
a = np.array([[1, 2, 3], [4, 5, 6]], 'u2').view()
|
||||||
a.flags.writeable = False
|
a.flags.writeable = False
|
||||||
assert ndim(a) == 2
|
assert m.ndim(a) == 2
|
||||||
assert all(shape(a) == [2, 3])
|
assert all(m.shape(a) == [2, 3])
|
||||||
assert shape(a, 0) == 2
|
assert m.shape(a, 0) == 2
|
||||||
assert shape(a, 1) == 3
|
assert m.shape(a, 1) == 3
|
||||||
assert all(strides(a) == [6, 2])
|
assert all(m.strides(a) == [6, 2])
|
||||||
assert strides(a, 0) == 6
|
assert m.strides(a, 0) == 6
|
||||||
assert strides(a, 1) == 2
|
assert m.strides(a, 1) == 2
|
||||||
with pytest.raises(IndexError) as excinfo:
|
with pytest.raises(IndexError) as excinfo:
|
||||||
shape(a, 2)
|
m.shape(a, 2)
|
||||||
assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)'
|
assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)'
|
||||||
with pytest.raises(IndexError) as excinfo:
|
with pytest.raises(IndexError) as excinfo:
|
||||||
strides(a, 2)
|
m.strides(a, 2)
|
||||||
assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)'
|
assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)'
|
||||||
assert not writeable(a)
|
assert not m.writeable(a)
|
||||||
assert size(a) == 6
|
assert m.size(a) == 6
|
||||||
assert itemsize(a) == 2
|
assert m.itemsize(a) == 2
|
||||||
assert nbytes(a) == 12
|
assert m.nbytes(a) == 12
|
||||||
assert not owndata(a)
|
assert not m.owndata(a)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)])
|
@pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)])
|
||||||
def test_index_offset(arr, args, ret):
|
def test_index_offset(arr, args, ret):
|
||||||
from pybind11_tests.array import index_at, index_at_t, offset_at, offset_at_t
|
assert m.index_at(arr, *args) == ret
|
||||||
assert index_at(arr, *args) == ret
|
assert m.index_at_t(arr, *args) == ret
|
||||||
assert index_at_t(arr, *args) == ret
|
assert m.offset_at(arr, *args) == ret * arr.dtype.itemsize
|
||||||
assert offset_at(arr, *args) == ret * arr.dtype.itemsize
|
assert m.offset_at_t(arr, *args) == ret * arr.dtype.itemsize
|
||||||
assert offset_at_t(arr, *args) == ret * arr.dtype.itemsize
|
|
||||||
|
|
||||||
|
|
||||||
def test_dim_check_fail(arr):
|
def test_dim_check_fail(arr):
|
||||||
from pybind11_tests.array import (index_at, index_at_t, offset_at, offset_at_t, data, data_t,
|
for func in (m.index_at, m.index_at_t, m.offset_at, m.offset_at_t, m.data, m.data_t,
|
||||||
mutate_data, mutate_data_t)
|
m.mutate_data, m.mutate_data_t):
|
||||||
for func in (index_at, index_at_t, offset_at, offset_at_t, data, data_t,
|
|
||||||
mutate_data, mutate_data_t):
|
|
||||||
with pytest.raises(IndexError) as excinfo:
|
with pytest.raises(IndexError) as excinfo:
|
||||||
func(arr, 1, 2, 3)
|
func(arr, 1, 2, 3)
|
||||||
assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)'
|
assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)'
|
||||||
@ -79,63 +73,53 @@ def test_dim_check_fail(arr):
|
|||||||
([0, 1], [2, 3, 4, 5, 6]),
|
([0, 1], [2, 3, 4, 5, 6]),
|
||||||
([1, 2], [6])])
|
([1, 2], [6])])
|
||||||
def test_data(arr, args, ret):
|
def test_data(arr, args, ret):
|
||||||
from pybind11_tests.array import data, data_t
|
|
||||||
from sys import byteorder
|
from sys import byteorder
|
||||||
assert all(data_t(arr, *args) == ret)
|
assert all(m.data_t(arr, *args) == ret)
|
||||||
assert all(data(arr, *args)[(0 if byteorder == 'little' else 1)::2] == ret)
|
assert all(m.data(arr, *args)[(0 if byteorder == 'little' else 1)::2] == ret)
|
||||||
assert all(data(arr, *args)[(1 if byteorder == 'little' else 0)::2] == 0)
|
assert all(m.data(arr, *args)[(1 if byteorder == 'little' else 0)::2] == 0)
|
||||||
|
|
||||||
|
|
||||||
def test_mutate_readonly(arr):
|
|
||||||
from pybind11_tests.array import mutate_data, mutate_data_t, mutate_at_t
|
|
||||||
arr.flags.writeable = False
|
|
||||||
for func, args in (mutate_data, ()), (mutate_data_t, ()), (mutate_at_t, (0, 0)):
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
|
||||||
func(arr, *args)
|
|
||||||
assert str(excinfo.value) == 'array is not writeable'
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('dim', [0, 1, 3])
|
@pytest.mark.parametrize('dim', [0, 1, 3])
|
||||||
def test_at_fail(arr, dim):
|
def test_at_fail(arr, dim):
|
||||||
from pybind11_tests.array import at_t, mutate_at_t
|
for func in m.at_t, m.mutate_at_t:
|
||||||
for func in at_t, mutate_at_t:
|
|
||||||
with pytest.raises(IndexError) as excinfo:
|
with pytest.raises(IndexError) as excinfo:
|
||||||
func(arr, *([0] * dim))
|
func(arr, *([0] * dim))
|
||||||
assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim)
|
assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim)
|
||||||
|
|
||||||
|
|
||||||
def test_at(arr):
|
def test_at(arr):
|
||||||
from pybind11_tests.array import at_t, mutate_at_t
|
assert m.at_t(arr, 0, 2) == 3
|
||||||
|
assert m.at_t(arr, 1, 0) == 4
|
||||||
|
|
||||||
assert at_t(arr, 0, 2) == 3
|
assert all(m.mutate_at_t(arr, 0, 2).ravel() == [1, 2, 4, 4, 5, 6])
|
||||||
assert at_t(arr, 1, 0) == 4
|
assert all(m.mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6])
|
||||||
|
|
||||||
assert all(mutate_at_t(arr, 0, 2).ravel() == [1, 2, 4, 4, 5, 6])
|
|
||||||
assert all(mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6])
|
def test_mutate_readonly(arr):
|
||||||
|
arr.flags.writeable = False
|
||||||
|
for func, args in (m.mutate_data, ()), (m.mutate_data_t, ()), (m.mutate_at_t, (0, 0)):
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
func(arr, *args)
|
||||||
|
assert str(excinfo.value) == 'array is not writeable'
|
||||||
|
|
||||||
|
|
||||||
def test_mutate_data(arr):
|
def test_mutate_data(arr):
|
||||||
from pybind11_tests.array import mutate_data, mutate_data_t
|
assert all(m.mutate_data(arr).ravel() == [2, 4, 6, 8, 10, 12])
|
||||||
|
assert all(m.mutate_data(arr).ravel() == [4, 8, 12, 16, 20, 24])
|
||||||
|
assert all(m.mutate_data(arr, 1).ravel() == [4, 8, 12, 32, 40, 48])
|
||||||
|
assert all(m.mutate_data(arr, 0, 1).ravel() == [4, 16, 24, 64, 80, 96])
|
||||||
|
assert all(m.mutate_data(arr, 1, 2).ravel() == [4, 16, 24, 64, 80, 192])
|
||||||
|
|
||||||
assert all(mutate_data(arr).ravel() == [2, 4, 6, 8, 10, 12])
|
assert all(m.mutate_data_t(arr).ravel() == [5, 17, 25, 65, 81, 193])
|
||||||
assert all(mutate_data(arr).ravel() == [4, 8, 12, 16, 20, 24])
|
assert all(m.mutate_data_t(arr).ravel() == [6, 18, 26, 66, 82, 194])
|
||||||
assert all(mutate_data(arr, 1).ravel() == [4, 8, 12, 32, 40, 48])
|
assert all(m.mutate_data_t(arr, 1).ravel() == [6, 18, 26, 67, 83, 195])
|
||||||
assert all(mutate_data(arr, 0, 1).ravel() == [4, 16, 24, 64, 80, 96])
|
assert all(m.mutate_data_t(arr, 0, 1).ravel() == [6, 19, 27, 68, 84, 196])
|
||||||
assert all(mutate_data(arr, 1, 2).ravel() == [4, 16, 24, 64, 80, 192])
|
assert all(m.mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197])
|
||||||
|
|
||||||
assert all(mutate_data_t(arr).ravel() == [5, 17, 25, 65, 81, 193])
|
|
||||||
assert all(mutate_data_t(arr).ravel() == [6, 18, 26, 66, 82, 194])
|
|
||||||
assert all(mutate_data_t(arr, 1).ravel() == [6, 18, 26, 67, 83, 195])
|
|
||||||
assert all(mutate_data_t(arr, 0, 1).ravel() == [6, 19, 27, 68, 84, 196])
|
|
||||||
assert all(mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197])
|
|
||||||
|
|
||||||
|
|
||||||
def test_bounds_check(arr):
|
def test_bounds_check(arr):
|
||||||
from pybind11_tests.array import (index_at, index_at_t, data, data_t,
|
for func in (m.index_at, m.index_at_t, m.data, m.data_t,
|
||||||
mutate_data, mutate_data_t, at_t, mutate_at_t)
|
m.mutate_data, m.mutate_data_t, m.at_t, m.mutate_at_t):
|
||||||
funcs = (index_at, index_at_t, data, data_t,
|
|
||||||
mutate_data, mutate_data_t, at_t, mutate_at_t)
|
|
||||||
for func in funcs:
|
|
||||||
with pytest.raises(IndexError) as excinfo:
|
with pytest.raises(IndexError) as excinfo:
|
||||||
func(arr, 2, 0)
|
func(arr, 2, 0)
|
||||||
assert str(excinfo.value) == 'index 2 is out of bounds for axis 0 with size 2'
|
assert str(excinfo.value) == 'index 2 is out of bounds for axis 0 with size 2'
|
||||||
@ -145,18 +129,13 @@ def test_bounds_check(arr):
|
|||||||
|
|
||||||
|
|
||||||
def test_make_c_f_array():
|
def test_make_c_f_array():
|
||||||
from pybind11_tests.array import (
|
assert m.make_c_array().flags.c_contiguous
|
||||||
make_c_array, make_f_array
|
assert not m.make_c_array().flags.f_contiguous
|
||||||
)
|
assert m.make_f_array().flags.f_contiguous
|
||||||
assert make_c_array().flags.c_contiguous
|
assert not m.make_f_array().flags.c_contiguous
|
||||||
assert not make_c_array().flags.f_contiguous
|
|
||||||
assert make_f_array().flags.f_contiguous
|
|
||||||
assert not make_f_array().flags.c_contiguous
|
|
||||||
|
|
||||||
|
|
||||||
def test_wrap():
|
def test_wrap():
|
||||||
from pybind11_tests.array import wrap
|
|
||||||
|
|
||||||
def assert_references(a, b, base=None):
|
def assert_references(a, b, base=None):
|
||||||
if base is None:
|
if base is None:
|
||||||
base = a
|
base = a
|
||||||
@ -178,40 +157,39 @@ def test_wrap():
|
|||||||
|
|
||||||
a1 = np.array([1, 2], dtype=np.int16)
|
a1 = np.array([1, 2], dtype=np.int16)
|
||||||
assert a1.flags.owndata and a1.base is None
|
assert a1.flags.owndata and a1.base is None
|
||||||
a2 = wrap(a1)
|
a2 = m.wrap(a1)
|
||||||
assert_references(a1, a2)
|
assert_references(a1, a2)
|
||||||
|
|
||||||
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='F')
|
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='F')
|
||||||
assert a1.flags.owndata and a1.base is None
|
assert a1.flags.owndata and a1.base is None
|
||||||
a2 = wrap(a1)
|
a2 = m.wrap(a1)
|
||||||
assert_references(a1, a2)
|
assert_references(a1, a2)
|
||||||
|
|
||||||
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='C')
|
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='C')
|
||||||
a1.flags.writeable = False
|
a1.flags.writeable = False
|
||||||
a2 = wrap(a1)
|
a2 = m.wrap(a1)
|
||||||
assert_references(a1, a2)
|
assert_references(a1, a2)
|
||||||
|
|
||||||
a1 = np.random.random((4, 4, 4))
|
a1 = np.random.random((4, 4, 4))
|
||||||
a2 = wrap(a1)
|
a2 = m.wrap(a1)
|
||||||
assert_references(a1, a2)
|
assert_references(a1, a2)
|
||||||
|
|
||||||
a1t = a1.transpose()
|
a1t = a1.transpose()
|
||||||
a2 = wrap(a1t)
|
a2 = m.wrap(a1t)
|
||||||
assert_references(a1t, a2, a1)
|
assert_references(a1t, a2, a1)
|
||||||
|
|
||||||
a1d = a1.diagonal()
|
a1d = a1.diagonal()
|
||||||
a2 = wrap(a1d)
|
a2 = m.wrap(a1d)
|
||||||
assert_references(a1d, a2, a1)
|
assert_references(a1d, a2, a1)
|
||||||
|
|
||||||
a1m = a1[::-1, ::-1, ::-1]
|
a1m = a1[::-1, ::-1, ::-1]
|
||||||
a2 = wrap(a1m)
|
a2 = m.wrap(a1m)
|
||||||
assert_references(a1m, a2, a1)
|
assert_references(a1m, a2, a1)
|
||||||
|
|
||||||
|
|
||||||
def test_numpy_view(capture):
|
def test_numpy_view(capture):
|
||||||
from pybind11_tests.array import ArrayClass
|
|
||||||
with capture:
|
with capture:
|
||||||
ac = ArrayClass()
|
ac = m.ArrayClass()
|
||||||
ac_view_1 = ac.numpy_view()
|
ac_view_1 = ac.numpy_view()
|
||||||
ac_view_2 = ac.numpy_view()
|
ac_view_2 = ac.numpy_view()
|
||||||
assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32))
|
assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32))
|
||||||
@ -238,29 +216,24 @@ def test_numpy_view(capture):
|
|||||||
|
|
||||||
@pytest.unsupported_on_pypy
|
@pytest.unsupported_on_pypy
|
||||||
def test_cast_numpy_int64_to_uint64():
|
def test_cast_numpy_int64_to_uint64():
|
||||||
from pybind11_tests.array import function_taking_uint64
|
m.function_taking_uint64(123)
|
||||||
function_taking_uint64(123)
|
m.function_taking_uint64(np.uint64(123))
|
||||||
function_taking_uint64(np.uint64(123))
|
|
||||||
|
|
||||||
|
|
||||||
def test_isinstance():
|
def test_isinstance():
|
||||||
from pybind11_tests.array import isinstance_untyped, isinstance_typed
|
assert m.isinstance_untyped(np.array([1, 2, 3]), "not an array")
|
||||||
|
assert m.isinstance_typed(np.array([1.0, 2.0, 3.0]))
|
||||||
assert isinstance_untyped(np.array([1, 2, 3]), "not an array")
|
|
||||||
assert isinstance_typed(np.array([1.0, 2.0, 3.0]))
|
|
||||||
|
|
||||||
|
|
||||||
def test_constructors():
|
def test_constructors():
|
||||||
from pybind11_tests.array import default_constructors, converting_constructors
|
defaults = m.default_constructors()
|
||||||
|
|
||||||
defaults = default_constructors()
|
|
||||||
for a in defaults.values():
|
for a in defaults.values():
|
||||||
assert a.size == 0
|
assert a.size == 0
|
||||||
assert defaults["array"].dtype == np.array([]).dtype
|
assert defaults["array"].dtype == np.array([]).dtype
|
||||||
assert defaults["array_t<int32>"].dtype == np.int32
|
assert defaults["array_t<int32>"].dtype == np.int32
|
||||||
assert defaults["array_t<double>"].dtype == np.float64
|
assert defaults["array_t<double>"].dtype == np.float64
|
||||||
|
|
||||||
results = converting_constructors([1, 2, 3])
|
results = m.converting_constructors([1, 2, 3])
|
||||||
for a in results.values():
|
for a in results.values():
|
||||||
np.testing.assert_array_equal(a, [1, 2, 3])
|
np.testing.assert_array_equal(a, [1, 2, 3])
|
||||||
assert results["array"].dtype == np.int_
|
assert results["array"].dtype == np.int_
|
||||||
@ -269,22 +242,20 @@ def test_constructors():
|
|||||||
|
|
||||||
|
|
||||||
def test_overload_resolution(msg):
|
def test_overload_resolution(msg):
|
||||||
from pybind11_tests.array import overloaded, overloaded2, overloaded3, overloaded4, overloaded5
|
|
||||||
|
|
||||||
# Exact overload matches:
|
# Exact overload matches:
|
||||||
assert overloaded(np.array([1], dtype='float64')) == 'double'
|
assert m.overloaded(np.array([1], dtype='float64')) == 'double'
|
||||||
assert overloaded(np.array([1], dtype='float32')) == 'float'
|
assert m.overloaded(np.array([1], dtype='float32')) == 'float'
|
||||||
assert overloaded(np.array([1], dtype='ushort')) == 'unsigned short'
|
assert m.overloaded(np.array([1], dtype='ushort')) == 'unsigned short'
|
||||||
assert overloaded(np.array([1], dtype='intc')) == 'int'
|
assert m.overloaded(np.array([1], dtype='intc')) == 'int'
|
||||||
assert overloaded(np.array([1], dtype='longlong')) == 'long long'
|
assert m.overloaded(np.array([1], dtype='longlong')) == 'long long'
|
||||||
assert overloaded(np.array([1], dtype='complex')) == 'double complex'
|
assert m.overloaded(np.array([1], dtype='complex')) == 'double complex'
|
||||||
assert overloaded(np.array([1], dtype='csingle')) == 'float complex'
|
assert m.overloaded(np.array([1], dtype='csingle')) == 'float complex'
|
||||||
|
|
||||||
# No exact match, should call first convertible version:
|
# No exact match, should call first convertible version:
|
||||||
assert overloaded(np.array([1], dtype='uint8')) == 'double'
|
assert m.overloaded(np.array([1], dtype='uint8')) == 'double'
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
overloaded("not an array")
|
m.overloaded("not an array")
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
overloaded(): incompatible function arguments. The following argument types are supported:
|
overloaded(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: numpy.ndarray[float64]) -> str
|
1. (arg0: numpy.ndarray[float64]) -> str
|
||||||
@ -298,14 +269,14 @@ def test_overload_resolution(msg):
|
|||||||
Invoked with: 'not an array'
|
Invoked with: 'not an array'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert overloaded2(np.array([1], dtype='float64')) == 'double'
|
assert m.overloaded2(np.array([1], dtype='float64')) == 'double'
|
||||||
assert overloaded2(np.array([1], dtype='float32')) == 'float'
|
assert m.overloaded2(np.array([1], dtype='float32')) == 'float'
|
||||||
assert overloaded2(np.array([1], dtype='complex64')) == 'float complex'
|
assert m.overloaded2(np.array([1], dtype='complex64')) == 'float complex'
|
||||||
assert overloaded2(np.array([1], dtype='complex128')) == 'double complex'
|
assert m.overloaded2(np.array([1], dtype='complex128')) == 'double complex'
|
||||||
assert overloaded2(np.array([1], dtype='float32')) == 'float'
|
assert m.overloaded2(np.array([1], dtype='float32')) == 'float'
|
||||||
|
|
||||||
assert overloaded3(np.array([1], dtype='float64')) == 'double'
|
assert m.overloaded3(np.array([1], dtype='float64')) == 'double'
|
||||||
assert overloaded3(np.array([1], dtype='intc')) == 'int'
|
assert m.overloaded3(np.array([1], dtype='intc')) == 'int'
|
||||||
expected_exc = """
|
expected_exc = """
|
||||||
overloaded3(): incompatible function arguments. The following argument types are supported:
|
overloaded3(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: numpy.ndarray[int32]) -> str
|
1. (arg0: numpy.ndarray[int32]) -> str
|
||||||
@ -314,122 +285,118 @@ def test_overload_resolution(msg):
|
|||||||
Invoked with:"""
|
Invoked with:"""
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
overloaded3(np.array([1], dtype='uintc'))
|
m.overloaded3(np.array([1], dtype='uintc'))
|
||||||
assert msg(excinfo.value) == expected_exc + " array([1], dtype=uint32)"
|
assert msg(excinfo.value) == expected_exc + " array([1], dtype=uint32)"
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
overloaded3(np.array([1], dtype='float32'))
|
m.overloaded3(np.array([1], dtype='float32'))
|
||||||
assert msg(excinfo.value) == expected_exc + " array([ 1.], dtype=float32)"
|
assert msg(excinfo.value) == expected_exc + " array([ 1.], dtype=float32)"
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
overloaded3(np.array([1], dtype='complex'))
|
m.overloaded3(np.array([1], dtype='complex'))
|
||||||
assert msg(excinfo.value) == expected_exc + " array([ 1.+0.j])"
|
assert msg(excinfo.value) == expected_exc + " array([ 1.+0.j])"
|
||||||
|
|
||||||
# Exact matches:
|
# Exact matches:
|
||||||
assert overloaded4(np.array([1], dtype='double')) == 'double'
|
assert m.overloaded4(np.array([1], dtype='double')) == 'double'
|
||||||
assert overloaded4(np.array([1], dtype='longlong')) == 'long long'
|
assert m.overloaded4(np.array([1], dtype='longlong')) == 'long long'
|
||||||
# Non-exact matches requiring conversion. Since float to integer isn't a
|
# Non-exact matches requiring conversion. Since float to integer isn't a
|
||||||
# save conversion, it should go to the double overload, but short can go to
|
# save conversion, it should go to the double overload, but short can go to
|
||||||
# either (and so should end up on the first-registered, the long long).
|
# either (and so should end up on the first-registered, the long long).
|
||||||
assert overloaded4(np.array([1], dtype='float32')) == 'double'
|
assert m.overloaded4(np.array([1], dtype='float32')) == 'double'
|
||||||
assert overloaded4(np.array([1], dtype='short')) == 'long long'
|
assert m.overloaded4(np.array([1], dtype='short')) == 'long long'
|
||||||
|
|
||||||
assert overloaded5(np.array([1], dtype='double')) == 'double'
|
assert m.overloaded5(np.array([1], dtype='double')) == 'double'
|
||||||
assert overloaded5(np.array([1], dtype='uintc')) == 'unsigned int'
|
assert m.overloaded5(np.array([1], dtype='uintc')) == 'unsigned int'
|
||||||
assert overloaded5(np.array([1], dtype='float32')) == 'unsigned int'
|
assert m.overloaded5(np.array([1], dtype='float32')) == 'unsigned int'
|
||||||
|
|
||||||
|
|
||||||
def test_greedy_string_overload(): # issue 685
|
def test_greedy_string_overload():
|
||||||
from pybind11_tests.array import issue685
|
"""Tests fix for #685 - ndarray shouldn't go to std::string overload"""
|
||||||
|
|
||||||
assert issue685("abc") == "string"
|
assert m.issue685("abc") == "string"
|
||||||
assert issue685(np.array([97, 98, 99], dtype='b')) == "array"
|
assert m.issue685(np.array([97, 98, 99], dtype='b')) == "array"
|
||||||
assert issue685(123) == "other"
|
assert m.issue685(123) == "other"
|
||||||
|
|
||||||
|
|
||||||
def test_array_unchecked_fixed_dims(msg):
|
def test_array_unchecked_fixed_dims(msg):
|
||||||
from pybind11_tests.array import (proxy_add2, proxy_init3F, proxy_init3, proxy_squared_L2_norm,
|
|
||||||
proxy_auxiliaries2, array_auxiliaries2)
|
|
||||||
|
|
||||||
z1 = np.array([[1, 2], [3, 4]], dtype='float64')
|
z1 = np.array([[1, 2], [3, 4]], dtype='float64')
|
||||||
proxy_add2(z1, 10)
|
m.proxy_add2(z1, 10)
|
||||||
assert np.all(z1 == [[11, 12], [13, 14]])
|
assert np.all(z1 == [[11, 12], [13, 14]])
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
proxy_add2(np.array([1., 2, 3]), 5.0)
|
m.proxy_add2(np.array([1., 2, 3]), 5.0)
|
||||||
assert msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2"
|
assert msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2"
|
||||||
|
|
||||||
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int')
|
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int')
|
||||||
assert np.all(proxy_init3(3.0) == expect_c)
|
assert np.all(m.proxy_init3(3.0) == expect_c)
|
||||||
expect_f = np.transpose(expect_c)
|
expect_f = np.transpose(expect_c)
|
||||||
assert np.all(proxy_init3F(3.0) == expect_f)
|
assert np.all(m.proxy_init3F(3.0) == expect_f)
|
||||||
|
|
||||||
assert proxy_squared_L2_norm(np.array(range(6))) == 55
|
assert m.proxy_squared_L2_norm(np.array(range(6))) == 55
|
||||||
assert proxy_squared_L2_norm(np.array(range(6), dtype="float64")) == 55
|
assert m.proxy_squared_L2_norm(np.array(range(6), dtype="float64")) == 55
|
||||||
|
|
||||||
assert proxy_auxiliaries2(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
|
assert m.proxy_auxiliaries2(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
|
||||||
assert proxy_auxiliaries2(z1) == array_auxiliaries2(z1)
|
assert m.proxy_auxiliaries2(z1) == m.array_auxiliaries2(z1)
|
||||||
|
|
||||||
|
|
||||||
def test_array_unchecked_dyn_dims(msg):
|
def test_array_unchecked_dyn_dims(msg):
|
||||||
from pybind11_tests.array import (proxy_add2_dyn, proxy_init3_dyn, proxy_auxiliaries2_dyn,
|
|
||||||
array_auxiliaries2)
|
|
||||||
z1 = np.array([[1, 2], [3, 4]], dtype='float64')
|
z1 = np.array([[1, 2], [3, 4]], dtype='float64')
|
||||||
proxy_add2_dyn(z1, 10)
|
m.proxy_add2_dyn(z1, 10)
|
||||||
assert np.all(z1 == [[11, 12], [13, 14]])
|
assert np.all(z1 == [[11, 12], [13, 14]])
|
||||||
|
|
||||||
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int')
|
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int')
|
||||||
assert np.all(proxy_init3_dyn(3.0) == expect_c)
|
assert np.all(m.proxy_init3_dyn(3.0) == expect_c)
|
||||||
|
|
||||||
assert proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
|
assert m.proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
|
||||||
assert proxy_auxiliaries2_dyn(z1) == array_auxiliaries2(z1)
|
assert m.proxy_auxiliaries2_dyn(z1) == m.array_auxiliaries2(z1)
|
||||||
|
|
||||||
|
|
||||||
def test_array_failure():
|
def test_array_failure():
|
||||||
from pybind11_tests.array import (array_fail_test, array_t_fail_test,
|
|
||||||
array_fail_test_negative_size)
|
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
array_fail_test()
|
m.array_fail_test()
|
||||||
assert str(excinfo.value) == 'cannot create a pybind11::array from a nullptr'
|
assert str(excinfo.value) == 'cannot create a pybind11::array from a nullptr'
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
array_t_fail_test()
|
m.array_t_fail_test()
|
||||||
assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr'
|
assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr'
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
array_fail_test_negative_size()
|
m.array_fail_test_negative_size()
|
||||||
assert str(excinfo.value) == 'negative dimensions are not allowed'
|
assert str(excinfo.value) == 'negative dimensions are not allowed'
|
||||||
|
|
||||||
|
|
||||||
def test_array_resize(msg):
|
def test_initializer_list():
|
||||||
from pybind11_tests.array import (array_reshape2, array_resize3)
|
assert m.array_initializer_list1().shape == (1,)
|
||||||
|
assert m.array_initializer_list2().shape == (1, 2)
|
||||||
|
assert m.array_initializer_list3().shape == (1, 2, 3)
|
||||||
|
assert m.array_initializer_list4().shape == (1, 2, 3, 4)
|
||||||
|
|
||||||
|
|
||||||
|
def test_array_resize(msg):
|
||||||
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='float64')
|
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='float64')
|
||||||
array_reshape2(a)
|
m.array_reshape2(a)
|
||||||
assert(a.size == 9)
|
assert(a.size == 9)
|
||||||
assert(np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
|
assert(np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
|
||||||
|
|
||||||
# total size change should succced with refcheck off
|
# total size change should succced with refcheck off
|
||||||
array_resize3(a, 4, False)
|
m.array_resize3(a, 4, False)
|
||||||
assert(a.size == 64)
|
assert(a.size == 64)
|
||||||
# ... and fail with refcheck on
|
# ... and fail with refcheck on
|
||||||
try:
|
try:
|
||||||
array_resize3(a, 3, True)
|
m.array_resize3(a, 3, True)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
assert(str(e).startswith("cannot resize an array"))
|
assert(str(e).startswith("cannot resize an array"))
|
||||||
# transposed array doesn't own data
|
# transposed array doesn't own data
|
||||||
b = a.transpose()
|
b = a.transpose()
|
||||||
try:
|
try:
|
||||||
array_resize3(b, 3, False)
|
m.array_resize3(b, 3, False)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
assert(str(e).startswith("cannot resize this array: it does not own its data"))
|
assert(str(e).startswith("cannot resize this array: it does not own its data"))
|
||||||
# ... but reshape should be fine
|
# ... but reshape should be fine
|
||||||
array_reshape2(b)
|
m.array_reshape2(b)
|
||||||
assert(b.shape == (8, 8))
|
assert(b.shape == (8, 8))
|
||||||
|
|
||||||
|
|
||||||
@pytest.unsupported_on_pypy
|
@pytest.unsupported_on_pypy
|
||||||
def test_array_create_and_resize(msg):
|
def test_array_create_and_resize(msg):
|
||||||
from pybind11_tests.array import create_and_resize
|
a = m.create_and_resize(2)
|
||||||
a = create_and_resize(2)
|
|
||||||
assert(a.size == 4)
|
assert(a.size == 4)
|
||||||
assert(np.all(a == 42.))
|
assert(np.all(a == 42.))
|
||||||
|
@ -156,90 +156,6 @@ py::array_t<S, 0> create_recarray(size_t n) {
|
|||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_format_unbound() {
|
|
||||||
return py::format_descriptor<UnboundStruct>::format();
|
|
||||||
}
|
|
||||||
|
|
||||||
py::array_t<NestedStruct, 0> create_nested(size_t n) {
|
|
||||||
auto arr = mkarray_via_buffer<NestedStruct>(n);
|
|
||||||
auto req = arr.request();
|
|
||||||
auto ptr = static_cast<NestedStruct*>(req.ptr);
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
|
||||||
SET_TEST_VALS(ptr[i].a, i);
|
|
||||||
SET_TEST_VALS(ptr[i].b, i + 1);
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
py::array_t<PartialNestedStruct, 0> create_partial_nested(size_t n) {
|
|
||||||
auto arr = mkarray_via_buffer<PartialNestedStruct>(n);
|
|
||||||
auto req = arr.request();
|
|
||||||
auto ptr = static_cast<PartialNestedStruct*>(req.ptr);
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
|
||||||
SET_TEST_VALS(ptr[i].a, i);
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
py::array_t<StringStruct, 0> create_string_array(bool non_empty) {
|
|
||||||
auto arr = mkarray_via_buffer<StringStruct>(non_empty ? 4 : 0);
|
|
||||||
if (non_empty) {
|
|
||||||
auto req = arr.request();
|
|
||||||
auto ptr = static_cast<StringStruct*>(req.ptr);
|
|
||||||
for (ssize_t i = 0; i < req.size * req.itemsize; i++)
|
|
||||||
static_cast<char*>(req.ptr)[i] = 0;
|
|
||||||
ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a';
|
|
||||||
ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a';
|
|
||||||
ptr[3].a[0] = 'a'; ptr[3].b[0] = 'a';
|
|
||||||
|
|
||||||
ptr[2].a[1] = 'b'; ptr[2].b[1] = 'b';
|
|
||||||
ptr[3].a[1] = 'b'; ptr[3].b[1] = 'b';
|
|
||||||
|
|
||||||
ptr[3].a[2] = 'c'; ptr[3].b[2] = 'c';
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
py::array_t<ArrayStruct, 0> create_array_array(size_t n) {
|
|
||||||
auto arr = mkarray_via_buffer<ArrayStruct>(n);
|
|
||||||
auto ptr = (ArrayStruct *) arr.mutable_data();
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
|
||||||
for (size_t j = 0; j < 3; j++)
|
|
||||||
for (size_t k = 0; k < 4; k++)
|
|
||||||
ptr[i].a[j][k] = char('A' + (i * 100 + j * 10 + k) % 26);
|
|
||||||
for (size_t j = 0; j < 2; j++)
|
|
||||||
ptr[i].b[j] = int32_t(i * 1000 + j);
|
|
||||||
for (size_t j = 0; j < 3; j++)
|
|
||||||
ptr[i].c[j] = uint8_t(i * 10 + j);
|
|
||||||
for (size_t j = 0; j < 4; j++)
|
|
||||||
for (size_t k = 0; k < 2; k++)
|
|
||||||
ptr[i].d[j][k] = float(i) * 100.0f + float(j) * 10.0f + float(k);
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
py::array_t<EnumStruct, 0> create_enum_array(size_t n) {
|
|
||||||
auto arr = mkarray_via_buffer<EnumStruct>(n);
|
|
||||||
auto ptr = (EnumStruct *) arr.mutable_data();
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
|
||||||
ptr[i].e1 = static_cast<E1>(-1 + ((int) i % 2) * 2);
|
|
||||||
ptr[i].e2 = static_cast<E2>(1 + (i % 2));
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
py::array_t<ComplexStruct, 0> create_complex_array(size_t n) {
|
|
||||||
auto arr = mkarray_via_buffer<ComplexStruct>(n);
|
|
||||||
auto ptr = (ComplexStruct *) arr.mutable_data();
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
|
||||||
ptr[i].cflt.real(float(i));
|
|
||||||
ptr[i].cflt.imag(float(i) + 0.25f);
|
|
||||||
ptr[i].cdbl.real(double(i) + 0.5);
|
|
||||||
ptr[i].cdbl.imag(double(i) + 0.75);
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
py::list print_recarray(py::array_t<S, 0> arr) {
|
py::list print_recarray(py::array_t<S, 0> arr) {
|
||||||
const auto req = arr.request();
|
const auto req = arr.request();
|
||||||
@ -253,45 +169,6 @@ py::list print_recarray(py::array_t<S, 0> arr) {
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
py::list print_format_descriptors() {
|
|
||||||
const auto fmts = {
|
|
||||||
py::format_descriptor<SimpleStruct>::format(),
|
|
||||||
py::format_descriptor<PackedStruct>::format(),
|
|
||||||
py::format_descriptor<NestedStruct>::format(),
|
|
||||||
py::format_descriptor<PartialStruct>::format(),
|
|
||||||
py::format_descriptor<PartialNestedStruct>::format(),
|
|
||||||
py::format_descriptor<StringStruct>::format(),
|
|
||||||
py::format_descriptor<ArrayStruct>::format(),
|
|
||||||
py::format_descriptor<EnumStruct>::format(),
|
|
||||||
py::format_descriptor<ComplexStruct>::format()
|
|
||||||
};
|
|
||||||
auto l = py::list();
|
|
||||||
for (const auto &fmt : fmts) {
|
|
||||||
l.append(py::cast(fmt));
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
py::list print_dtypes() {
|
|
||||||
const auto dtypes = {
|
|
||||||
py::str(py::dtype::of<SimpleStruct>()),
|
|
||||||
py::str(py::dtype::of<PackedStruct>()),
|
|
||||||
py::str(py::dtype::of<NestedStruct>()),
|
|
||||||
py::str(py::dtype::of<PartialStruct>()),
|
|
||||||
py::str(py::dtype::of<PartialNestedStruct>()),
|
|
||||||
py::str(py::dtype::of<StringStruct>()),
|
|
||||||
py::str(py::dtype::of<ArrayStruct>()),
|
|
||||||
py::str(py::dtype::of<EnumStruct>()),
|
|
||||||
py::str(py::dtype::of<StructWithUglyNames>()),
|
|
||||||
py::str(py::dtype::of<ComplexStruct>())
|
|
||||||
};
|
|
||||||
auto l = py::list();
|
|
||||||
for (const auto &s : dtypes) {
|
|
||||||
l.append(s);
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
py::array_t<int32_t, 0> test_array_ctors(int i) {
|
py::array_t<int32_t, 0> test_array_ctors(int i) {
|
||||||
using arr_t = py::array_t<int32_t, 0>;
|
using arr_t = py::array_t<int32_t, 0>;
|
||||||
|
|
||||||
@ -367,51 +244,9 @@ py::list test_dtype_ctors() {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TrailingPaddingStruct {
|
TEST_SUBMODULE(numpy_dtypes, m) {
|
||||||
int32_t a;
|
try { py::module::import("numpy"); }
|
||||||
char b;
|
catch (...) { return; }
|
||||||
};
|
|
||||||
|
|
||||||
py::dtype trailing_padding_dtype() {
|
|
||||||
return py::dtype::of<TrailingPaddingStruct>();
|
|
||||||
}
|
|
||||||
|
|
||||||
py::dtype buffer_to_dtype(py::buffer& buf) {
|
|
||||||
return py::dtype(buf.request());
|
|
||||||
}
|
|
||||||
|
|
||||||
py::list test_dtype_methods() {
|
|
||||||
py::list list;
|
|
||||||
auto dt1 = py::dtype::of<int32_t>();
|
|
||||||
auto dt2 = py::dtype::of<SimpleStruct>();
|
|
||||||
list.append(dt1); list.append(dt2);
|
|
||||||
list.append(py::bool_(dt1.has_fields())); list.append(py::bool_(dt2.has_fields()));
|
|
||||||
list.append(py::int_(dt1.itemsize())); list.append(py::int_(dt2.itemsize()));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CompareStruct {
|
|
||||||
bool x;
|
|
||||||
uint32_t y;
|
|
||||||
float z;
|
|
||||||
};
|
|
||||||
|
|
||||||
py::list test_compare_buffer_info() {
|
|
||||||
py::list list;
|
|
||||||
list.append(py::bool_(py::detail::compare_buffer_info<float>::compare(py::buffer_info(nullptr, sizeof(float), "f", 1))));
|
|
||||||
list.append(py::bool_(py::detail::compare_buffer_info<unsigned>::compare(py::buffer_info(nullptr, sizeof(int), "I", 1))));
|
|
||||||
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), "l", 1))));
|
|
||||||
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), sizeof(long) == sizeof(int) ? "i" : "q", 1))));
|
|
||||||
list.append(py::bool_(py::detail::compare_buffer_info<CompareStruct>::compare(py::buffer_info(nullptr, sizeof(CompareStruct), "T{?:x:3xI:y:f:z:}", 1))));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
test_initializer numpy_dtypes([](py::module &m) {
|
|
||||||
try {
|
|
||||||
py::module::import("numpy");
|
|
||||||
} catch (...) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// typeinfo may be registered before the dtype descriptor for scalar casts to work...
|
// typeinfo may be registered before the dtype descriptor for scalar casts to work...
|
||||||
py::class_<SimpleStruct>(m, "SimpleStruct");
|
py::class_<SimpleStruct>(m, "SimpleStruct");
|
||||||
@ -425,8 +260,6 @@ test_initializer numpy_dtypes([](py::module &m) {
|
|||||||
PYBIND11_NUMPY_DTYPE(ArrayStruct, a, b, c, d);
|
PYBIND11_NUMPY_DTYPE(ArrayStruct, a, b, c, d);
|
||||||
PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2);
|
PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2);
|
||||||
PYBIND11_NUMPY_DTYPE(ComplexStruct, cflt, cdbl);
|
PYBIND11_NUMPY_DTYPE(ComplexStruct, cflt, cdbl);
|
||||||
PYBIND11_NUMPY_DTYPE(TrailingPaddingStruct, a, b);
|
|
||||||
PYBIND11_NUMPY_DTYPE(CompareStruct, x, y, z);
|
|
||||||
|
|
||||||
// ... or after
|
// ... or after
|
||||||
py::class_<PackedStruct>(m, "PackedStruct");
|
py::class_<PackedStruct>(m, "PackedStruct");
|
||||||
@ -438,35 +271,181 @@ test_initializer numpy_dtypes([](py::module &m) {
|
|||||||
// struct NotPOD { std::string v; NotPOD() : v("hi") {}; };
|
// struct NotPOD { std::string v; NotPOD() : v("hi") {}; };
|
||||||
// PYBIND11_NUMPY_DTYPE(NotPOD, v);
|
// PYBIND11_NUMPY_DTYPE(NotPOD, v);
|
||||||
|
|
||||||
|
// test_recarray, test_scalar_conversion
|
||||||
m.def("create_rec_simple", &create_recarray<SimpleStruct>);
|
m.def("create_rec_simple", &create_recarray<SimpleStruct>);
|
||||||
m.def("create_rec_packed", &create_recarray<PackedStruct>);
|
m.def("create_rec_packed", &create_recarray<PackedStruct>);
|
||||||
m.def("create_rec_nested", &create_nested);
|
m.def("create_rec_nested", [](size_t n) { // test_signature
|
||||||
|
py::array_t<NestedStruct, 0> arr = mkarray_via_buffer<NestedStruct>(n);
|
||||||
|
auto req = arr.request();
|
||||||
|
auto ptr = static_cast<NestedStruct*>(req.ptr);
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
SET_TEST_VALS(ptr[i].a, i);
|
||||||
|
SET_TEST_VALS(ptr[i].b, i + 1);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
});
|
||||||
m.def("create_rec_partial", &create_recarray<PartialStruct>);
|
m.def("create_rec_partial", &create_recarray<PartialStruct>);
|
||||||
m.def("create_rec_partial_nested", &create_partial_nested);
|
m.def("create_rec_partial_nested", [](size_t n) {
|
||||||
m.def("print_format_descriptors", &print_format_descriptors);
|
py::array_t<PartialNestedStruct, 0> arr = mkarray_via_buffer<PartialNestedStruct>(n);
|
||||||
|
auto req = arr.request();
|
||||||
|
auto ptr = static_cast<PartialNestedStruct*>(req.ptr);
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
SET_TEST_VALS(ptr[i].a, i);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
});
|
||||||
m.def("print_rec_simple", &print_recarray<SimpleStruct>);
|
m.def("print_rec_simple", &print_recarray<SimpleStruct>);
|
||||||
m.def("print_rec_packed", &print_recarray<PackedStruct>);
|
m.def("print_rec_packed", &print_recarray<PackedStruct>);
|
||||||
m.def("print_rec_nested", &print_recarray<NestedStruct>);
|
m.def("print_rec_nested", &print_recarray<NestedStruct>);
|
||||||
m.def("print_dtypes", &print_dtypes);
|
|
||||||
m.def("get_format_unbound", &get_format_unbound);
|
// test_format_descriptors
|
||||||
m.def("create_string_array", &create_string_array);
|
m.def("get_format_unbound", []() { return py::format_descriptor<UnboundStruct>::format(); });
|
||||||
m.def("print_string_array", &print_recarray<StringStruct>);
|
m.def("print_format_descriptors", []() {
|
||||||
m.def("create_array_array", &create_array_array);
|
py::list l;
|
||||||
m.def("print_array_array", &print_recarray<ArrayStruct>);
|
for (const auto &fmt : {
|
||||||
m.def("create_enum_array", &create_enum_array);
|
py::format_descriptor<SimpleStruct>::format(),
|
||||||
m.def("print_enum_array", &print_recarray<EnumStruct>);
|
py::format_descriptor<PackedStruct>::format(),
|
||||||
m.def("create_complex_array", &create_complex_array);
|
py::format_descriptor<NestedStruct>::format(),
|
||||||
m.def("print_complex_array", &print_recarray<ComplexStruct>);
|
py::format_descriptor<PartialStruct>::format(),
|
||||||
m.def("test_array_ctors", &test_array_ctors);
|
py::format_descriptor<PartialNestedStruct>::format(),
|
||||||
|
py::format_descriptor<StringStruct>::format(),
|
||||||
|
py::format_descriptor<ArrayStruct>::format(),
|
||||||
|
py::format_descriptor<EnumStruct>::format(),
|
||||||
|
py::format_descriptor<ComplexStruct>::format()
|
||||||
|
}) {
|
||||||
|
l.append(py::cast(fmt));
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
});
|
||||||
|
|
||||||
|
// test_dtype
|
||||||
|
m.def("print_dtypes", []() {
|
||||||
|
py::list l;
|
||||||
|
for (const py::handle &d : {
|
||||||
|
py::dtype::of<SimpleStruct>(),
|
||||||
|
py::dtype::of<PackedStruct>(),
|
||||||
|
py::dtype::of<NestedStruct>(),
|
||||||
|
py::dtype::of<PartialStruct>(),
|
||||||
|
py::dtype::of<PartialNestedStruct>(),
|
||||||
|
py::dtype::of<StringStruct>(),
|
||||||
|
py::dtype::of<ArrayStruct>(),
|
||||||
|
py::dtype::of<EnumStruct>(),
|
||||||
|
py::dtype::of<StructWithUglyNames>(),
|
||||||
|
py::dtype::of<ComplexStruct>()
|
||||||
|
})
|
||||||
|
l.append(py::str(d));
|
||||||
|
return l;
|
||||||
|
});
|
||||||
m.def("test_dtype_ctors", &test_dtype_ctors);
|
m.def("test_dtype_ctors", &test_dtype_ctors);
|
||||||
m.def("test_dtype_methods", &test_dtype_methods);
|
m.def("test_dtype_methods", []() {
|
||||||
m.def("compare_buffer_info", &test_compare_buffer_info);
|
py::list list;
|
||||||
m.def("trailing_padding_dtype", &trailing_padding_dtype);
|
auto dt1 = py::dtype::of<int32_t>();
|
||||||
m.def("buffer_to_dtype", &buffer_to_dtype);
|
auto dt2 = py::dtype::of<SimpleStruct>();
|
||||||
|
list.append(dt1); list.append(dt2);
|
||||||
|
list.append(py::bool_(dt1.has_fields())); list.append(py::bool_(dt2.has_fields()));
|
||||||
|
list.append(py::int_(dt1.itemsize())); list.append(py::int_(dt2.itemsize()));
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
struct TrailingPaddingStruct {
|
||||||
|
int32_t a;
|
||||||
|
char b;
|
||||||
|
};
|
||||||
|
PYBIND11_NUMPY_DTYPE(TrailingPaddingStruct, a, b);
|
||||||
|
m.def("trailing_padding_dtype", []() { return py::dtype::of<TrailingPaddingStruct>(); });
|
||||||
|
|
||||||
|
// test_string_array
|
||||||
|
m.def("create_string_array", [](bool non_empty) {
|
||||||
|
py::array_t<StringStruct, 0> arr = mkarray_via_buffer<StringStruct>(non_empty ? 4 : 0);
|
||||||
|
if (non_empty) {
|
||||||
|
auto req = arr.request();
|
||||||
|
auto ptr = static_cast<StringStruct*>(req.ptr);
|
||||||
|
for (ssize_t i = 0; i < req.size * req.itemsize; i++)
|
||||||
|
static_cast<char*>(req.ptr)[i] = 0;
|
||||||
|
ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a';
|
||||||
|
ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a';
|
||||||
|
ptr[3].a[0] = 'a'; ptr[3].b[0] = 'a';
|
||||||
|
|
||||||
|
ptr[2].a[1] = 'b'; ptr[2].b[1] = 'b';
|
||||||
|
ptr[3].a[1] = 'b'; ptr[3].b[1] = 'b';
|
||||||
|
|
||||||
|
ptr[3].a[2] = 'c'; ptr[3].b[2] = 'c';
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
});
|
||||||
|
m.def("print_string_array", &print_recarray<StringStruct>);
|
||||||
|
|
||||||
|
// test_array_array
|
||||||
|
m.def("create_array_array", [](size_t n) {
|
||||||
|
py::array_t<ArrayStruct, 0> arr = mkarray_via_buffer<ArrayStruct>(n);
|
||||||
|
auto ptr = (ArrayStruct *) arr.mutable_data();
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
for (size_t j = 0; j < 3; j++)
|
||||||
|
for (size_t k = 0; k < 4; k++)
|
||||||
|
ptr[i].a[j][k] = char('A' + (i * 100 + j * 10 + k) % 26);
|
||||||
|
for (size_t j = 0; j < 2; j++)
|
||||||
|
ptr[i].b[j] = int32_t(i * 1000 + j);
|
||||||
|
for (size_t j = 0; j < 3; j++)
|
||||||
|
ptr[i].c[j] = uint8_t(i * 10 + j);
|
||||||
|
for (size_t j = 0; j < 4; j++)
|
||||||
|
for (size_t k = 0; k < 2; k++)
|
||||||
|
ptr[i].d[j][k] = float(i) * 100.0f + float(j) * 10.0f + float(k);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
});
|
||||||
|
m.def("print_array_array", &print_recarray<ArrayStruct>);
|
||||||
|
|
||||||
|
// test_enum_array
|
||||||
|
m.def("create_enum_array", [](size_t n) {
|
||||||
|
py::array_t<EnumStruct, 0> arr = mkarray_via_buffer<EnumStruct>(n);
|
||||||
|
auto ptr = (EnumStruct *) arr.mutable_data();
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
ptr[i].e1 = static_cast<E1>(-1 + ((int) i % 2) * 2);
|
||||||
|
ptr[i].e2 = static_cast<E2>(1 + (i % 2));
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
});
|
||||||
|
m.def("print_enum_array", &print_recarray<EnumStruct>);
|
||||||
|
|
||||||
|
// test_complex_array
|
||||||
|
m.def("create_complex_array", [](size_t n) {
|
||||||
|
py::array_t<ComplexStruct, 0> arr = mkarray_via_buffer<ComplexStruct>(n);
|
||||||
|
auto ptr = (ComplexStruct *) arr.mutable_data();
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
ptr[i].cflt.real(float(i));
|
||||||
|
ptr[i].cflt.imag(float(i) + 0.25f);
|
||||||
|
ptr[i].cdbl.real(double(i) + 0.5);
|
||||||
|
ptr[i].cdbl.imag(double(i) + 0.75);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
});
|
||||||
|
m.def("print_complex_array", &print_recarray<ComplexStruct>);
|
||||||
|
|
||||||
|
// test_array_constructors
|
||||||
|
m.def("test_array_ctors", &test_array_ctors);
|
||||||
|
|
||||||
|
// test_compare_buffer_info
|
||||||
|
struct CompareStruct {
|
||||||
|
bool x;
|
||||||
|
uint32_t y;
|
||||||
|
float z;
|
||||||
|
};
|
||||||
|
PYBIND11_NUMPY_DTYPE(CompareStruct, x, y, z);
|
||||||
|
m.def("compare_buffer_info", []() {
|
||||||
|
py::list list;
|
||||||
|
list.append(py::bool_(py::detail::compare_buffer_info<float>::compare(py::buffer_info(nullptr, sizeof(float), "f", 1))));
|
||||||
|
list.append(py::bool_(py::detail::compare_buffer_info<unsigned>::compare(py::buffer_info(nullptr, sizeof(int), "I", 1))));
|
||||||
|
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), "l", 1))));
|
||||||
|
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), sizeof(long) == sizeof(int) ? "i" : "q", 1))));
|
||||||
|
list.append(py::bool_(py::detail::compare_buffer_info<CompareStruct>::compare(py::buffer_info(nullptr, sizeof(CompareStruct), "T{?:x:3xI:y:f:z:}", 1))));
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
m.def("buffer_to_dtype", [](py::buffer& buf) { return py::dtype(buf.request()); });
|
||||||
|
|
||||||
|
// test_scalar_conversion
|
||||||
m.def("f_simple", [](SimpleStruct s) { return s.uint_ * 10; });
|
m.def("f_simple", [](SimpleStruct s) { return s.uint_ * 10; });
|
||||||
m.def("f_packed", [](PackedStruct s) { return s.uint_ * 10; });
|
m.def("f_packed", [](PackedStruct s) { return s.uint_ * 10; });
|
||||||
m.def("f_nested", [](NestedStruct s) { return s.a.uint_ * 10; });
|
m.def("f_nested", [](NestedStruct s) { return s.a.uint_ * 10; });
|
||||||
m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
|
|
||||||
});
|
|
||||||
|
|
||||||
#undef PYBIND11_PACKED
|
// test_register_dtype
|
||||||
|
m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import re
|
import re
|
||||||
import pytest
|
import pytest
|
||||||
|
from pybind11_tests import numpy_dtypes as m
|
||||||
|
|
||||||
pytestmark = pytest.requires_numpy
|
pytestmark = pytest.requires_numpy
|
||||||
|
|
||||||
@ -65,10 +66,8 @@ def assert_equal(actual, expected_data, expected_dtype):
|
|||||||
|
|
||||||
|
|
||||||
def test_format_descriptors():
|
def test_format_descriptors():
|
||||||
from pybind11_tests import get_format_unbound, print_format_descriptors
|
|
||||||
|
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
get_format_unbound()
|
m.get_format_unbound()
|
||||||
assert re.match('^NumPy type info missing for .*UnboundStruct.*$', str(excinfo.value))
|
assert re.match('^NumPy type info missing for .*UnboundStruct.*$', str(excinfo.value))
|
||||||
|
|
||||||
ld = np.dtype('longdouble')
|
ld = np.dtype('longdouble')
|
||||||
@ -79,7 +78,7 @@ def test_format_descriptors():
|
|||||||
str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) +
|
str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) +
|
||||||
"xg:ldbl_:}")
|
"xg:ldbl_:}")
|
||||||
nested_extra = str(max(8, ld.alignment))
|
nested_extra = str(max(8, ld.alignment))
|
||||||
assert print_format_descriptors() == [
|
assert m.print_format_descriptors() == [
|
||||||
ss_fmt,
|
ss_fmt,
|
||||||
"^T{?:bool_:I:uint_:f:float_:g:ldbl_:}",
|
"^T{?:bool_:I:uint_:f:float_:g:ldbl_:}",
|
||||||
"^T{" + ss_fmt + ":a:^T{?:bool_:I:uint_:f:float_:g:ldbl_:}:b:}",
|
"^T{" + ss_fmt + ":a:^T{?:bool_:I:uint_:f:float_:g:ldbl_:}:b:}",
|
||||||
@ -93,12 +92,10 @@ def test_format_descriptors():
|
|||||||
|
|
||||||
|
|
||||||
def test_dtype(simple_dtype):
|
def test_dtype(simple_dtype):
|
||||||
from pybind11_tests import (print_dtypes, test_dtype_ctors, test_dtype_methods,
|
|
||||||
trailing_padding_dtype, buffer_to_dtype)
|
|
||||||
from sys import byteorder
|
from sys import byteorder
|
||||||
e = '<' if byteorder == 'little' else '>'
|
e = '<' if byteorder == 'little' else '>'
|
||||||
|
|
||||||
assert print_dtypes() == [
|
assert m.print_dtypes() == [
|
||||||
simple_dtype_fmt(),
|
simple_dtype_fmt(),
|
||||||
packed_dtype_fmt(),
|
packed_dtype_fmt(),
|
||||||
"[('a', {}), ('b', {})]".format(simple_dtype_fmt(), packed_dtype_fmt()),
|
"[('a', {}), ('b', {})]".format(simple_dtype_fmt(), packed_dtype_fmt()),
|
||||||
@ -116,23 +113,19 @@ def test_dtype(simple_dtype):
|
|||||||
d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'],
|
d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'],
|
||||||
'offsets': [1, 10], 'itemsize': 20})
|
'offsets': [1, 10], 'itemsize': 20})
|
||||||
d2 = np.dtype([('a', 'i4'), ('b', 'f4')])
|
d2 = np.dtype([('a', 'i4'), ('b', 'f4')])
|
||||||
assert test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'),
|
assert m.test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'),
|
||||||
np.dtype('bool'), d1, d1, np.dtype('uint32'), d2]
|
np.dtype('bool'), d1, d1, np.dtype('uint32'), d2]
|
||||||
|
|
||||||
assert test_dtype_methods() == [np.dtype('int32'), simple_dtype, False, True,
|
assert m.test_dtype_methods() == [np.dtype('int32'), simple_dtype, False, True,
|
||||||
np.dtype('int32').itemsize, simple_dtype.itemsize]
|
np.dtype('int32').itemsize, simple_dtype.itemsize]
|
||||||
|
|
||||||
assert trailing_padding_dtype() == buffer_to_dtype(np.zeros(1, trailing_padding_dtype()))
|
assert m.trailing_padding_dtype() == m.buffer_to_dtype(np.zeros(1, m.trailing_padding_dtype()))
|
||||||
|
|
||||||
|
|
||||||
def test_recarray(simple_dtype, packed_dtype):
|
def test_recarray(simple_dtype, packed_dtype):
|
||||||
from pybind11_tests import (create_rec_simple, create_rec_packed, create_rec_nested,
|
|
||||||
print_rec_simple, print_rec_packed, print_rec_nested,
|
|
||||||
create_rec_partial, create_rec_partial_nested)
|
|
||||||
|
|
||||||
elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)]
|
elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)]
|
||||||
|
|
||||||
for func, dtype in [(create_rec_simple, simple_dtype), (create_rec_packed, packed_dtype)]:
|
for func, dtype in [(m.create_rec_simple, simple_dtype), (m.create_rec_packed, packed_dtype)]:
|
||||||
arr = func(0)
|
arr = func(0)
|
||||||
assert arr.dtype == dtype
|
assert arr.dtype == dtype
|
||||||
assert_equal(arr, [], simple_dtype)
|
assert_equal(arr, [], simple_dtype)
|
||||||
@ -144,13 +137,13 @@ def test_recarray(simple_dtype, packed_dtype):
|
|||||||
assert_equal(arr, elements, packed_dtype)
|
assert_equal(arr, elements, packed_dtype)
|
||||||
|
|
||||||
if dtype == simple_dtype:
|
if dtype == simple_dtype:
|
||||||
assert print_rec_simple(arr) == [
|
assert m.print_rec_simple(arr) == [
|
||||||
"s:0,0,0,-0",
|
"s:0,0,0,-0",
|
||||||
"s:1,1,1.5,-2.5",
|
"s:1,1,1.5,-2.5",
|
||||||
"s:0,2,3,-5"
|
"s:0,2,3,-5"
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
assert print_rec_packed(arr) == [
|
assert m.print_rec_packed(arr) == [
|
||||||
"p:0,0,0,-0",
|
"p:0,0,0,-0",
|
||||||
"p:1,1,1.5,-2.5",
|
"p:1,1,1.5,-2.5",
|
||||||
"p:0,2,3,-5"
|
"p:0,2,3,-5"
|
||||||
@ -158,22 +151,22 @@ def test_recarray(simple_dtype, packed_dtype):
|
|||||||
|
|
||||||
nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)])
|
nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)])
|
||||||
|
|
||||||
arr = create_rec_nested(0)
|
arr = m.create_rec_nested(0)
|
||||||
assert arr.dtype == nested_dtype
|
assert arr.dtype == nested_dtype
|
||||||
assert_equal(arr, [], nested_dtype)
|
assert_equal(arr, [], nested_dtype)
|
||||||
|
|
||||||
arr = create_rec_nested(3)
|
arr = m.create_rec_nested(3)
|
||||||
assert arr.dtype == nested_dtype
|
assert arr.dtype == nested_dtype
|
||||||
assert_equal(arr, [((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)),
|
assert_equal(arr, [((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)),
|
||||||
((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)),
|
((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)),
|
||||||
((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5))], nested_dtype)
|
((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5))], nested_dtype)
|
||||||
assert print_rec_nested(arr) == [
|
assert m.print_rec_nested(arr) == [
|
||||||
"n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5",
|
"n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5",
|
||||||
"n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5",
|
"n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5",
|
||||||
"n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5"
|
"n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5"
|
||||||
]
|
]
|
||||||
|
|
||||||
arr = create_rec_partial(3)
|
arr = m.create_rec_partial(3)
|
||||||
assert str(arr.dtype) == partial_dtype_fmt()
|
assert str(arr.dtype) == partial_dtype_fmt()
|
||||||
partial_dtype = arr.dtype
|
partial_dtype = arr.dtype
|
||||||
assert '' not in arr.dtype.fields
|
assert '' not in arr.dtype.fields
|
||||||
@ -181,32 +174,28 @@ def test_recarray(simple_dtype, packed_dtype):
|
|||||||
assert_equal(arr, elements, simple_dtype)
|
assert_equal(arr, elements, simple_dtype)
|
||||||
assert_equal(arr, elements, packed_dtype)
|
assert_equal(arr, elements, packed_dtype)
|
||||||
|
|
||||||
arr = create_rec_partial_nested(3)
|
arr = m.create_rec_partial_nested(3)
|
||||||
assert str(arr.dtype) == partial_nested_fmt()
|
assert str(arr.dtype) == partial_nested_fmt()
|
||||||
assert '' not in arr.dtype.fields
|
assert '' not in arr.dtype.fields
|
||||||
assert '' not in arr.dtype.fields['a'][0].fields
|
assert '' not in arr.dtype.fields['a'][0].fields
|
||||||
assert arr.dtype.itemsize > partial_dtype.itemsize
|
assert arr.dtype.itemsize > partial_dtype.itemsize
|
||||||
np.testing.assert_equal(arr['a'], create_rec_partial(3))
|
np.testing.assert_equal(arr['a'], m.create_rec_partial(3))
|
||||||
|
|
||||||
|
|
||||||
def test_array_constructors():
|
def test_array_constructors():
|
||||||
from pybind11_tests import test_array_ctors
|
|
||||||
|
|
||||||
data = np.arange(1, 7, dtype='int32')
|
data = np.arange(1, 7, dtype='int32')
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
np.testing.assert_array_equal(test_array_ctors(10 + i), data.reshape((3, 2)))
|
np.testing.assert_array_equal(m.test_array_ctors(10 + i), data.reshape((3, 2)))
|
||||||
np.testing.assert_array_equal(test_array_ctors(20 + i), data.reshape((3, 2)))
|
np.testing.assert_array_equal(m.test_array_ctors(20 + i), data.reshape((3, 2)))
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
np.testing.assert_array_equal(test_array_ctors(30 + i), data)
|
np.testing.assert_array_equal(m.test_array_ctors(30 + i), data)
|
||||||
np.testing.assert_array_equal(test_array_ctors(40 + i), data)
|
np.testing.assert_array_equal(m.test_array_ctors(40 + i), data)
|
||||||
|
|
||||||
|
|
||||||
def test_string_array():
|
def test_string_array():
|
||||||
from pybind11_tests import create_string_array, print_string_array
|
arr = m.create_string_array(True)
|
||||||
|
|
||||||
arr = create_string_array(True)
|
|
||||||
assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]"
|
assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]"
|
||||||
assert print_string_array(arr) == [
|
assert m.print_string_array(arr) == [
|
||||||
"a='',b=''",
|
"a='',b=''",
|
||||||
"a='a',b='a'",
|
"a='a',b='a'",
|
||||||
"a='ab',b='ab'",
|
"a='ab',b='ab'",
|
||||||
@ -215,21 +204,20 @@ def test_string_array():
|
|||||||
dtype = arr.dtype
|
dtype = arr.dtype
|
||||||
assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc']
|
assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc']
|
||||||
assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc']
|
assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc']
|
||||||
arr = create_string_array(False)
|
arr = m.create_string_array(False)
|
||||||
assert dtype == arr.dtype
|
assert dtype == arr.dtype
|
||||||
|
|
||||||
|
|
||||||
def test_array_array():
|
def test_array_array():
|
||||||
from pybind11_tests import create_array_array, print_array_array
|
|
||||||
from sys import byteorder
|
from sys import byteorder
|
||||||
e = '<' if byteorder == 'little' else '>'
|
e = '<' if byteorder == 'little' else '>'
|
||||||
|
|
||||||
arr = create_array_array(3)
|
arr = m.create_array_array(3)
|
||||||
assert str(arr.dtype) == (
|
assert str(arr.dtype) == (
|
||||||
"{{'names':['a','b','c','d'], " +
|
"{{'names':['a','b','c','d'], " +
|
||||||
"'formats':[('S4', (3,)),('<i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], " +
|
"'formats':[('S4', (3,)),('<i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], " +
|
||||||
"'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e)
|
"'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e)
|
||||||
assert print_array_array(arr) == [
|
assert m.print_array_array(arr) == [
|
||||||
"a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," +
|
"a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," +
|
||||||
"c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}",
|
"c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}",
|
||||||
"a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," +
|
"a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," +
|
||||||
@ -241,61 +229,53 @@ def test_array_array():
|
|||||||
[b'WXYZ', b'GHIJ', b'QRST'],
|
[b'WXYZ', b'GHIJ', b'QRST'],
|
||||||
[b'STUV', b'CDEF', b'MNOP']]
|
[b'STUV', b'CDEF', b'MNOP']]
|
||||||
assert arr['b'].tolist() == [[0, 1], [1000, 1001], [2000, 2001]]
|
assert arr['b'].tolist() == [[0, 1], [1000, 1001], [2000, 2001]]
|
||||||
assert create_array_array(0).dtype == arr.dtype
|
assert m.create_array_array(0).dtype == arr.dtype
|
||||||
|
|
||||||
|
|
||||||
def test_enum_array():
|
def test_enum_array():
|
||||||
from pybind11_tests import create_enum_array, print_enum_array
|
|
||||||
from sys import byteorder
|
from sys import byteorder
|
||||||
e = '<' if byteorder == 'little' else '>'
|
e = '<' if byteorder == 'little' else '>'
|
||||||
|
|
||||||
arr = create_enum_array(3)
|
arr = m.create_enum_array(3)
|
||||||
dtype = arr.dtype
|
dtype = arr.dtype
|
||||||
assert dtype == np.dtype([('e1', e + 'i8'), ('e2', 'u1')])
|
assert dtype == np.dtype([('e1', e + 'i8'), ('e2', 'u1')])
|
||||||
assert print_enum_array(arr) == [
|
assert m.print_enum_array(arr) == [
|
||||||
"e1=A,e2=X",
|
"e1=A,e2=X",
|
||||||
"e1=B,e2=Y",
|
"e1=B,e2=Y",
|
||||||
"e1=A,e2=X"
|
"e1=A,e2=X"
|
||||||
]
|
]
|
||||||
assert arr['e1'].tolist() == [-1, 1, -1]
|
assert arr['e1'].tolist() == [-1, 1, -1]
|
||||||
assert arr['e2'].tolist() == [1, 2, 1]
|
assert arr['e2'].tolist() == [1, 2, 1]
|
||||||
assert create_enum_array(0).dtype == dtype
|
assert m.create_enum_array(0).dtype == dtype
|
||||||
|
|
||||||
|
|
||||||
def test_complex_array():
|
def test_complex_array():
|
||||||
from pybind11_tests import create_complex_array, print_complex_array
|
|
||||||
from sys import byteorder
|
from sys import byteorder
|
||||||
e = '<' if byteorder == 'little' else '>'
|
e = '<' if byteorder == 'little' else '>'
|
||||||
|
|
||||||
arr = create_complex_array(3)
|
arr = m.create_complex_array(3)
|
||||||
dtype = arr.dtype
|
dtype = arr.dtype
|
||||||
assert dtype == np.dtype([('cflt', e + 'c8'), ('cdbl', e + 'c16')])
|
assert dtype == np.dtype([('cflt', e + 'c8'), ('cdbl', e + 'c16')])
|
||||||
assert print_complex_array(arr) == [
|
assert m.print_complex_array(arr) == [
|
||||||
"c:(0,0.25),(0.5,0.75)",
|
"c:(0,0.25),(0.5,0.75)",
|
||||||
"c:(1,1.25),(1.5,1.75)",
|
"c:(1,1.25),(1.5,1.75)",
|
||||||
"c:(2,2.25),(2.5,2.75)"
|
"c:(2,2.25),(2.5,2.75)"
|
||||||
]
|
]
|
||||||
assert arr['cflt'].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j]
|
assert arr['cflt'].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j]
|
||||||
assert arr['cdbl'].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j]
|
assert arr['cdbl'].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j]
|
||||||
assert create_complex_array(0).dtype == dtype
|
assert m.create_complex_array(0).dtype == dtype
|
||||||
|
|
||||||
|
|
||||||
def test_signature(doc):
|
def test_signature(doc):
|
||||||
from pybind11_tests import create_rec_nested
|
assert doc(m.create_rec_nested) == \
|
||||||
|
"create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
|
||||||
assert doc(create_rec_nested) == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
|
|
||||||
|
|
||||||
|
|
||||||
def test_scalar_conversion():
|
def test_scalar_conversion():
|
||||||
from pybind11_tests import (create_rec_simple, f_simple,
|
|
||||||
create_rec_packed, f_packed,
|
|
||||||
create_rec_nested, f_nested,
|
|
||||||
create_enum_array)
|
|
||||||
|
|
||||||
n = 3
|
n = 3
|
||||||
arrays = [create_rec_simple(n), create_rec_packed(n),
|
arrays = [m.create_rec_simple(n), m.create_rec_packed(n),
|
||||||
create_rec_nested(n), create_enum_array(n)]
|
m.create_rec_nested(n), m.create_enum_array(n)]
|
||||||
funcs = [f_simple, f_packed, f_nested]
|
funcs = [m.f_simple, m.f_packed, m.f_nested]
|
||||||
|
|
||||||
for i, func in enumerate(funcs):
|
for i, func in enumerate(funcs):
|
||||||
for j, arr in enumerate(arrays):
|
for j, arr in enumerate(arrays):
|
||||||
@ -308,14 +288,11 @@ def test_scalar_conversion():
|
|||||||
|
|
||||||
|
|
||||||
def test_register_dtype():
|
def test_register_dtype():
|
||||||
from pybind11_tests import register_dtype
|
|
||||||
|
|
||||||
with pytest.raises(RuntimeError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
register_dtype()
|
m.register_dtype()
|
||||||
assert 'dtype is already registered' in str(excinfo.value)
|
assert 'dtype is already registered' in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
@pytest.requires_numpy
|
@pytest.requires_numpy
|
||||||
def test_compare_buffer_info():
|
def test_compare_buffer_info():
|
||||||
from pybind11_tests import compare_buffer_info
|
assert all(m.compare_buffer_info())
|
||||||
assert all(compare_buffer_info())
|
|
||||||
|
@ -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 {
|
// test_vectorize, test_docs, test_array_collapse
|
||||||
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) {
|
|
||||||
// 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) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 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) {
|
|||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// 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) {
|
|||||||
// 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) {
|
|||||||
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);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
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):
|
|||||||
|
|
||||||
|
|
||||||
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):
|
|||||||
|
|
||||||
|
|
||||||
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():
|
|||||||
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 @@
|
|||||||
#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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
result->push_back("some value");
|
result->push_back("some value");
|
||||||
return std::unique_ptr<StringList>(result);
|
return std::unique_ptr<StringList>(result);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
@ -1,40 +1,36 @@
|
|||||||
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):
|
|||||||
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:
|
|||||||
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; }
|
|||||||
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) {
|
|||||||
|
|
||||||
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) {
|
|||||||
.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; });
|
||||||
});
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
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():
|
|||||||
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():
|
|||||||
|
|
||||||
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():
|
|||||||
|
|
||||||
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 @@
|
|||||||
|
|
||||||
#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) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
#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) {
|
|||||||
self.attr("__dict__") = t[2];
|
self.attr("__dict__") = t[2];
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
});
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
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:
|
|||||||
|
|
||||||
|
|
||||||
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():
|
|||||||
|
|
||||||
@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"
|
||||||
|
|
||||||
|
@ -13,146 +13,6 @@
|
|||||||
#include <pybind11/operators.h>
|
#include <pybind11/operators.h>
|
||||||
#include <pybind11/stl.h>
|
#include <pybind11/stl.h>
|
||||||
|
|
||||||
class Sequence {
|
|
||||||
public:
|
|
||||||
Sequence(size_t size) : m_size(size) {
|
|
||||||
print_created(this, "of size", m_size);
|
|
||||||
m_data = new float[size];
|
|
||||||
memset(m_data, 0, sizeof(float) * size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Sequence(const std::vector<float> &value) : m_size(value.size()) {
|
|
||||||
print_created(this, "of size", m_size, "from std::vector");
|
|
||||||
m_data = new float[m_size];
|
|
||||||
memcpy(m_data, &value[0], sizeof(float) * m_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Sequence(const Sequence &s) : m_size(s.m_size) {
|
|
||||||
print_copy_created(this);
|
|
||||||
m_data = new float[m_size];
|
|
||||||
memcpy(m_data, s.m_data, sizeof(float)*m_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) {
|
|
||||||
print_move_created(this);
|
|
||||||
s.m_size = 0;
|
|
||||||
s.m_data = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Sequence() {
|
|
||||||
print_destroyed(this);
|
|
||||||
delete[] m_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sequence &operator=(const Sequence &s) {
|
|
||||||
if (&s != this) {
|
|
||||||
delete[] m_data;
|
|
||||||
m_size = s.m_size;
|
|
||||||
m_data = new float[m_size];
|
|
||||||
memcpy(m_data, s.m_data, sizeof(float)*m_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
print_copy_assigned(this);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sequence &operator=(Sequence &&s) {
|
|
||||||
if (&s != this) {
|
|
||||||
delete[] m_data;
|
|
||||||
m_size = s.m_size;
|
|
||||||
m_data = s.m_data;
|
|
||||||
s.m_size = 0;
|
|
||||||
s.m_data = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_move_assigned(this);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const Sequence &s) const {
|
|
||||||
if (m_size != s.size())
|
|
||||||
return false;
|
|
||||||
for (size_t i=0; i<m_size; ++i)
|
|
||||||
if (m_data[i] != s[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const Sequence &s) const {
|
|
||||||
return !operator==(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
float operator[](size_t index) const {
|
|
||||||
return m_data[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
float &operator[](size_t index) {
|
|
||||||
return m_data[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool contains(float v) const {
|
|
||||||
for (size_t i=0; i<m_size; ++i)
|
|
||||||
if (v == m_data[i])
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sequence reversed() const {
|
|
||||||
Sequence result(m_size);
|
|
||||||
for (size_t i=0; i<m_size; ++i)
|
|
||||||
result[m_size-i-1] = m_data[i];
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const { return m_size; }
|
|
||||||
|
|
||||||
const float *begin() const { return m_data; }
|
|
||||||
const float *end() const { return m_data+m_size; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t m_size;
|
|
||||||
float *m_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
class IntPairs {
|
|
||||||
public:
|
|
||||||
IntPairs(std::vector<std::pair<int, int>> data) : data_(std::move(data)) {}
|
|
||||||
const std::pair<int, int>* begin() const { return data_.data(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<std::pair<int, int>> data_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Interface of a map-like object that isn't (directly) an unordered_map, but provides some basic
|
|
||||||
// map-like functionality.
|
|
||||||
class StringMap {
|
|
||||||
public:
|
|
||||||
StringMap() = default;
|
|
||||||
StringMap(std::unordered_map<std::string, std::string> init)
|
|
||||||
: map(std::move(init)) {}
|
|
||||||
|
|
||||||
void set(std::string key, std::string val) {
|
|
||||||
map[key] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get(std::string key) const {
|
|
||||||
return map.at(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const {
|
|
||||||
return map.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unordered_map<std::string, std::string> map;
|
|
||||||
|
|
||||||
public:
|
|
||||||
decltype(map.cbegin()) begin() const { return map.cbegin(); }
|
|
||||||
decltype(map.cend()) end() const { return map.cend(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class NonZeroIterator {
|
class NonZeroIterator {
|
||||||
const T* ptr_;
|
const T* ptr_;
|
||||||
@ -210,66 +70,164 @@ py::list test_random_access_iterator(PythonType x) {
|
|||||||
return checks;
|
return checks;
|
||||||
}
|
}
|
||||||
|
|
||||||
test_initializer sequences_and_iterators([](py::module &pm) {
|
TEST_SUBMODULE(sequences_and_iterators, m) {
|
||||||
auto m = pm.def_submodule("sequences_and_iterators");
|
|
||||||
|
|
||||||
py::class_<Sequence> seq(m, "Sequence");
|
// test_sequence
|
||||||
|
class Sequence {
|
||||||
|
public:
|
||||||
|
Sequence(size_t size) : m_size(size) {
|
||||||
|
print_created(this, "of size", m_size);
|
||||||
|
m_data = new float[size];
|
||||||
|
memset(m_data, 0, sizeof(float) * size);
|
||||||
|
}
|
||||||
|
Sequence(const std::vector<float> &value) : m_size(value.size()) {
|
||||||
|
print_created(this, "of size", m_size, "from std::vector");
|
||||||
|
m_data = new float[m_size];
|
||||||
|
memcpy(m_data, &value[0], sizeof(float) * m_size);
|
||||||
|
}
|
||||||
|
Sequence(const Sequence &s) : m_size(s.m_size) {
|
||||||
|
print_copy_created(this);
|
||||||
|
m_data = new float[m_size];
|
||||||
|
memcpy(m_data, s.m_data, sizeof(float)*m_size);
|
||||||
|
}
|
||||||
|
Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) {
|
||||||
|
print_move_created(this);
|
||||||
|
s.m_size = 0;
|
||||||
|
s.m_data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
seq.def(py::init<size_t>())
|
~Sequence() { print_destroyed(this); delete[] m_data; }
|
||||||
.def(py::init<const std::vector<float>&>())
|
|
||||||
/// Bare bones interface
|
Sequence &operator=(const Sequence &s) {
|
||||||
.def("__getitem__", [](const Sequence &s, size_t i) {
|
if (&s != this) {
|
||||||
if (i >= s.size())
|
delete[] m_data;
|
||||||
throw py::index_error();
|
m_size = s.m_size;
|
||||||
|
m_data = new float[m_size];
|
||||||
|
memcpy(m_data, s.m_data, sizeof(float)*m_size);
|
||||||
|
}
|
||||||
|
print_copy_assigned(this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sequence &operator=(Sequence &&s) {
|
||||||
|
if (&s != this) {
|
||||||
|
delete[] m_data;
|
||||||
|
m_size = s.m_size;
|
||||||
|
m_data = s.m_data;
|
||||||
|
s.m_size = 0;
|
||||||
|
s.m_data = nullptr;
|
||||||
|
}
|
||||||
|
print_move_assigned(this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Sequence &s) const {
|
||||||
|
if (m_size != s.size()) return false;
|
||||||
|
for (size_t i = 0; i < m_size; ++i)
|
||||||
|
if (m_data[i] != s[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool operator!=(const Sequence &s) const { return !operator==(s); }
|
||||||
|
|
||||||
|
float operator[](size_t index) const { return m_data[index]; }
|
||||||
|
float &operator[](size_t index) { return m_data[index]; }
|
||||||
|
|
||||||
|
bool contains(float v) const {
|
||||||
|
for (size_t i = 0; i < m_size; ++i)
|
||||||
|
if (v == m_data[i])
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sequence reversed() const {
|
||||||
|
Sequence result(m_size);
|
||||||
|
for (size_t i = 0; i < m_size; ++i)
|
||||||
|
result[m_size - i - 1] = m_data[i];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const { return m_size; }
|
||||||
|
|
||||||
|
const float *begin() const { return m_data; }
|
||||||
|
const float *end() const { return m_data+m_size; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t m_size;
|
||||||
|
float *m_data;
|
||||||
|
};
|
||||||
|
py::class_<Sequence>(m, "Sequence")
|
||||||
|
.def(py::init<size_t>())
|
||||||
|
.def(py::init<const std::vector<float>&>())
|
||||||
|
/// Bare bones interface
|
||||||
|
.def("__getitem__", [](const Sequence &s, size_t i) {
|
||||||
|
if (i >= s.size()) throw py::index_error();
|
||||||
return s[i];
|
return s[i];
|
||||||
})
|
})
|
||||||
.def("__setitem__", [](Sequence &s, size_t i, float v) {
|
.def("__setitem__", [](Sequence &s, size_t i, float v) {
|
||||||
if (i >= s.size())
|
if (i >= s.size()) throw py::index_error();
|
||||||
throw py::index_error();
|
|
||||||
s[i] = v;
|
s[i] = v;
|
||||||
})
|
})
|
||||||
.def("__len__", &Sequence::size)
|
.def("__len__", &Sequence::size)
|
||||||
/// Optional sequence protocol operations
|
/// Optional sequence protocol operations
|
||||||
.def("__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); },
|
.def("__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); },
|
||||||
py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */)
|
py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */)
|
||||||
.def("__contains__", [](const Sequence &s, float v) { return s.contains(v); })
|
.def("__contains__", [](const Sequence &s, float v) { return s.contains(v); })
|
||||||
.def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); })
|
.def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); })
|
||||||
/// Slicing protocol (optional)
|
/// Slicing protocol (optional)
|
||||||
.def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* {
|
.def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* {
|
||||||
size_t start, stop, step, slicelength;
|
size_t start, stop, step, slicelength;
|
||||||
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
|
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
|
||||||
throw py::error_already_set();
|
throw py::error_already_set();
|
||||||
Sequence *seq = new Sequence(slicelength);
|
Sequence *seq = new Sequence(slicelength);
|
||||||
for (size_t i=0; i<slicelength; ++i) {
|
for (size_t i = 0; i < slicelength; ++i) {
|
||||||
(*seq)[i] = s[start]; start += step;
|
(*seq)[i] = s[start]; start += step;
|
||||||
}
|
}
|
||||||
return seq;
|
return seq;
|
||||||
})
|
})
|
||||||
.def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) {
|
.def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) {
|
||||||
size_t start, stop, step, slicelength;
|
size_t start, stop, step, slicelength;
|
||||||
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
|
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
|
||||||
throw py::error_already_set();
|
throw py::error_already_set();
|
||||||
if (slicelength != value.size())
|
if (slicelength != value.size())
|
||||||
throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
|
throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
|
||||||
for (size_t i=0; i<slicelength; ++i) {
|
for (size_t i = 0; i < slicelength; ++i) {
|
||||||
s[start] = value[i]; start += step;
|
s[start] = value[i]; start += step;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
/// Comparisons
|
/// Comparisons
|
||||||
.def(py::self == py::self)
|
.def(py::self == py::self)
|
||||||
.def(py::self != py::self);
|
.def(py::self != py::self)
|
||||||
// Could also define py::self + py::self for concatenation, etc.
|
// Could also define py::self + py::self for concatenation, etc.
|
||||||
|
;
|
||||||
|
|
||||||
py::class_<StringMap> map(m, "StringMap");
|
// test_map_iterator
|
||||||
|
// Interface of a map-like object that isn't (directly) an unordered_map, but provides some basic
|
||||||
|
// map-like functionality.
|
||||||
|
class StringMap {
|
||||||
|
public:
|
||||||
|
StringMap() = default;
|
||||||
|
StringMap(std::unordered_map<std::string, std::string> init)
|
||||||
|
: map(std::move(init)) {}
|
||||||
|
|
||||||
map .def(py::init<>())
|
void set(std::string key, std::string val) { map[key] = val; }
|
||||||
|
std::string get(std::string key) const { return map.at(key); }
|
||||||
|
size_t size() const { return map.size(); }
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, std::string> map;
|
||||||
|
public:
|
||||||
|
decltype(map.cbegin()) begin() const { return map.cbegin(); }
|
||||||
|
decltype(map.cend()) end() const { return map.cend(); }
|
||||||
|
};
|
||||||
|
py::class_<StringMap>(m, "StringMap")
|
||||||
|
.def(py::init<>())
|
||||||
.def(py::init<std::unordered_map<std::string, std::string>>())
|
.def(py::init<std::unordered_map<std::string, std::string>>())
|
||||||
.def("__getitem__", [](const StringMap &map, std::string key) {
|
.def("__getitem__", [](const StringMap &map, std::string key) {
|
||||||
try { return map.get(key); }
|
try { return map.get(key); }
|
||||||
catch (const std::out_of_range&) {
|
catch (const std::out_of_range&) {
|
||||||
throw py::key_error("key '" + key + "' does not exist");
|
throw py::key_error("key '" + key + "' does not exist");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.def("__setitem__", &StringMap::set)
|
.def("__setitem__", &StringMap::set)
|
||||||
.def("__len__", &StringMap::size)
|
.def("__len__", &StringMap::size)
|
||||||
.def("__iter__", [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); },
|
.def("__iter__", [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); },
|
||||||
@ -278,14 +236,23 @@ test_initializer sequences_and_iterators([](py::module &pm) {
|
|||||||
py::keep_alive<0, 1>())
|
py::keep_alive<0, 1>())
|
||||||
;
|
;
|
||||||
|
|
||||||
|
// test_generalized_iterators
|
||||||
|
class IntPairs {
|
||||||
|
public:
|
||||||
|
IntPairs(std::vector<std::pair<int, int>> data) : data_(std::move(data)) {}
|
||||||
|
const std::pair<int, int>* begin() const { return data_.data(); }
|
||||||
|
private:
|
||||||
|
std::vector<std::pair<int, int>> data_;
|
||||||
|
};
|
||||||
py::class_<IntPairs>(m, "IntPairs")
|
py::class_<IntPairs>(m, "IntPairs")
|
||||||
.def(py::init<std::vector<std::pair<int, int>>>())
|
.def(py::init<std::vector<std::pair<int, int>>>())
|
||||||
.def("nonzero", [](const IntPairs& s) {
|
.def("nonzero", [](const IntPairs& s) {
|
||||||
return py::make_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel());
|
return py::make_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel());
|
||||||
}, py::keep_alive<0, 1>())
|
}, py::keep_alive<0, 1>())
|
||||||
.def("nonzero_keys", [](const IntPairs& s) {
|
.def("nonzero_keys", [](const IntPairs& s) {
|
||||||
return py::make_key_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel());
|
return py::make_key_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel());
|
||||||
}, py::keep_alive<0, 1>());
|
}, py::keep_alive<0, 1>())
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -315,6 +282,7 @@ test_initializer sequences_and_iterators([](py::module &pm) {
|
|||||||
.def("__iter__", [](py::object s) { return PySequenceIterator(s.cast<const Sequence &>(), s); })
|
.def("__iter__", [](py::object s) { return PySequenceIterator(s.cast<const Sequence &>(), s); })
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// test_python_iterator_in_cpp
|
||||||
m.def("object_to_list", [](py::object o) {
|
m.def("object_to_list", [](py::object o) {
|
||||||
auto l = py::list();
|
auto l = py::list();
|
||||||
for (auto item : o) {
|
for (auto item : o) {
|
||||||
@ -348,17 +316,19 @@ test_initializer sequences_and_iterators([](py::module &pm) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
m.def("tuple_iterator", [](py::tuple x) { return test_random_access_iterator(x); });
|
m.def("tuple_iterator", &test_random_access_iterator<py::tuple>);
|
||||||
m.def("list_iterator", [](py::list x) { return test_random_access_iterator(x); });
|
m.def("list_iterator", &test_random_access_iterator<py::list>);
|
||||||
m.def("sequence_iterator", [](py::sequence x) { return test_random_access_iterator(x); });
|
m.def("sequence_iterator", &test_random_access_iterator<py::sequence>);
|
||||||
|
|
||||||
|
// test_iterator_passthrough
|
||||||
// #181: iterator passthrough did not compile
|
// #181: iterator passthrough did not compile
|
||||||
m.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
|
m.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
|
||||||
return py::make_iterator(std::begin(s), std::end(s));
|
return py::make_iterator(std::begin(s), std::end(s));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// test_iterator_rvp
|
||||||
// #388: Can't make iterators via make_iterator() with different r/v policies
|
// #388: Can't make iterators via make_iterator() with different r/v policies
|
||||||
static std::vector<int> list = { 1, 2, 3 };
|
static std::vector<int> list = { 1, 2, 3 };
|
||||||
m.def("make_iterator_1", []() { return py::make_iterator<py::return_value_policy::copy>(list); });
|
m.def("make_iterator_1", []() { return py::make_iterator<py::return_value_policy::copy>(list); });
|
||||||
m.def("make_iterator_2", []() { return py::make_iterator<py::return_value_policy::automatic>(list); });
|
m.def("make_iterator_2", []() { return py::make_iterator<py::return_value_policy::automatic>(list); });
|
||||||
});
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
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):
|
|||||||
|
|
||||||
|
|
||||||
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 = m.Sequence(5)
|
||||||
|
|
||||||
s = 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():
|
|||||||
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():
|
|||||||
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():
|
|||||||
|
|
||||||
|
|
||||||
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]
|
||||||
|
@ -11,108 +11,12 @@
|
|||||||
#include "pybind11_tests.h"
|
#include "pybind11_tests.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
|
||||||
/// Custom object with builtin reference counting (see 'object.h' for the implementation)
|
// Make pybind aware of the ref-counted wrapper type (s):
|
||||||
class MyObject1 : public Object {
|
|
||||||
public:
|
|
||||||
MyObject1(int value) : value(value) {
|
|
||||||
print_created(this, toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toString() const {
|
|
||||||
return "MyObject1[" + std::to_string(value) + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~MyObject1() {
|
|
||||||
print_destroyed(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int value;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Object managed by a std::shared_ptr<>
|
|
||||||
class MyObject2 {
|
|
||||||
public:
|
|
||||||
MyObject2(int value) : value(value) {
|
|
||||||
print_created(this, toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toString() const {
|
|
||||||
return "MyObject2[" + std::to_string(value) + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~MyObject2() {
|
|
||||||
print_destroyed(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int value;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<>
|
|
||||||
class MyObject3 : public std::enable_shared_from_this<MyObject3> {
|
|
||||||
public:
|
|
||||||
MyObject3(int value) : value(value) {
|
|
||||||
print_created(this, toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toString() const {
|
|
||||||
return "MyObject3[" + std::to_string(value) + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~MyObject3() {
|
|
||||||
print_destroyed(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MyObject4 {
|
|
||||||
public:
|
|
||||||
MyObject4(int value) : value{value} {
|
|
||||||
print_created(this);
|
|
||||||
}
|
|
||||||
int value;
|
|
||||||
private:
|
|
||||||
~MyObject4() {
|
|
||||||
print_destroyed(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the
|
|
||||||
/// holder size to trigger the non-simple-layout internal instance layout for single inheritance with
|
|
||||||
/// large holder type.
|
|
||||||
template <typename T> class huge_unique_ptr {
|
|
||||||
std::unique_ptr<T> ptr;
|
|
||||||
uint64_t padding[10];
|
|
||||||
public:
|
|
||||||
huge_unique_ptr(T *p) : ptr(p) {};
|
|
||||||
T *get() { return ptr.get(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class MyObject5 { // managed by huge_unique_ptr
|
|
||||||
public:
|
|
||||||
MyObject5(int value) : value{value} {
|
|
||||||
print_created(this);
|
|
||||||
}
|
|
||||||
int value;
|
|
||||||
~MyObject5() {
|
|
||||||
print_destroyed(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Make pybind aware of the ref-counted wrapper type (s)
|
|
||||||
|
|
||||||
// ref<T> is a wrapper for 'Object' which uses intrusive reference counting
|
// ref<T> is a wrapper for 'Object' which uses intrusive reference counting
|
||||||
// It is always possible to construct a ref<T> from an Object* pointer without
|
// It is always possible to construct a ref<T> from an Object* pointer without
|
||||||
// possible incosistencies, hence the 'true' argument at the end.
|
// possible incosistencies, hence the 'true' argument at the end.
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true);
|
PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true);
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>); // Not required any more for std::shared_ptr,
|
|
||||||
// but it should compile without error
|
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>);
|
|
||||||
|
|
||||||
// Make pybind11 aware of the non-standard getter member function
|
// Make pybind11 aware of the non-standard getter member function
|
||||||
namespace pybind11 { namespace detail {
|
namespace pybind11 { namespace detail {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -121,162 +25,157 @@ namespace pybind11 { namespace detail {
|
|||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
Object *make_object_1() { return new MyObject1(1); }
|
// The following is not required anymore for std::shared_ptr, but it should compile without error:
|
||||||
ref<Object> make_object_2() { return new MyObject1(2); }
|
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
||||||
|
|
||||||
MyObject1 *make_myobject1_1() { return new MyObject1(4); }
|
// This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the
|
||||||
ref<MyObject1> make_myobject1_2() { return new MyObject1(5); }
|
// holder size to trigger the non-simple-layout internal instance layout for single inheritance with
|
||||||
|
// large holder type:
|
||||||
|
template <typename T> class huge_unique_ptr {
|
||||||
|
std::unique_ptr<T> ptr;
|
||||||
|
uint64_t padding[10];
|
||||||
|
public:
|
||||||
|
huge_unique_ptr(T *p) : ptr(p) {};
|
||||||
|
T *get() { return ptr.get(); }
|
||||||
|
};
|
||||||
|
PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>);
|
||||||
|
|
||||||
MyObject2 *make_myobject2_1() { return new MyObject2(6); }
|
// Simple custom holder that works like unique_ptr
|
||||||
std::shared_ptr<MyObject2> make_myobject2_2() { return std::make_shared<MyObject2>(7); }
|
template <typename T>
|
||||||
|
class custom_unique_ptr {
|
||||||
|
std::unique_ptr<T> impl;
|
||||||
|
public:
|
||||||
|
custom_unique_ptr(T* p) : impl(p) { }
|
||||||
|
T* get() const { return impl.get(); }
|
||||||
|
T* release_ptr() { return impl.release(); }
|
||||||
|
};
|
||||||
|
PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
|
||||||
|
|
||||||
MyObject3 *make_myobject3_1() { return new MyObject3(8); }
|
|
||||||
std::shared_ptr<MyObject3> make_myobject3_2() { return std::make_shared<MyObject3>(9); }
|
|
||||||
|
|
||||||
void print_object_1(const Object *obj) { py::print(obj->toString()); }
|
TEST_SUBMODULE(smart_ptr, m) {
|
||||||
void print_object_2(ref<Object> obj) { py::print(obj->toString()); }
|
|
||||||
void print_object_3(const ref<Object> &obj) { py::print(obj->toString()); }
|
|
||||||
void print_object_4(const ref<Object> *obj) { py::print((*obj)->toString()); }
|
|
||||||
|
|
||||||
void print_myobject1_1(const MyObject1 *obj) { py::print(obj->toString()); }
|
// test_smart_ptr
|
||||||
void print_myobject1_2(ref<MyObject1> obj) { py::print(obj->toString()); }
|
|
||||||
void print_myobject1_3(const ref<MyObject1> &obj) { py::print(obj->toString()); }
|
|
||||||
void print_myobject1_4(const ref<MyObject1> *obj) { py::print((*obj)->toString()); }
|
|
||||||
|
|
||||||
void print_myobject2_1(const MyObject2 *obj) { py::print(obj->toString()); }
|
// Object implementation in `object.h`
|
||||||
void print_myobject2_2(std::shared_ptr<MyObject2> obj) { py::print(obj->toString()); }
|
|
||||||
void print_myobject2_3(const std::shared_ptr<MyObject2> &obj) { py::print(obj->toString()); }
|
|
||||||
void print_myobject2_4(const std::shared_ptr<MyObject2> *obj) { py::print((*obj)->toString()); }
|
|
||||||
|
|
||||||
void print_myobject3_1(const MyObject3 *obj) { py::print(obj->toString()); }
|
|
||||||
void print_myobject3_2(std::shared_ptr<MyObject3> obj) { py::print(obj->toString()); }
|
|
||||||
void print_myobject3_3(const std::shared_ptr<MyObject3> &obj) { py::print(obj->toString()); }
|
|
||||||
void print_myobject3_4(const std::shared_ptr<MyObject3> *obj) { py::print((*obj)->toString()); }
|
|
||||||
|
|
||||||
test_initializer smart_ptr([](py::module &m) {
|
|
||||||
py::class_<Object, ref<Object>> obj(m, "Object");
|
py::class_<Object, ref<Object>> obj(m, "Object");
|
||||||
obj.def("getRefCount", &Object::getRefCount);
|
obj.def("getRefCount", &Object::getRefCount);
|
||||||
|
|
||||||
|
// Custom object with builtin reference counting (see 'object.h' for the implementation)
|
||||||
|
class MyObject1 : public Object {
|
||||||
|
public:
|
||||||
|
MyObject1(int value) : value(value) { print_created(this, toString()); }
|
||||||
|
std::string toString() const { return "MyObject1[" + std::to_string(value) + "]"; }
|
||||||
|
protected:
|
||||||
|
virtual ~MyObject1() { print_destroyed(this); }
|
||||||
|
private:
|
||||||
|
int value;
|
||||||
|
};
|
||||||
py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj)
|
py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj)
|
||||||
.def(py::init<int>());
|
.def(py::init<int>());
|
||||||
|
py::implicitly_convertible<py::int_, MyObject1>();
|
||||||
|
|
||||||
m.def("test_object1_refcounting",
|
m.def("make_object_1", []() -> Object * { return new MyObject1(1); });
|
||||||
[]() -> bool {
|
m.def("make_object_2", []() -> ref<Object> { return new MyObject1(2); });
|
||||||
ref<MyObject1> o = new MyObject1(0);
|
m.def("make_myobject1_1", []() -> MyObject1 * { return new MyObject1(4); });
|
||||||
bool good = o->getRefCount() == 1;
|
m.def("make_myobject1_2", []() -> ref<MyObject1> { return new MyObject1(5); });
|
||||||
py::object o2 = py::cast(o, py::return_value_policy::reference);
|
m.def("print_object_1", [](const Object *obj) { py::print(obj->toString()); });
|
||||||
// always request (partial) ownership for objects with intrusive
|
m.def("print_object_2", [](ref<Object> obj) { py::print(obj->toString()); });
|
||||||
// reference counting even when using the 'reference' RVP
|
m.def("print_object_3", [](const ref<Object> &obj) { py::print(obj->toString()); });
|
||||||
good &= o->getRefCount() == 2;
|
m.def("print_object_4", [](const ref<Object> *obj) { py::print((*obj)->toString()); });
|
||||||
return good;
|
m.def("print_myobject1_1", [](const MyObject1 *obj) { py::print(obj->toString()); });
|
||||||
}
|
m.def("print_myobject1_2", [](ref<MyObject1> obj) { py::print(obj->toString()); });
|
||||||
);
|
m.def("print_myobject1_3", [](const ref<MyObject1> &obj) { py::print(obj->toString()); });
|
||||||
|
m.def("print_myobject1_4", [](const ref<MyObject1> *obj) { py::print((*obj)->toString()); });
|
||||||
|
|
||||||
m.def("make_object_1", &make_object_1);
|
// Expose constructor stats for the ref type
|
||||||
m.def("make_object_2", &make_object_2);
|
m.def("cstats_ref", &ConstructorStats::get<ref_tag>);
|
||||||
m.def("make_myobject1_1", &make_myobject1_1);
|
|
||||||
m.def("make_myobject1_2", &make_myobject1_2);
|
|
||||||
m.def("print_object_1", &print_object_1);
|
|
||||||
m.def("print_object_2", &print_object_2);
|
|
||||||
m.def("print_object_3", &print_object_3);
|
|
||||||
m.def("print_object_4", &print_object_4);
|
|
||||||
m.def("print_myobject1_1", &print_myobject1_1);
|
|
||||||
m.def("print_myobject1_2", &print_myobject1_2);
|
|
||||||
m.def("print_myobject1_3", &print_myobject1_3);
|
|
||||||
m.def("print_myobject1_4", &print_myobject1_4);
|
|
||||||
|
|
||||||
|
|
||||||
|
// Object managed by a std::shared_ptr<>
|
||||||
|
class MyObject2 {
|
||||||
|
public:
|
||||||
|
MyObject2(int value) : value(value) { print_created(this, toString()); }
|
||||||
|
std::string toString() const { return "MyObject2[" + std::to_string(value) + "]"; }
|
||||||
|
virtual ~MyObject2() { print_destroyed(this); }
|
||||||
|
private:
|
||||||
|
int value;
|
||||||
|
};
|
||||||
py::class_<MyObject2, std::shared_ptr<MyObject2>>(m, "MyObject2")
|
py::class_<MyObject2, std::shared_ptr<MyObject2>>(m, "MyObject2")
|
||||||
.def(py::init<int>());
|
.def(py::init<int>());
|
||||||
m.def("make_myobject2_1", &make_myobject2_1);
|
m.def("make_myobject2_1", []() { return new MyObject2(6); });
|
||||||
m.def("make_myobject2_2", &make_myobject2_2);
|
m.def("make_myobject2_2", []() { return std::make_shared<MyObject2>(7); });
|
||||||
m.def("print_myobject2_1", &print_myobject2_1);
|
m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); });
|
||||||
m.def("print_myobject2_2", &print_myobject2_2);
|
m.def("print_myobject2_2", [](std::shared_ptr<MyObject2> obj) { py::print(obj->toString()); });
|
||||||
m.def("print_myobject2_3", &print_myobject2_3);
|
m.def("print_myobject2_3", [](const std::shared_ptr<MyObject2> &obj) { py::print(obj->toString()); });
|
||||||
m.def("print_myobject2_4", &print_myobject2_4);
|
m.def("print_myobject2_4", [](const std::shared_ptr<MyObject2> *obj) { py::print((*obj)->toString()); });
|
||||||
|
|
||||||
|
// Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<>
|
||||||
|
class MyObject3 : public std::enable_shared_from_this<MyObject3> {
|
||||||
|
public:
|
||||||
|
MyObject3(int value) : value(value) { print_created(this, toString()); }
|
||||||
|
std::string toString() const { return "MyObject3[" + std::to_string(value) + "]"; }
|
||||||
|
virtual ~MyObject3() { print_destroyed(this); }
|
||||||
|
private:
|
||||||
|
int value;
|
||||||
|
};
|
||||||
py::class_<MyObject3, std::shared_ptr<MyObject3>>(m, "MyObject3")
|
py::class_<MyObject3, std::shared_ptr<MyObject3>>(m, "MyObject3")
|
||||||
.def(py::init<int>());
|
.def(py::init<int>());
|
||||||
m.def("make_myobject3_1", &make_myobject3_1);
|
m.def("make_myobject3_1", []() { return new MyObject3(8); });
|
||||||
m.def("make_myobject3_2", &make_myobject3_2);
|
m.def("make_myobject3_2", []() { return std::make_shared<MyObject3>(9); });
|
||||||
m.def("print_myobject3_1", &print_myobject3_1);
|
m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); });
|
||||||
m.def("print_myobject3_2", &print_myobject3_2);
|
m.def("print_myobject3_2", [](std::shared_ptr<MyObject3> obj) { py::print(obj->toString()); });
|
||||||
m.def("print_myobject3_3", &print_myobject3_3);
|
m.def("print_myobject3_3", [](const std::shared_ptr<MyObject3> &obj) { py::print(obj->toString()); });
|
||||||
m.def("print_myobject3_4", &print_myobject3_4);
|
m.def("print_myobject3_4", [](const std::shared_ptr<MyObject3> *obj) { py::print((*obj)->toString()); });
|
||||||
|
|
||||||
|
// test_smart_ptr_refcounting
|
||||||
|
m.def("test_object1_refcounting", []() {
|
||||||
|
ref<MyObject1> o = new MyObject1(0);
|
||||||
|
bool good = o->getRefCount() == 1;
|
||||||
|
py::object o2 = py::cast(o, py::return_value_policy::reference);
|
||||||
|
// always request (partial) ownership for objects with intrusive
|
||||||
|
// reference counting even when using the 'reference' RVP
|
||||||
|
good &= o->getRefCount() == 2;
|
||||||
|
return good;
|
||||||
|
});
|
||||||
|
|
||||||
|
// test_unique_nodelete
|
||||||
|
// Object with a private destructor
|
||||||
|
class MyObject4 {
|
||||||
|
public:
|
||||||
|
MyObject4(int value) : value{value} { print_created(this); }
|
||||||
|
int value;
|
||||||
|
private:
|
||||||
|
~MyObject4() { print_destroyed(this); }
|
||||||
|
};
|
||||||
py::class_<MyObject4, std::unique_ptr<MyObject4, py::nodelete>>(m, "MyObject4")
|
py::class_<MyObject4, std::unique_ptr<MyObject4, py::nodelete>>(m, "MyObject4")
|
||||||
.def(py::init<int>())
|
.def(py::init<int>())
|
||||||
.def_readwrite("value", &MyObject4::value);
|
.def_readwrite("value", &MyObject4::value);
|
||||||
|
|
||||||
|
// test_large_holder
|
||||||
|
class MyObject5 { // managed by huge_unique_ptr
|
||||||
|
public:
|
||||||
|
MyObject5(int value) : value{value} { print_created(this); }
|
||||||
|
~MyObject5() { print_destroyed(this); }
|
||||||
|
int value;
|
||||||
|
};
|
||||||
py::class_<MyObject5, huge_unique_ptr<MyObject5>>(m, "MyObject5")
|
py::class_<MyObject5, huge_unique_ptr<MyObject5>>(m, "MyObject5")
|
||||||
.def(py::init<int>())
|
.def(py::init<int>())
|
||||||
.def_readwrite("value", &MyObject5::value);
|
.def_readwrite("value", &MyObject5::value);
|
||||||
|
|
||||||
py::implicitly_convertible<py::int_, MyObject1>();
|
// test_shared_ptr_and_references
|
||||||
|
struct SharedPtrRef {
|
||||||
|
struct A {
|
||||||
|
A() { print_created(this); }
|
||||||
|
A(const A &) { print_copy_created(this); }
|
||||||
|
A(A &&) { print_move_created(this); }
|
||||||
|
~A() { print_destroyed(this); }
|
||||||
|
};
|
||||||
|
|
||||||
// Expose constructor stats for the ref type
|
A value = {};
|
||||||
m.def("cstats_ref", &ConstructorStats::get<ref_tag>);
|
std::shared_ptr<A> shared = std::make_shared<A>();
|
||||||
});
|
|
||||||
|
|
||||||
struct SharedPtrRef {
|
|
||||||
struct A {
|
|
||||||
A() { print_created(this); }
|
|
||||||
A(const A &) { print_copy_created(this); }
|
|
||||||
A(A &&) { print_move_created(this); }
|
|
||||||
~A() { print_destroyed(this); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
A value = {};
|
|
||||||
std::shared_ptr<A> shared = std::make_shared<A>();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SharedFromThisRef {
|
|
||||||
struct B : std::enable_shared_from_this<B> {
|
|
||||||
B() { print_created(this); }
|
|
||||||
B(const B &) : std::enable_shared_from_this<B>() { print_copy_created(this); }
|
|
||||||
B(B &&) : std::enable_shared_from_this<B>() { print_move_created(this); }
|
|
||||||
~B() { print_destroyed(this); }
|
|
||||||
};
|
|
||||||
|
|
||||||
B value = {};
|
|
||||||
std::shared_ptr<B> shared = std::make_shared<B>();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Issue #865: shared_from_this doesn't work with virtual inheritance
|
|
||||||
struct SharedFromThisVBase : std::enable_shared_from_this<SharedFromThisVBase> {
|
|
||||||
virtual ~SharedFromThisVBase() = default;
|
|
||||||
};
|
|
||||||
struct SharedFromThisVirt : virtual SharedFromThisVBase {};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class CustomUniquePtr {
|
|
||||||
std::unique_ptr<T> impl;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CustomUniquePtr(T* p) : impl(p) { }
|
|
||||||
T* get() const { return impl.get(); }
|
|
||||||
T* release_ptr() { return impl.release(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, CustomUniquePtr<T>);
|
|
||||||
|
|
||||||
struct ElementBase { virtual void foo() { } /* Force creation of virtual table */ };
|
|
||||||
struct ElementA : ElementBase {
|
|
||||||
ElementA(int v) : v(v) { }
|
|
||||||
int value() { return v; }
|
|
||||||
int v;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ElementList {
|
|
||||||
void add(std::shared_ptr<ElementBase> e) { l.push_back(e); }
|
|
||||||
std::vector<std::shared_ptr<ElementBase>> l;
|
|
||||||
};
|
|
||||||
|
|
||||||
test_initializer smart_ptr_and_references([](py::module &pm) {
|
|
||||||
auto m = pm.def_submodule("smart_ptr");
|
|
||||||
|
|
||||||
using A = SharedPtrRef::A;
|
using A = SharedPtrRef::A;
|
||||||
py::class_<A, std::shared_ptr<A>>(m, "A");
|
py::class_<A, std::shared_ptr<A>>(m, "A");
|
||||||
|
|
||||||
py::class_<SharedPtrRef>(m, "SharedPtrRef")
|
py::class_<SharedPtrRef>(m, "SharedPtrRef")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def_readonly("ref", &SharedPtrRef::value)
|
.def_readonly("ref", &SharedPtrRef::value)
|
||||||
@ -288,9 +187,20 @@ test_initializer smart_ptr_and_references([](py::module &pm) {
|
|||||||
.def("set_ref", [](SharedPtrRef &, const A &) { return true; })
|
.def("set_ref", [](SharedPtrRef &, const A &) { return true; })
|
||||||
.def("set_holder", [](SharedPtrRef &, std::shared_ptr<A>) { return true; });
|
.def("set_holder", [](SharedPtrRef &, std::shared_ptr<A>) { return true; });
|
||||||
|
|
||||||
|
// test_shared_ptr_from_this_and_references
|
||||||
|
struct SharedFromThisRef {
|
||||||
|
struct B : std::enable_shared_from_this<B> {
|
||||||
|
B() { print_created(this); }
|
||||||
|
B(const B &) : std::enable_shared_from_this<B>() { print_copy_created(this); }
|
||||||
|
B(B &&) : std::enable_shared_from_this<B>() { print_move_created(this); }
|
||||||
|
~B() { print_destroyed(this); }
|
||||||
|
};
|
||||||
|
|
||||||
|
B value = {};
|
||||||
|
std::shared_ptr<B> shared = std::make_shared<B>();
|
||||||
|
};
|
||||||
using B = SharedFromThisRef::B;
|
using B = SharedFromThisRef::B;
|
||||||
py::class_<B, std::shared_ptr<B>>(m, "B");
|
py::class_<B, std::shared_ptr<B>>(m, "B");
|
||||||
|
|
||||||
py::class_<SharedFromThisRef>(m, "SharedFromThisRef")
|
py::class_<SharedFromThisRef>(m, "SharedFromThisRef")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def_readonly("bad_wp", &SharedFromThisRef::value)
|
.def_readonly("bad_wp", &SharedFromThisRef::value)
|
||||||
@ -304,31 +214,46 @@ test_initializer smart_ptr_and_references([](py::module &pm) {
|
|||||||
.def("set_holder", [](SharedFromThisRef &, std::shared_ptr<B>) { return true; });
|
.def("set_holder", [](SharedFromThisRef &, std::shared_ptr<B>) { return true; });
|
||||||
|
|
||||||
// Issue #865: shared_from_this doesn't work with virtual inheritance
|
// Issue #865: shared_from_this doesn't work with virtual inheritance
|
||||||
|
struct SharedFromThisVBase : std::enable_shared_from_this<SharedFromThisVBase> {
|
||||||
|
virtual ~SharedFromThisVBase() = default;
|
||||||
|
};
|
||||||
|
struct SharedFromThisVirt : virtual SharedFromThisVBase {};
|
||||||
static std::shared_ptr<SharedFromThisVirt> sft(new SharedFromThisVirt());
|
static std::shared_ptr<SharedFromThisVirt> sft(new SharedFromThisVirt());
|
||||||
py::class_<SharedFromThisVirt, std::shared_ptr<SharedFromThisVirt>>(m, "SharedFromThisVirt")
|
py::class_<SharedFromThisVirt, std::shared_ptr<SharedFromThisVirt>>(m, "SharedFromThisVirt")
|
||||||
.def_static("get", []() { return sft.get(); });
|
.def_static("get", []() { return sft.get(); });
|
||||||
|
|
||||||
|
// test_move_only_holder
|
||||||
struct C {
|
struct C {
|
||||||
C() { print_created(this); }
|
C() { print_created(this); }
|
||||||
~C() { print_destroyed(this); }
|
~C() { print_destroyed(this); }
|
||||||
};
|
};
|
||||||
|
py::class_<C, custom_unique_ptr<C>>(m, "TypeWithMoveOnlyHolder")
|
||||||
|
.def_static("make", []() { return custom_unique_ptr<C>(new C); });
|
||||||
|
|
||||||
py::class_<C, CustomUniquePtr<C>>(m, "TypeWithMoveOnlyHolder")
|
// test_smart_ptr_from_default
|
||||||
.def_static("make", []() { return CustomUniquePtr<C>(new C); });
|
|
||||||
|
|
||||||
struct HeldByDefaultHolder { };
|
struct HeldByDefaultHolder { };
|
||||||
|
|
||||||
py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder")
|
py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {});
|
.def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {});
|
||||||
|
|
||||||
|
// 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
|
||||||
|
struct ElementBase { virtual void foo() { } /* Force creation of virtual table */ };
|
||||||
py::class_<ElementBase, std::shared_ptr<ElementBase>>(m, "ElementBase");
|
py::class_<ElementBase, std::shared_ptr<ElementBase>>(m, "ElementBase");
|
||||||
|
|
||||||
|
struct ElementA : ElementBase {
|
||||||
|
ElementA(int v) : v(v) { }
|
||||||
|
int value() { return v; }
|
||||||
|
int v;
|
||||||
|
};
|
||||||
py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m, "ElementA")
|
py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m, "ElementA")
|
||||||
.def(py::init<int>())
|
.def(py::init<int>())
|
||||||
.def("value", &ElementA::value);
|
.def("value", &ElementA::value);
|
||||||
|
|
||||||
|
struct ElementList {
|
||||||
|
void add(std::shared_ptr<ElementBase> e) { l.push_back(e); }
|
||||||
|
std::vector<std::shared_ptr<ElementBase>> l;
|
||||||
|
};
|
||||||
py::class_<ElementList, std::shared_ptr<ElementList>>(m, "ElementList")
|
py::class_<ElementList, std::shared_ptr<ElementList>>(m, "ElementList")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def("add", &ElementList::add)
|
.def("add", &ElementList::add)
|
||||||
@ -338,4 +263,4 @@ test_initializer smart_ptr_and_references([](py::module &pm) {
|
|||||||
list.append(py::cast(e));
|
list.append(py::cast(e));
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
@ -1,40 +1,35 @@
|
|||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
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):
|
|||||||
|
|
||||||
|
|
||||||
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():
|
|||||||
|
|
||||||
|
|
||||||
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():
|
|||||||
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 @@
|
|||||||
#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) {
|
|||||||
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) {
|
|||||||
#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) {
|
|||||||
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) {
|
|||||||
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
|
// test_vector_int
|
||||||
bool w;
|
|
||||||
uint32_t x;
|
|
||||||
double y;
|
|
||||||
bool z;
|
|
||||||
};
|
|
||||||
|
|
||||||
test_initializer stl_binder_vector([](py::module &m) {
|
|
||||||
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", ×_ten<std::map<int, E_nc>>, py::return_value_policy::reference);
|
m.def("get_mnc", ×_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", ×_ten<std::unordered_map<int, E_nc>>, py::return_value_policy::reference);
|
m.def("get_umnc", ×_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}};});
|
||||||
|
}
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
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():
|
|||||||
|
|
||||||
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():
|
|||||||
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_vector_custom():
|
||||||
|
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}]"
|
||||||
|
|
||||||
|
vv_a = m.VectorVectorEl()
|
||||||
|
vv_a.append(v_a)
|
||||||
|
vv_b = vv_a[0]
|
||||||
|
assert str(vv_b) == "VectorEl[El{1}, El{2}]"
|
||||||
|
|
||||||
|
|
||||||
def test_map_string_double():
|
def test_map_string_double():
|
||||||
from pybind11_tests import MapStringDouble, UnorderedMapStringDouble
|
mm = m.MapStringDouble()
|
||||||
|
mm['a'] = 1
|
||||||
|
mm['b'] = 2.5
|
||||||
|
|
||||||
m = MapStringDouble()
|
assert list(mm) == ['a', 'b']
|
||||||
m['a'] = 1
|
assert list(mm.items()) == [('a', 1), ('b', 2.5)]
|
||||||
m['b'] = 2.5
|
assert str(mm) == "MapStringDouble{a: 1, b: 2.5}"
|
||||||
|
|
||||||
assert list(m) == ['a', 'b']
|
um = m.UnorderedMapStringDouble()
|
||||||
assert list(m.items()) == [('a', 1), ('b', 2.5)]
|
|
||||||
assert str(m) == "MapStringDouble{a: 1, b: 2.5}"
|
|
||||||
|
|
||||||
um = 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():
|
|||||||
|
|
||||||
|
|
||||||
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():
|
|||||||
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():
|
|||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
@ -145,16 +145,147 @@ class NCVirtTrampoline : public NCVirt {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int runExampleVirt(ExampleVirt *ex, int value) {
|
struct Base {
|
||||||
return ex->run(value);
|
/* for some reason MSVC2015 can't compile this if the function is pure virtual */
|
||||||
}
|
virtual std::string dispatch() const { return {}; };
|
||||||
|
};
|
||||||
|
|
||||||
bool runExampleVirtBool(ExampleVirt* ex) {
|
struct DispatchIssue : Base {
|
||||||
return ex->run_bool();
|
virtual std::string dispatch() const {
|
||||||
}
|
PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void runExampleVirtVirtual(ExampleVirt *ex) {
|
// Forward declaration (so that we can put the main tests here; the inherited virtual approaches are
|
||||||
ex->pure_virtual();
|
// rather long).
|
||||||
|
void initialize_inherited_virtuals(py::module &m);
|
||||||
|
|
||||||
|
TEST_SUBMODULE(virtual_functions, m) {
|
||||||
|
// test_override
|
||||||
|
py::class_<ExampleVirt, PyExampleVirt>(m, "ExampleVirt")
|
||||||
|
.def(py::init<int>())
|
||||||
|
/* Reference original class in function definitions */
|
||||||
|
.def("run", &ExampleVirt::run)
|
||||||
|
.def("run_bool", &ExampleVirt::run_bool)
|
||||||
|
.def("pure_virtual", &ExampleVirt::pure_virtual);
|
||||||
|
|
||||||
|
py::class_<NonCopyable>(m, "NonCopyable")
|
||||||
|
.def(py::init<int, int>());
|
||||||
|
|
||||||
|
py::class_<Movable>(m, "Movable")
|
||||||
|
.def(py::init<int, int>());
|
||||||
|
|
||||||
|
// test_move_support
|
||||||
|
#if !defined(__INTEL_COMPILER)
|
||||||
|
py::class_<NCVirt, NCVirtTrampoline>(m, "NCVirt")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("get_noncopyable", &NCVirt::get_noncopyable)
|
||||||
|
.def("get_movable", &NCVirt::get_movable)
|
||||||
|
.def("print_nc", &NCVirt::print_nc)
|
||||||
|
.def("print_movable", &NCVirt::print_movable);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m.def("runExampleVirt", [](ExampleVirt *ex, int value) { return ex->run(value); });
|
||||||
|
m.def("runExampleVirtBool", [](ExampleVirt* ex) { return ex->run_bool(); });
|
||||||
|
m.def("runExampleVirtVirtual", [](ExampleVirt *ex) { ex->pure_virtual(); });
|
||||||
|
|
||||||
|
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
|
||||||
|
initialize_inherited_virtuals(m);
|
||||||
|
|
||||||
|
// test_alias_delay_initialization1
|
||||||
|
// don't invoke Python dispatch classes by default when instantiating C++ classes
|
||||||
|
// that were not extended on the Python side
|
||||||
|
struct A {
|
||||||
|
virtual ~A() {}
|
||||||
|
virtual void f() { py::print("A.f()"); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PyA : A {
|
||||||
|
PyA() { py::print("PyA.PyA()"); }
|
||||||
|
~PyA() { py::print("PyA.~PyA()"); }
|
||||||
|
|
||||||
|
void f() override {
|
||||||
|
py::print("PyA.f()");
|
||||||
|
PYBIND11_OVERLOAD(void, A, f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
py::class_<A, PyA>(m, "A")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("f", &A::f);
|
||||||
|
|
||||||
|
m.def("call_f", [](A *a) { a->f(); });
|
||||||
|
|
||||||
|
// test_alias_delay_initialization2
|
||||||
|
// ... unless we explicitly request it, as in this example:
|
||||||
|
struct A2 {
|
||||||
|
virtual ~A2() {}
|
||||||
|
virtual void f() { py::print("A2.f()"); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PyA2 : A2 {
|
||||||
|
PyA2() { py::print("PyA2.PyA2()"); }
|
||||||
|
~PyA2() { py::print("PyA2.~PyA2()"); }
|
||||||
|
void f() override {
|
||||||
|
py::print("PyA2.f()");
|
||||||
|
PYBIND11_OVERLOAD(void, A2, f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
py::class_<A2, PyA2>(m, "A2")
|
||||||
|
.def(py::init_alias<>())
|
||||||
|
.def("f", &A2::f);
|
||||||
|
|
||||||
|
m.def("call_f", [](A2 *a2) { a2->f(); });
|
||||||
|
|
||||||
|
// test_dispatch_issue
|
||||||
|
// #159: virtual function dispatch has problems with similar-named functions
|
||||||
|
py::class_<Base, DispatchIssue>(m, "DispatchIssue")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("dispatch", &Base::dispatch);
|
||||||
|
|
||||||
|
m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
|
||||||
|
|
||||||
|
// test_override_ref
|
||||||
|
// #392/397: overridding reference-returning functions
|
||||||
|
class OverrideTest {
|
||||||
|
public:
|
||||||
|
struct A { std::string value = "hi"; };
|
||||||
|
std::string v;
|
||||||
|
A a;
|
||||||
|
explicit OverrideTest(const std::string &v) : v{v} {}
|
||||||
|
virtual std::string str_value() { return v; }
|
||||||
|
virtual std::string &str_ref() { return v; }
|
||||||
|
virtual A A_value() { return a; }
|
||||||
|
virtual A &A_ref() { return a; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class PyOverrideTest : public OverrideTest {
|
||||||
|
public:
|
||||||
|
using OverrideTest::OverrideTest;
|
||||||
|
std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
|
||||||
|
// Not allowed (uncommenting should hit a static_assert failure): we can't get a reference
|
||||||
|
// to a python numeric value, since we only copy values in the numeric type caster:
|
||||||
|
// std::string &str_ref() override { PYBIND11_OVERLOAD(std::string &, OverrideTest, str_ref); }
|
||||||
|
// But we can work around it like this:
|
||||||
|
private:
|
||||||
|
std::string _tmp;
|
||||||
|
std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); }
|
||||||
|
public:
|
||||||
|
std::string &str_ref() override { return _tmp = str_ref_helper(); }
|
||||||
|
|
||||||
|
A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); }
|
||||||
|
A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); }
|
||||||
|
};
|
||||||
|
|
||||||
|
py::class_<OverrideTest::A>(m, "OverrideTest_A")
|
||||||
|
.def_readwrite("value", &OverrideTest::A::value);
|
||||||
|
py::class_<OverrideTest, PyOverrideTest>(m, "OverrideTest")
|
||||||
|
.def(py::init<const std::string &>())
|
||||||
|
.def("str_value", &OverrideTest::str_value)
|
||||||
|
// .def("str_ref", &OverrideTest::str_ref)
|
||||||
|
.def("A_value", &OverrideTest::A_value)
|
||||||
|
.def("A_ref", &OverrideTest::A_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -281,6 +412,8 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
void initialize_inherited_virtuals(py::module &m) {
|
void initialize_inherited_virtuals(py::module &m) {
|
||||||
|
// test_inherited_virtuals
|
||||||
|
|
||||||
// Method 1: repeat
|
// Method 1: repeat
|
||||||
py::class_<A_Repeat, PyA_Repeat>(m, "A_Repeat")
|
py::class_<A_Repeat, PyA_Repeat>(m, "A_Repeat")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
@ -295,6 +428,7 @@ void initialize_inherited_virtuals(py::module &m) {
|
|||||||
py::class_<D_Repeat, C_Repeat, PyD_Repeat>(m, "D_Repeat")
|
py::class_<D_Repeat, C_Repeat, PyD_Repeat>(m, "D_Repeat")
|
||||||
.def(py::init<>());
|
.def(py::init<>());
|
||||||
|
|
||||||
|
// test_
|
||||||
// Method 2: Templated trampolines
|
// Method 2: Templated trampolines
|
||||||
py::class_<A_Tpl, PyA_Tpl<>>(m, "A_Tpl")
|
py::class_<A_Tpl, PyA_Tpl<>>(m, "A_Tpl")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
@ -311,137 +445,3 @@ void initialize_inherited_virtuals(py::module &m) {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Base {
|
|
||||||
/* for some reason MSVC2015 can't compile this if the function is pure virtual */
|
|
||||||
virtual std::string dispatch() const { return {}; };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DispatchIssue : Base {
|
|
||||||
virtual std::string dispatch() const {
|
|
||||||
PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_SUBMODULE(virtual_functions, m) {
|
|
||||||
py::class_<ExampleVirt, PyExampleVirt>(m, "ExampleVirt")
|
|
||||||
.def(py::init<int>())
|
|
||||||
/* Reference original class in function definitions */
|
|
||||||
.def("run", &ExampleVirt::run)
|
|
||||||
.def("run_bool", &ExampleVirt::run_bool)
|
|
||||||
.def("pure_virtual", &ExampleVirt::pure_virtual);
|
|
||||||
|
|
||||||
py::class_<NonCopyable>(m, "NonCopyable")
|
|
||||||
.def(py::init<int, int>());
|
|
||||||
|
|
||||||
py::class_<Movable>(m, "Movable")
|
|
||||||
.def(py::init<int, int>());
|
|
||||||
|
|
||||||
#if !defined(__INTEL_COMPILER)
|
|
||||||
py::class_<NCVirt, NCVirtTrampoline>(m, "NCVirt")
|
|
||||||
.def(py::init<>())
|
|
||||||
.def("get_noncopyable", &NCVirt::get_noncopyable)
|
|
||||||
.def("get_movable", &NCVirt::get_movable)
|
|
||||||
.def("print_nc", &NCVirt::print_nc)
|
|
||||||
.def("print_movable", &NCVirt::print_movable);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m.def("runExampleVirt", &runExampleVirt);
|
|
||||||
m.def("runExampleVirtBool", &runExampleVirtBool);
|
|
||||||
m.def("runExampleVirtVirtual", &runExampleVirtVirtual);
|
|
||||||
|
|
||||||
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
|
|
||||||
initialize_inherited_virtuals(m);
|
|
||||||
|
|
||||||
// test_alias_delay_initialization1
|
|
||||||
// don't invoke Python dispatch classes by default when instantiating C++ classes
|
|
||||||
// that were not extended on the Python side
|
|
||||||
struct A {
|
|
||||||
virtual ~A() {}
|
|
||||||
virtual void f() { py::print("A.f()"); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PyA : A {
|
|
||||||
PyA() { py::print("PyA.PyA()"); }
|
|
||||||
~PyA() { py::print("PyA.~PyA()"); }
|
|
||||||
|
|
||||||
void f() override {
|
|
||||||
py::print("PyA.f()");
|
|
||||||
PYBIND11_OVERLOAD(void, A, f);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
py::class_<A, PyA>(m, "A")
|
|
||||||
.def(py::init<>())
|
|
||||||
.def("f", &A::f);
|
|
||||||
|
|
||||||
m.def("call_f", [](A *a) { a->f(); });
|
|
||||||
|
|
||||||
// test_alias_delay_initialization2
|
|
||||||
// ... unless we explicitly request it, as in this example:
|
|
||||||
struct A2 {
|
|
||||||
virtual ~A2() {}
|
|
||||||
virtual void f() { py::print("A2.f()"); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PyA2 : A2 {
|
|
||||||
PyA2() { py::print("PyA2.PyA2()"); }
|
|
||||||
~PyA2() { py::print("PyA2.~PyA2()"); }
|
|
||||||
void f() override {
|
|
||||||
py::print("PyA2.f()");
|
|
||||||
PYBIND11_OVERLOAD(void, A2, f);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
py::class_<A2, PyA2>(m, "A2")
|
|
||||||
.def(py::init_alias<>())
|
|
||||||
.def("f", &A2::f);
|
|
||||||
|
|
||||||
m.def("call_f", [](A2 *a2) { a2->f(); });
|
|
||||||
|
|
||||||
// #159: virtual function dispatch has problems with similar-named functions
|
|
||||||
py::class_<Base, DispatchIssue>(m, "DispatchIssue")
|
|
||||||
.def(py::init<>())
|
|
||||||
.def("dispatch", &Base::dispatch);
|
|
||||||
|
|
||||||
m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
|
|
||||||
|
|
||||||
// #392/397: overridding reference-returning functions
|
|
||||||
class OverrideTest {
|
|
||||||
public:
|
|
||||||
struct A { std::string value = "hi"; };
|
|
||||||
std::string v;
|
|
||||||
A a;
|
|
||||||
explicit OverrideTest(const std::string &v) : v{v} {}
|
|
||||||
virtual std::string str_value() { return v; }
|
|
||||||
virtual std::string &str_ref() { return v; }
|
|
||||||
virtual A A_value() { return a; }
|
|
||||||
virtual A &A_ref() { return a; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class PyOverrideTest : public OverrideTest {
|
|
||||||
public:
|
|
||||||
using OverrideTest::OverrideTest;
|
|
||||||
std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
|
|
||||||
// Not allowed (uncommenting should hit a static_assert failure): we can't get a reference
|
|
||||||
// to a python numeric value, since we only copy values in the numeric type caster:
|
|
||||||
// std::string &str_ref() override { PYBIND11_OVERLOAD(std::string &, OverrideTest, str_ref); }
|
|
||||||
// But we can work around it like this:
|
|
||||||
private:
|
|
||||||
std::string _tmp;
|
|
||||||
std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); }
|
|
||||||
public:
|
|
||||||
std::string &str_ref() override { return _tmp = str_ref_helper(); }
|
|
||||||
|
|
||||||
A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); }
|
|
||||||
A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); }
|
|
||||||
};
|
|
||||||
|
|
||||||
py::class_<OverrideTest::A>(m, "OverrideTest_A")
|
|
||||||
.def_readwrite("value", &OverrideTest::A::value);
|
|
||||||
py::class_<OverrideTest, PyOverrideTest>(m, "OverrideTest")
|
|
||||||
.def(py::init<const std::string &>())
|
|
||||||
.def("str_value", &OverrideTest::str_value)
|
|
||||||
// .def("str_ref", &OverrideTest::str_ref)
|
|
||||||
.def("A_value", &OverrideTest::A_value)
|
|
||||||
.def("A_ref", &OverrideTest::A_ref);
|
|
||||||
}
|
|
||||||
|
@ -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():
|
|||||||
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"
|
|
||||||
|
Loading…
Reference in New Issue
Block a user