Spaces:
Sleeping
Sleeping
0308a1b16ebf8b9711d3d72c37774bd06959075a0fa32d7c6521ae3e95b8fa89
Browse files- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_buffers.cpp +212 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_buffers.py +164 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_builtin_casters.cpp +278 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_builtin_casters.py +537 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_call_policies.cpp +107 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_call_policies.py +249 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_callbacks.cpp +188 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_callbacks.py +195 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_chrono.cpp +84 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_chrono.py +209 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_class.cpp +534 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_class.py +466 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/CMakeLists.txt +84 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/embed.cpp +21 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt +26 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt +38 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt +45 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/main.cpp +6 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt +39 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt +34 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt +40 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/test.py +6 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_constants_and_functions.cpp +165 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_constants_and_functions.py +53 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_copy_move.cpp +238 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_copy_move.py +125 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_custom_type_casters.cpp +141 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_custom_type_casters.py +116 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_docstring_options.cpp +69 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_docstring_options.py +42 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_eigen.cpp +341 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_eigen.py +770 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_embed/CMakeLists.txt +46 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_embed/catch.cpp +22 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_embed/external_module.cpp +23 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_embed/test_interpreter.cpp +285 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_embed/test_interpreter.py +10 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_enum.cpp +87 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_enum.py +236 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_eval.cpp +101 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_eval.py +35 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_eval_call.py +5 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_exceptions.cpp +238 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_exceptions.h +12 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_exceptions.py +223 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_factory_constructors.cpp +382 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_factory_constructors.py +520 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_gil_scoped.cpp +49 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_gil_scoped.py +94 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_iostream.cpp +125 -0
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_buffers.cpp
ADDED
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_buffers.cpp -- supporting Pythons' buffer protocol
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "pybind11_tests.h"
|
11 |
+
#include "constructor_stats.h"
|
12 |
+
#include <pybind11/stl.h>
|
13 |
+
|
14 |
+
TEST_SUBMODULE(buffers, m) {
|
15 |
+
// test_from_python / test_to_python:
|
16 |
+
class Matrix {
|
17 |
+
public:
|
18 |
+
Matrix(py::ssize_t rows, py::ssize_t cols) : m_rows(rows), m_cols(cols) {
|
19 |
+
print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
20 |
+
m_data = new float[(size_t) (rows*cols)];
|
21 |
+
memset(m_data, 0, sizeof(float) * (size_t) (rows * cols));
|
22 |
+
}
|
23 |
+
|
24 |
+
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
|
25 |
+
print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
26 |
+
m_data = new float[(size_t) (m_rows * m_cols)];
|
27 |
+
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
|
28 |
+
}
|
29 |
+
|
30 |
+
Matrix(Matrix &&s) noexcept : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
|
31 |
+
print_move_created(this);
|
32 |
+
s.m_rows = 0;
|
33 |
+
s.m_cols = 0;
|
34 |
+
s.m_data = nullptr;
|
35 |
+
}
|
36 |
+
|
37 |
+
~Matrix() {
|
38 |
+
print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
39 |
+
delete[] m_data;
|
40 |
+
}
|
41 |
+
|
42 |
+
Matrix &operator=(const Matrix &s) {
|
43 |
+
print_copy_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
44 |
+
delete[] m_data;
|
45 |
+
m_rows = s.m_rows;
|
46 |
+
m_cols = s.m_cols;
|
47 |
+
m_data = new float[(size_t) (m_rows * m_cols)];
|
48 |
+
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
|
49 |
+
return *this;
|
50 |
+
}
|
51 |
+
|
52 |
+
Matrix &operator=(Matrix &&s) noexcept {
|
53 |
+
print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
54 |
+
if (&s != this) {
|
55 |
+
delete[] m_data;
|
56 |
+
m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data;
|
57 |
+
s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr;
|
58 |
+
}
|
59 |
+
return *this;
|
60 |
+
}
|
61 |
+
|
62 |
+
float operator()(py::ssize_t i, py::ssize_t j) const {
|
63 |
+
return m_data[(size_t) (i*m_cols + j)];
|
64 |
+
}
|
65 |
+
|
66 |
+
float &operator()(py::ssize_t i, py::ssize_t j) {
|
67 |
+
return m_data[(size_t) (i*m_cols + j)];
|
68 |
+
}
|
69 |
+
|
70 |
+
float *data() { return m_data; }
|
71 |
+
|
72 |
+
py::ssize_t rows() const { return m_rows; }
|
73 |
+
py::ssize_t cols() const { return m_cols; }
|
74 |
+
private:
|
75 |
+
py::ssize_t m_rows;
|
76 |
+
py::ssize_t m_cols;
|
77 |
+
float *m_data;
|
78 |
+
};
|
79 |
+
py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
|
80 |
+
.def(py::init<py::ssize_t, py::ssize_t>())
|
81 |
+
/// Construct from a buffer
|
82 |
+
.def(py::init([](const py::buffer &b) {
|
83 |
+
py::buffer_info info = b.request();
|
84 |
+
if (info.format != py::format_descriptor<float>::format() || info.ndim != 2)
|
85 |
+
throw std::runtime_error("Incompatible buffer format!");
|
86 |
+
|
87 |
+
auto v = new Matrix(info.shape[0], info.shape[1]);
|
88 |
+
memcpy(v->data(), info.ptr, sizeof(float) * (size_t) (v->rows() * v->cols()));
|
89 |
+
return v;
|
90 |
+
}))
|
91 |
+
|
92 |
+
.def("rows", &Matrix::rows)
|
93 |
+
.def("cols", &Matrix::cols)
|
94 |
+
|
95 |
+
/// Bare bones interface
|
96 |
+
.def("__getitem__",
|
97 |
+
[](const Matrix &m, std::pair<py::ssize_t, py::ssize_t> i) {
|
98 |
+
if (i.first >= m.rows() || i.second >= m.cols())
|
99 |
+
throw py::index_error();
|
100 |
+
return m(i.first, i.second);
|
101 |
+
})
|
102 |
+
.def("__setitem__",
|
103 |
+
[](Matrix &m, std::pair<py::ssize_t, py::ssize_t> i, float v) {
|
104 |
+
if (i.first >= m.rows() || i.second >= m.cols())
|
105 |
+
throw py::index_error();
|
106 |
+
m(i.first, i.second) = v;
|
107 |
+
})
|
108 |
+
/// Provide buffer access
|
109 |
+
.def_buffer([](Matrix &m) -> py::buffer_info {
|
110 |
+
return py::buffer_info(
|
111 |
+
m.data(), /* Pointer to buffer */
|
112 |
+
{ m.rows(), m.cols() }, /* Buffer dimensions */
|
113 |
+
{ sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */
|
114 |
+
sizeof(float) }
|
115 |
+
);
|
116 |
+
});
|
117 |
+
|
118 |
+
// test_inherited_protocol
|
119 |
+
class SquareMatrix : public Matrix {
|
120 |
+
public:
|
121 |
+
SquareMatrix(py::ssize_t n) : Matrix(n, n) { }
|
122 |
+
};
|
123 |
+
// Derived classes inherit the buffer protocol and the buffer access function
|
124 |
+
py::class_<SquareMatrix, Matrix>(m, "SquareMatrix")
|
125 |
+
.def(py::init<py::ssize_t>());
|
126 |
+
|
127 |
+
|
128 |
+
// test_pointer_to_member_fn
|
129 |
+
// Tests that passing a pointer to member to the base class works in
|
130 |
+
// the derived class.
|
131 |
+
struct Buffer {
|
132 |
+
int32_t value = 0;
|
133 |
+
|
134 |
+
py::buffer_info get_buffer_info() {
|
135 |
+
return py::buffer_info(&value, sizeof(value),
|
136 |
+
py::format_descriptor<int32_t>::format(), 1);
|
137 |
+
}
|
138 |
+
};
|
139 |
+
py::class_<Buffer>(m, "Buffer", py::buffer_protocol())
|
140 |
+
.def(py::init<>())
|
141 |
+
.def_readwrite("value", &Buffer::value)
|
142 |
+
.def_buffer(&Buffer::get_buffer_info);
|
143 |
+
|
144 |
+
|
145 |
+
class ConstBuffer {
|
146 |
+
std::unique_ptr<int32_t> value;
|
147 |
+
|
148 |
+
public:
|
149 |
+
int32_t get_value() const { return *value; }
|
150 |
+
void set_value(int32_t v) { *value = v; }
|
151 |
+
|
152 |
+
py::buffer_info get_buffer_info() const {
|
153 |
+
return py::buffer_info(value.get(), sizeof(*value),
|
154 |
+
py::format_descriptor<int32_t>::format(), 1);
|
155 |
+
}
|
156 |
+
|
157 |
+
ConstBuffer() : value(new int32_t{0}) {}
|
158 |
+
};
|
159 |
+
py::class_<ConstBuffer>(m, "ConstBuffer", py::buffer_protocol())
|
160 |
+
.def(py::init<>())
|
161 |
+
.def_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value)
|
162 |
+
.def_buffer(&ConstBuffer::get_buffer_info);
|
163 |
+
|
164 |
+
struct DerivedBuffer : public Buffer { };
|
165 |
+
py::class_<DerivedBuffer>(m, "DerivedBuffer", py::buffer_protocol())
|
166 |
+
.def(py::init<>())
|
167 |
+
.def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value)
|
168 |
+
.def_buffer(&DerivedBuffer::get_buffer_info);
|
169 |
+
|
170 |
+
struct BufferReadOnly {
|
171 |
+
const uint8_t value = 0;
|
172 |
+
BufferReadOnly(uint8_t value): value(value) {}
|
173 |
+
|
174 |
+
py::buffer_info get_buffer_info() {
|
175 |
+
return py::buffer_info(&value, 1);
|
176 |
+
}
|
177 |
+
};
|
178 |
+
py::class_<BufferReadOnly>(m, "BufferReadOnly", py::buffer_protocol())
|
179 |
+
.def(py::init<uint8_t>())
|
180 |
+
.def_buffer(&BufferReadOnly::get_buffer_info);
|
181 |
+
|
182 |
+
struct BufferReadOnlySelect {
|
183 |
+
uint8_t value = 0;
|
184 |
+
bool readonly = false;
|
185 |
+
|
186 |
+
py::buffer_info get_buffer_info() {
|
187 |
+
return py::buffer_info(&value, 1, readonly);
|
188 |
+
}
|
189 |
+
};
|
190 |
+
py::class_<BufferReadOnlySelect>(m, "BufferReadOnlySelect", py::buffer_protocol())
|
191 |
+
.def(py::init<>())
|
192 |
+
.def_readwrite("value", &BufferReadOnlySelect::value)
|
193 |
+
.def_readwrite("readonly", &BufferReadOnlySelect::readonly)
|
194 |
+
.def_buffer(&BufferReadOnlySelect::get_buffer_info);
|
195 |
+
|
196 |
+
// Expose buffer_info for testing.
|
197 |
+
py::class_<py::buffer_info>(m, "buffer_info")
|
198 |
+
.def(py::init<>())
|
199 |
+
.def_readonly("itemsize", &py::buffer_info::itemsize)
|
200 |
+
.def_readonly("size", &py::buffer_info::size)
|
201 |
+
.def_readonly("format", &py::buffer_info::format)
|
202 |
+
.def_readonly("ndim", &py::buffer_info::ndim)
|
203 |
+
.def_readonly("shape", &py::buffer_info::shape)
|
204 |
+
.def_readonly("strides", &py::buffer_info::strides)
|
205 |
+
.def_readonly("readonly", &py::buffer_info::readonly)
|
206 |
+
.def("__repr__", [](py::handle self) {
|
207 |
+
return py::str("itemsize={0.itemsize!r}, size={0.size!r}, format={0.format!r}, ndim={0.ndim!r}, shape={0.shape!r}, strides={0.strides!r}, readonly={0.readonly!r}").format(self);
|
208 |
+
})
|
209 |
+
;
|
210 |
+
|
211 |
+
m.def("get_buffer_info", [](const py::buffer &buffer) { return buffer.request(); });
|
212 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_buffers.py
ADDED
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import io
|
3 |
+
import struct
|
4 |
+
import ctypes
|
5 |
+
|
6 |
+
import pytest
|
7 |
+
|
8 |
+
import env # noqa: F401
|
9 |
+
|
10 |
+
from pybind11_tests import buffers as m
|
11 |
+
from pybind11_tests import ConstructorStats
|
12 |
+
|
13 |
+
np = pytest.importorskip("numpy")
|
14 |
+
|
15 |
+
|
16 |
+
def test_from_python():
|
17 |
+
with pytest.raises(RuntimeError) as excinfo:
|
18 |
+
m.Matrix(np.array([1, 2, 3])) # trying to assign a 1D array
|
19 |
+
assert str(excinfo.value) == "Incompatible buffer format!"
|
20 |
+
|
21 |
+
m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32)
|
22 |
+
m4 = m.Matrix(m3)
|
23 |
+
|
24 |
+
for i in range(m4.rows()):
|
25 |
+
for j in range(m4.cols()):
|
26 |
+
assert m3[i, j] == m4[i, j]
|
27 |
+
|
28 |
+
cstats = ConstructorStats.get(m.Matrix)
|
29 |
+
assert cstats.alive() == 1
|
30 |
+
del m3, m4
|
31 |
+
assert cstats.alive() == 0
|
32 |
+
assert cstats.values() == ["2x3 matrix"]
|
33 |
+
assert cstats.copy_constructions == 0
|
34 |
+
# assert cstats.move_constructions >= 0 # Don't invoke any
|
35 |
+
assert cstats.copy_assignments == 0
|
36 |
+
assert cstats.move_assignments == 0
|
37 |
+
|
38 |
+
|
39 |
+
# https://foss.heptapod.net/pypy/pypy/-/issues/2444
|
40 |
+
def test_to_python():
|
41 |
+
mat = m.Matrix(5, 4)
|
42 |
+
assert memoryview(mat).shape == (5, 4)
|
43 |
+
|
44 |
+
assert mat[2, 3] == 0
|
45 |
+
mat[2, 3] = 4.0
|
46 |
+
mat[3, 2] = 7.0
|
47 |
+
assert mat[2, 3] == 4
|
48 |
+
assert mat[3, 2] == 7
|
49 |
+
assert struct.unpack_from("f", mat, (3 * 4 + 2) * 4) == (7,)
|
50 |
+
assert struct.unpack_from("f", mat, (2 * 4 + 3) * 4) == (4,)
|
51 |
+
|
52 |
+
mat2 = np.array(mat, copy=False)
|
53 |
+
assert mat2.shape == (5, 4)
|
54 |
+
assert abs(mat2).sum() == 11
|
55 |
+
assert mat2[2, 3] == 4 and mat2[3, 2] == 7
|
56 |
+
mat2[2, 3] = 5
|
57 |
+
assert mat2[2, 3] == 5
|
58 |
+
|
59 |
+
cstats = ConstructorStats.get(m.Matrix)
|
60 |
+
assert cstats.alive() == 1
|
61 |
+
del mat
|
62 |
+
pytest.gc_collect()
|
63 |
+
assert cstats.alive() == 1
|
64 |
+
del mat2 # holds a mat reference
|
65 |
+
pytest.gc_collect()
|
66 |
+
assert cstats.alive() == 0
|
67 |
+
assert cstats.values() == ["5x4 matrix"]
|
68 |
+
assert cstats.copy_constructions == 0
|
69 |
+
# assert cstats.move_constructions >= 0 # Don't invoke any
|
70 |
+
assert cstats.copy_assignments == 0
|
71 |
+
assert cstats.move_assignments == 0
|
72 |
+
|
73 |
+
|
74 |
+
def test_inherited_protocol():
|
75 |
+
"""SquareMatrix is derived from Matrix and inherits the buffer protocol"""
|
76 |
+
|
77 |
+
matrix = m.SquareMatrix(5)
|
78 |
+
assert memoryview(matrix).shape == (5, 5)
|
79 |
+
assert np.asarray(matrix).shape == (5, 5)
|
80 |
+
|
81 |
+
|
82 |
+
def test_pointer_to_member_fn():
|
83 |
+
for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]:
|
84 |
+
buf = cls()
|
85 |
+
buf.value = 0x12345678
|
86 |
+
value = struct.unpack("i", bytearray(buf))[0]
|
87 |
+
assert value == 0x12345678
|
88 |
+
|
89 |
+
|
90 |
+
def test_readonly_buffer():
|
91 |
+
buf = m.BufferReadOnly(0x64)
|
92 |
+
view = memoryview(buf)
|
93 |
+
assert view[0] == b"d" if env.PY2 else 0x64
|
94 |
+
assert view.readonly
|
95 |
+
with pytest.raises(TypeError):
|
96 |
+
view[0] = b"\0" if env.PY2 else 0
|
97 |
+
|
98 |
+
|
99 |
+
def test_selective_readonly_buffer():
|
100 |
+
buf = m.BufferReadOnlySelect()
|
101 |
+
|
102 |
+
memoryview(buf)[0] = b"d" if env.PY2 else 0x64
|
103 |
+
assert buf.value == 0x64
|
104 |
+
|
105 |
+
io.BytesIO(b"A").readinto(buf)
|
106 |
+
assert buf.value == ord(b"A")
|
107 |
+
|
108 |
+
buf.readonly = True
|
109 |
+
with pytest.raises(TypeError):
|
110 |
+
memoryview(buf)[0] = b"\0" if env.PY2 else 0
|
111 |
+
with pytest.raises(TypeError):
|
112 |
+
io.BytesIO(b"1").readinto(buf)
|
113 |
+
|
114 |
+
|
115 |
+
def test_ctypes_array_1d():
|
116 |
+
char1d = (ctypes.c_char * 10)()
|
117 |
+
int1d = (ctypes.c_int * 15)()
|
118 |
+
long1d = (ctypes.c_long * 7)()
|
119 |
+
|
120 |
+
for carray in (char1d, int1d, long1d):
|
121 |
+
info = m.get_buffer_info(carray)
|
122 |
+
assert info.itemsize == ctypes.sizeof(carray._type_)
|
123 |
+
assert info.size == len(carray)
|
124 |
+
assert info.ndim == 1
|
125 |
+
assert info.shape == [info.size]
|
126 |
+
assert info.strides == [info.itemsize]
|
127 |
+
assert not info.readonly
|
128 |
+
|
129 |
+
|
130 |
+
def test_ctypes_array_2d():
|
131 |
+
char2d = ((ctypes.c_char * 10) * 4)()
|
132 |
+
int2d = ((ctypes.c_int * 15) * 3)()
|
133 |
+
long2d = ((ctypes.c_long * 7) * 2)()
|
134 |
+
|
135 |
+
for carray in (char2d, int2d, long2d):
|
136 |
+
info = m.get_buffer_info(carray)
|
137 |
+
assert info.itemsize == ctypes.sizeof(carray[0]._type_)
|
138 |
+
assert info.size == len(carray) * len(carray[0])
|
139 |
+
assert info.ndim == 2
|
140 |
+
assert info.shape == [len(carray), len(carray[0])]
|
141 |
+
assert info.strides == [info.itemsize * len(carray[0]), info.itemsize]
|
142 |
+
assert not info.readonly
|
143 |
+
|
144 |
+
|
145 |
+
@pytest.mark.skipif(
|
146 |
+
"env.PYPY and env.PY2", reason="PyPy2 bytes buffer not reported as readonly"
|
147 |
+
)
|
148 |
+
def test_ctypes_from_buffer():
|
149 |
+
test_pystr = b"0123456789"
|
150 |
+
for pyarray in (test_pystr, bytearray(test_pystr)):
|
151 |
+
pyinfo = m.get_buffer_info(pyarray)
|
152 |
+
|
153 |
+
if pyinfo.readonly:
|
154 |
+
cbytes = (ctypes.c_char * len(pyarray)).from_buffer_copy(pyarray)
|
155 |
+
cinfo = m.get_buffer_info(cbytes)
|
156 |
+
else:
|
157 |
+
cbytes = (ctypes.c_char * len(pyarray)).from_buffer(pyarray)
|
158 |
+
cinfo = m.get_buffer_info(cbytes)
|
159 |
+
|
160 |
+
assert cinfo.size == pyinfo.size
|
161 |
+
assert cinfo.ndim == pyinfo.ndim
|
162 |
+
assert cinfo.shape == pyinfo.shape
|
163 |
+
assert cinfo.strides == pyinfo.strides
|
164 |
+
assert not cinfo.readonly
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_builtin_casters.cpp
ADDED
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_builtin_casters.cpp -- Casters available without any additional headers
|
3 |
+
|
4 |
+
Copyright (c) 2017 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "pybind11_tests.h"
|
11 |
+
#include <pybind11/complex.h>
|
12 |
+
|
13 |
+
#if defined(_MSC_VER)
|
14 |
+
# pragma warning(push)
|
15 |
+
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
16 |
+
#endif
|
17 |
+
|
18 |
+
struct ConstRefCasted {
|
19 |
+
int tag;
|
20 |
+
};
|
21 |
+
|
22 |
+
PYBIND11_NAMESPACE_BEGIN(pybind11)
|
23 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
24 |
+
template <>
|
25 |
+
class type_caster<ConstRefCasted> {
|
26 |
+
public:
|
27 |
+
static constexpr auto name = _<ConstRefCasted>();
|
28 |
+
|
29 |
+
// Input is unimportant, a new value will always be constructed based on the
|
30 |
+
// cast operator.
|
31 |
+
bool load(handle, bool) { return true; }
|
32 |
+
|
33 |
+
operator ConstRefCasted &&() {
|
34 |
+
value = {1};
|
35 |
+
// NOLINTNEXTLINE(performance-move-const-arg)
|
36 |
+
return std::move(value);
|
37 |
+
}
|
38 |
+
operator ConstRefCasted&() { value = {2}; return value; }
|
39 |
+
operator ConstRefCasted*() { value = {3}; return &value; }
|
40 |
+
|
41 |
+
operator const ConstRefCasted&() { value = {4}; return value; }
|
42 |
+
operator const ConstRefCasted*() { value = {5}; return &value; }
|
43 |
+
|
44 |
+
// custom cast_op to explicitly propagate types to the conversion operators.
|
45 |
+
template <typename T_>
|
46 |
+
using cast_op_type =
|
47 |
+
/// const
|
48 |
+
conditional_t<
|
49 |
+
std::is_same<remove_reference_t<T_>, const ConstRefCasted*>::value, const ConstRefCasted*,
|
50 |
+
conditional_t<
|
51 |
+
std::is_same<T_, const ConstRefCasted&>::value, const ConstRefCasted&,
|
52 |
+
/// non-const
|
53 |
+
conditional_t<
|
54 |
+
std::is_same<remove_reference_t<T_>, ConstRefCasted*>::value, ConstRefCasted*,
|
55 |
+
conditional_t<
|
56 |
+
std::is_same<T_, ConstRefCasted&>::value, ConstRefCasted&,
|
57 |
+
/* else */ConstRefCasted&&>>>>;
|
58 |
+
|
59 |
+
private:
|
60 |
+
ConstRefCasted value = {0};
|
61 |
+
};
|
62 |
+
PYBIND11_NAMESPACE_END(detail)
|
63 |
+
PYBIND11_NAMESPACE_END(pybind11)
|
64 |
+
|
65 |
+
TEST_SUBMODULE(builtin_casters, m) {
|
66 |
+
// test_simple_string
|
67 |
+
m.def("string_roundtrip", [](const char *s) { return s; });
|
68 |
+
|
69 |
+
// test_unicode_conversion
|
70 |
+
// Some test characters in utf16 and utf32 encodings. The last one (the 𝐀) contains a null byte
|
71 |
+
char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/, mathbfA32 = 0x1d400 /*𝐀*/;
|
72 |
+
char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82, mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00;
|
73 |
+
std::wstring wstr;
|
74 |
+
wstr.push_back(0x61); // a
|
75 |
+
wstr.push_back(0x2e18); // ⸘
|
76 |
+
if (sizeof(wchar_t) == 2) { wstr.push_back(mathbfA16_1); wstr.push_back(mathbfA16_2); } // 𝐀, utf16
|
77 |
+
else { wstr.push_back((wchar_t) mathbfA32); } // 𝐀, utf32
|
78 |
+
wstr.push_back(0x7a); // z
|
79 |
+
|
80 |
+
m.def("good_utf8_string", []() { return std::string((const char*)u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀
|
81 |
+
m.def("good_utf16_string", [=]() { return std::u16string({ b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16 }); }); // b‽🎂𝐀z
|
82 |
+
m.def("good_utf32_string", [=]() { return std::u32string({ a32, mathbfA32, cake32, ib32, z32 }); }); // a𝐀🎂‽z
|
83 |
+
m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z
|
84 |
+
m.def("bad_utf8_string", []() { return std::string("abc\xd0" "def"); });
|
85 |
+
m.def("bad_utf16_string", [=]() { return std::u16string({ b16, char16_t(0xd800), z16 }); });
|
86 |
+
// Under Python 2.7, invalid unicode UTF-32 characters don't appear to trigger UnicodeDecodeError
|
87 |
+
if (PY_MAJOR_VERSION >= 3)
|
88 |
+
m.def("bad_utf32_string", [=]() { return std::u32string({ a32, char32_t(0xd800), z32 }); });
|
89 |
+
if (PY_MAJOR_VERSION >= 3 || sizeof(wchar_t) == 2)
|
90 |
+
m.def("bad_wchar_string", [=]() { return std::wstring({ wchar_t(0x61), wchar_t(0xd800) }); });
|
91 |
+
m.def("u8_Z", []() -> char { return 'Z'; });
|
92 |
+
m.def("u8_eacute", []() -> char { return '\xe9'; });
|
93 |
+
m.def("u16_ibang", [=]() -> char16_t { return ib16; });
|
94 |
+
m.def("u32_mathbfA", [=]() -> char32_t { return mathbfA32; });
|
95 |
+
m.def("wchar_heart", []() -> wchar_t { return 0x2665; });
|
96 |
+
|
97 |
+
// test_single_char_arguments
|
98 |
+
m.attr("wchar_size") = py::cast(sizeof(wchar_t));
|
99 |
+
m.def("ord_char", [](char c) -> int { return static_cast<unsigned char>(c); });
|
100 |
+
m.def("ord_char_lv", [](char &c) -> int { return static_cast<unsigned char>(c); });
|
101 |
+
m.def("ord_char16", [](char16_t c) -> uint16_t { return c; });
|
102 |
+
m.def("ord_char16_lv", [](char16_t &c) -> uint16_t { return c; });
|
103 |
+
m.def("ord_char32", [](char32_t c) -> uint32_t { return c; });
|
104 |
+
m.def("ord_wchar", [](wchar_t c) -> int { return c; });
|
105 |
+
|
106 |
+
// test_bytes_to_string
|
107 |
+
m.def("strlen", [](char *s) { return strlen(s); });
|
108 |
+
m.def("string_length", [](const std::string &s) { return s.length(); });
|
109 |
+
|
110 |
+
#ifdef PYBIND11_HAS_U8STRING
|
111 |
+
m.attr("has_u8string") = true;
|
112 |
+
m.def("good_utf8_u8string", []() { return std::u8string(u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀
|
113 |
+
m.def("bad_utf8_u8string", []() { return std::u8string((const char8_t*)"abc\xd0" "def"); });
|
114 |
+
|
115 |
+
m.def("u8_char8_Z", []() -> char8_t { return u8'Z'; });
|
116 |
+
|
117 |
+
// test_single_char_arguments
|
118 |
+
m.def("ord_char8", [](char8_t c) -> int { return static_cast<unsigned char>(c); });
|
119 |
+
m.def("ord_char8_lv", [](char8_t &c) -> int { return static_cast<unsigned char>(c); });
|
120 |
+
#endif
|
121 |
+
|
122 |
+
// test_string_view
|
123 |
+
#ifdef PYBIND11_HAS_STRING_VIEW
|
124 |
+
m.attr("has_string_view") = true;
|
125 |
+
m.def("string_view_print", [](std::string_view s) { py::print(s, s.size()); });
|
126 |
+
m.def("string_view16_print", [](std::u16string_view s) { py::print(s, s.size()); });
|
127 |
+
m.def("string_view32_print", [](std::u32string_view s) { py::print(s, s.size()); });
|
128 |
+
m.def("string_view_chars", [](std::string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; });
|
129 |
+
m.def("string_view16_chars", [](std::u16string_view s) { py::list l; for (auto c : s) l.append((int) c); return l; });
|
130 |
+
m.def("string_view32_chars", [](std::u32string_view s) { py::list l; for (auto c : s) l.append((int) c); return l; });
|
131 |
+
m.def("string_view_return", []() { return std::string_view((const char*)u8"utf8 secret \U0001f382"); });
|
132 |
+
m.def("string_view16_return", []() { return std::u16string_view(u"utf16 secret \U0001f382"); });
|
133 |
+
m.def("string_view32_return", []() { return std::u32string_view(U"utf32 secret \U0001f382"); });
|
134 |
+
|
135 |
+
# ifdef PYBIND11_HAS_U8STRING
|
136 |
+
m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); });
|
137 |
+
m.def("string_view8_chars", [](std::u8string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; });
|
138 |
+
m.def("string_view8_return", []() { return std::u8string_view(u8"utf8 secret \U0001f382"); });
|
139 |
+
# endif
|
140 |
+
#endif
|
141 |
+
|
142 |
+
// test_integer_casting
|
143 |
+
m.def("i32_str", [](std::int32_t v) { return std::to_string(v); });
|
144 |
+
m.def("u32_str", [](std::uint32_t v) { return std::to_string(v); });
|
145 |
+
m.def("i64_str", [](std::int64_t v) { return std::to_string(v); });
|
146 |
+
m.def("u64_str", [](std::uint64_t v) { return std::to_string(v); });
|
147 |
+
|
148 |
+
// test_int_convert
|
149 |
+
m.def("int_passthrough", [](int arg) { return arg; });
|
150 |
+
m.def("int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert());
|
151 |
+
|
152 |
+
// test_tuple
|
153 |
+
m.def(
|
154 |
+
"pair_passthrough",
|
155 |
+
[](const std::pair<bool, std::string> &input) {
|
156 |
+
return std::make_pair(input.second, input.first);
|
157 |
+
},
|
158 |
+
"Return a pair in reversed order");
|
159 |
+
m.def("tuple_passthrough", [](std::tuple<bool, std::string, int> input) {
|
160 |
+
return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input));
|
161 |
+
}, "Return a triple in reversed order");
|
162 |
+
m.def("empty_tuple", []() { return std::tuple<>(); });
|
163 |
+
static std::pair<RValueCaster, RValueCaster> lvpair;
|
164 |
+
static std::tuple<RValueCaster, RValueCaster, RValueCaster> lvtuple;
|
165 |
+
static std::pair<RValueCaster, std::tuple<RValueCaster, std::pair<RValueCaster, RValueCaster>>> lvnested;
|
166 |
+
m.def("rvalue_pair", []() { return std::make_pair(RValueCaster{}, RValueCaster{}); });
|
167 |
+
m.def("lvalue_pair", []() -> const decltype(lvpair) & { return lvpair; });
|
168 |
+
m.def("rvalue_tuple", []() { return std::make_tuple(RValueCaster{}, RValueCaster{}, RValueCaster{}); });
|
169 |
+
m.def("lvalue_tuple", []() -> const decltype(lvtuple) & { return lvtuple; });
|
170 |
+
m.def("rvalue_nested", []() {
|
171 |
+
return std::make_pair(RValueCaster{}, std::make_tuple(RValueCaster{}, std::make_pair(RValueCaster{}, RValueCaster{}))); });
|
172 |
+
m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; });
|
173 |
+
|
174 |
+
static std::pair<int, std::string> int_string_pair{2, "items"};
|
175 |
+
m.def("int_string_pair", []() { return &int_string_pair; });
|
176 |
+
|
177 |
+
// test_builtins_cast_return_none
|
178 |
+
m.def("return_none_string", []() -> std::string * { return nullptr; });
|
179 |
+
m.def("return_none_char", []() -> const char * { return nullptr; });
|
180 |
+
m.def("return_none_bool", []() -> bool * { return nullptr; });
|
181 |
+
m.def("return_none_int", []() -> int * { return nullptr; });
|
182 |
+
m.def("return_none_float", []() -> float * { return nullptr; });
|
183 |
+
m.def("return_none_pair", []() -> std::pair<int,int> * { return nullptr; });
|
184 |
+
|
185 |
+
// test_none_deferred
|
186 |
+
m.def("defer_none_cstring", [](char *) { return false; });
|
187 |
+
m.def("defer_none_cstring", [](const py::none &) { return true; });
|
188 |
+
m.def("defer_none_custom", [](UserType *) { return false; });
|
189 |
+
m.def("defer_none_custom", [](const py::none &) { return true; });
|
190 |
+
m.def("nodefer_none_void", [](void *) { return true; });
|
191 |
+
m.def("nodefer_none_void", [](const py::none &) { return false; });
|
192 |
+
|
193 |
+
// test_void_caster
|
194 |
+
m.def("load_nullptr_t", [](std::nullptr_t) {}); // not useful, but it should still compile
|
195 |
+
m.def("cast_nullptr_t", []() { return std::nullptr_t{}; });
|
196 |
+
|
197 |
+
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
|
198 |
+
|
199 |
+
// test_bool_caster
|
200 |
+
m.def("bool_passthrough", [](bool arg) { return arg; });
|
201 |
+
m.def("bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert());
|
202 |
+
|
203 |
+
// TODO: This should be disabled and fixed in future Intel compilers
|
204 |
+
#if !defined(__INTEL_COMPILER)
|
205 |
+
// Test "bool_passthrough_noconvert" again, but using () instead of {} to construct py::arg
|
206 |
+
// When compiled with the Intel compiler, this results in segmentation faults when importing
|
207 |
+
// the module. Tested with icc (ICC) 2021.1 Beta 20200827, this should be tested again when
|
208 |
+
// a newer version of icc is available.
|
209 |
+
m.def("bool_passthrough_noconvert2", [](bool arg) { return arg; }, py::arg().noconvert());
|
210 |
+
#endif
|
211 |
+
|
212 |
+
// test_reference_wrapper
|
213 |
+
m.def("refwrap_builtin", [](std::reference_wrapper<int> p) { return 10 * p.get(); });
|
214 |
+
m.def("refwrap_usertype", [](std::reference_wrapper<UserType> p) { return p.get().value(); });
|
215 |
+
m.def("refwrap_usertype_const", [](std::reference_wrapper<const UserType> p) { return p.get().value(); });
|
216 |
+
|
217 |
+
m.def("refwrap_lvalue", []() -> std::reference_wrapper<UserType> {
|
218 |
+
static UserType x(1);
|
219 |
+
return std::ref(x);
|
220 |
+
});
|
221 |
+
m.def("refwrap_lvalue_const", []() -> std::reference_wrapper<const UserType> {
|
222 |
+
static UserType x(1);
|
223 |
+
return std::cref(x);
|
224 |
+
});
|
225 |
+
|
226 |
+
// Not currently supported (std::pair caster has return-by-value cast operator);
|
227 |
+
// triggers static_assert failure.
|
228 |
+
//m.def("refwrap_pair", [](std::reference_wrapper<std::pair<int, int>>) { });
|
229 |
+
|
230 |
+
m.def("refwrap_list", [](bool copy) {
|
231 |
+
static IncType x1(1), x2(2);
|
232 |
+
py::list l;
|
233 |
+
for (auto &f : {std::ref(x1), std::ref(x2)}) {
|
234 |
+
l.append(py::cast(f, copy ? py::return_value_policy::copy
|
235 |
+
: py::return_value_policy::reference));
|
236 |
+
}
|
237 |
+
return l;
|
238 |
+
}, "copy"_a);
|
239 |
+
|
240 |
+
m.def("refwrap_iiw", [](const IncType &w) { return w.value(); });
|
241 |
+
m.def("refwrap_call_iiw", [](IncType &w, const py::function &f) {
|
242 |
+
py::list l;
|
243 |
+
l.append(f(std::ref(w)));
|
244 |
+
l.append(f(std::cref(w)));
|
245 |
+
IncType x(w.value());
|
246 |
+
l.append(f(std::ref(x)));
|
247 |
+
IncType y(w.value());
|
248 |
+
auto r3 = std::ref(y);
|
249 |
+
l.append(f(r3));
|
250 |
+
return l;
|
251 |
+
});
|
252 |
+
|
253 |
+
// test_complex
|
254 |
+
m.def("complex_cast", [](float x) { return "{}"_s.format(x); });
|
255 |
+
m.def("complex_cast", [](std::complex<float> x) { return "({}, {})"_s.format(x.real(), x.imag()); });
|
256 |
+
|
257 |
+
// test int vs. long (Python 2)
|
258 |
+
m.def("int_cast", []() {return (int) 42;});
|
259 |
+
m.def("long_cast", []() {return (long) 42;});
|
260 |
+
m.def("longlong_cast", []() {return ULLONG_MAX;});
|
261 |
+
|
262 |
+
/// test void* cast operator
|
263 |
+
m.def("test_void_caster", []() -> bool {
|
264 |
+
void *v = (void *) 0xabcd;
|
265 |
+
py::object o = py::cast(v);
|
266 |
+
return py::cast<void *>(o) == v;
|
267 |
+
});
|
268 |
+
|
269 |
+
// Tests const/non-const propagation in cast_op.
|
270 |
+
m.def("takes", [](ConstRefCasted x) { return x.tag; });
|
271 |
+
m.def("takes_move", [](ConstRefCasted&& x) { return x.tag; });
|
272 |
+
m.def("takes_ptr", [](ConstRefCasted* x) { return x->tag; });
|
273 |
+
m.def("takes_ref", [](ConstRefCasted& x) { return x.tag; });
|
274 |
+
m.def("takes_ref_wrap", [](std::reference_wrapper<ConstRefCasted> x) { return x.get().tag; });
|
275 |
+
m.def("takes_const_ptr", [](const ConstRefCasted* x) { return x->tag; });
|
276 |
+
m.def("takes_const_ref", [](const ConstRefCasted& x) { return x.tag; });
|
277 |
+
m.def("takes_const_ref_wrap", [](std::reference_wrapper<const ConstRefCasted> x) { return x.get().tag; });
|
278 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_builtin_casters.py
ADDED
@@ -0,0 +1,537 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
import env # noqa: F401
|
5 |
+
|
6 |
+
from pybind11_tests import builtin_casters as m
|
7 |
+
from pybind11_tests import UserType, IncType
|
8 |
+
|
9 |
+
|
10 |
+
def test_simple_string():
|
11 |
+
assert m.string_roundtrip("const char *") == "const char *"
|
12 |
+
|
13 |
+
|
14 |
+
def test_unicode_conversion():
|
15 |
+
"""Tests unicode conversion and error reporting."""
|
16 |
+
assert m.good_utf8_string() == u"Say utf8‽ 🎂 𝐀"
|
17 |
+
assert m.good_utf16_string() == u"b‽🎂𝐀z"
|
18 |
+
assert m.good_utf32_string() == u"a𝐀🎂‽z"
|
19 |
+
assert m.good_wchar_string() == u"a⸘𝐀z"
|
20 |
+
if hasattr(m, "has_u8string"):
|
21 |
+
assert m.good_utf8_u8string() == u"Say utf8‽ 🎂 𝐀"
|
22 |
+
|
23 |
+
with pytest.raises(UnicodeDecodeError):
|
24 |
+
m.bad_utf8_string()
|
25 |
+
|
26 |
+
with pytest.raises(UnicodeDecodeError):
|
27 |
+
m.bad_utf16_string()
|
28 |
+
|
29 |
+
# These are provided only if they actually fail (they don't when 32-bit and under Python 2.7)
|
30 |
+
if hasattr(m, "bad_utf32_string"):
|
31 |
+
with pytest.raises(UnicodeDecodeError):
|
32 |
+
m.bad_utf32_string()
|
33 |
+
if hasattr(m, "bad_wchar_string"):
|
34 |
+
with pytest.raises(UnicodeDecodeError):
|
35 |
+
m.bad_wchar_string()
|
36 |
+
if hasattr(m, "has_u8string"):
|
37 |
+
with pytest.raises(UnicodeDecodeError):
|
38 |
+
m.bad_utf8_u8string()
|
39 |
+
|
40 |
+
assert m.u8_Z() == "Z"
|
41 |
+
assert m.u8_eacute() == u"é"
|
42 |
+
assert m.u16_ibang() == u"‽"
|
43 |
+
assert m.u32_mathbfA() == u"𝐀"
|
44 |
+
assert m.wchar_heart() == u"♥"
|
45 |
+
if hasattr(m, "has_u8string"):
|
46 |
+
assert m.u8_char8_Z() == "Z"
|
47 |
+
|
48 |
+
|
49 |
+
def test_single_char_arguments():
|
50 |
+
"""Tests failures for passing invalid inputs to char-accepting functions"""
|
51 |
+
|
52 |
+
def toobig_message(r):
|
53 |
+
return "Character code point not in range({:#x})".format(r)
|
54 |
+
|
55 |
+
toolong_message = "Expected a character, but multi-character string found"
|
56 |
+
|
57 |
+
assert m.ord_char(u"a") == 0x61 # simple ASCII
|
58 |
+
assert m.ord_char_lv(u"b") == 0x62
|
59 |
+
assert (
|
60 |
+
m.ord_char(u"é") == 0xE9
|
61 |
+
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
62 |
+
with pytest.raises(ValueError) as excinfo:
|
63 |
+
assert m.ord_char(u"Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
64 |
+
assert str(excinfo.value) == toobig_message(0x100)
|
65 |
+
with pytest.raises(ValueError) as excinfo:
|
66 |
+
assert m.ord_char(u"ab")
|
67 |
+
assert str(excinfo.value) == toolong_message
|
68 |
+
|
69 |
+
assert m.ord_char16(u"a") == 0x61
|
70 |
+
assert m.ord_char16(u"é") == 0xE9
|
71 |
+
assert m.ord_char16_lv(u"ê") == 0xEA
|
72 |
+
assert m.ord_char16(u"Ā") == 0x100
|
73 |
+
assert m.ord_char16(u"‽") == 0x203D
|
74 |
+
assert m.ord_char16(u"♥") == 0x2665
|
75 |
+
assert m.ord_char16_lv(u"♡") == 0x2661
|
76 |
+
with pytest.raises(ValueError) as excinfo:
|
77 |
+
assert m.ord_char16(u"🎂") == 0x1F382 # requires surrogate pair
|
78 |
+
assert str(excinfo.value) == toobig_message(0x10000)
|
79 |
+
with pytest.raises(ValueError) as excinfo:
|
80 |
+
assert m.ord_char16(u"aa")
|
81 |
+
assert str(excinfo.value) == toolong_message
|
82 |
+
|
83 |
+
assert m.ord_char32(u"a") == 0x61
|
84 |
+
assert m.ord_char32(u"é") == 0xE9
|
85 |
+
assert m.ord_char32(u"Ā") == 0x100
|
86 |
+
assert m.ord_char32(u"‽") == 0x203D
|
87 |
+
assert m.ord_char32(u"♥") == 0x2665
|
88 |
+
assert m.ord_char32(u"🎂") == 0x1F382
|
89 |
+
with pytest.raises(ValueError) as excinfo:
|
90 |
+
assert m.ord_char32(u"aa")
|
91 |
+
assert str(excinfo.value) == toolong_message
|
92 |
+
|
93 |
+
assert m.ord_wchar(u"a") == 0x61
|
94 |
+
assert m.ord_wchar(u"é") == 0xE9
|
95 |
+
assert m.ord_wchar(u"Ā") == 0x100
|
96 |
+
assert m.ord_wchar(u"‽") == 0x203D
|
97 |
+
assert m.ord_wchar(u"♥") == 0x2665
|
98 |
+
if m.wchar_size == 2:
|
99 |
+
with pytest.raises(ValueError) as excinfo:
|
100 |
+
assert m.ord_wchar(u"🎂") == 0x1F382 # requires surrogate pair
|
101 |
+
assert str(excinfo.value) == toobig_message(0x10000)
|
102 |
+
else:
|
103 |
+
assert m.ord_wchar(u"🎂") == 0x1F382
|
104 |
+
with pytest.raises(ValueError) as excinfo:
|
105 |
+
assert m.ord_wchar(u"aa")
|
106 |
+
assert str(excinfo.value) == toolong_message
|
107 |
+
|
108 |
+
if hasattr(m, "has_u8string"):
|
109 |
+
assert m.ord_char8(u"a") == 0x61 # simple ASCII
|
110 |
+
assert m.ord_char8_lv(u"b") == 0x62
|
111 |
+
assert (
|
112 |
+
m.ord_char8(u"é") == 0xE9
|
113 |
+
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
114 |
+
with pytest.raises(ValueError) as excinfo:
|
115 |
+
assert m.ord_char8(u"Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
116 |
+
assert str(excinfo.value) == toobig_message(0x100)
|
117 |
+
with pytest.raises(ValueError) as excinfo:
|
118 |
+
assert m.ord_char8(u"ab")
|
119 |
+
assert str(excinfo.value) == toolong_message
|
120 |
+
|
121 |
+
|
122 |
+
def test_bytes_to_string():
|
123 |
+
"""Tests the ability to pass bytes to C++ string-accepting functions. Note that this is
|
124 |
+
one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
|
125 |
+
# Issue #816
|
126 |
+
|
127 |
+
def to_bytes(s):
|
128 |
+
b = s if env.PY2 else s.encode("utf8")
|
129 |
+
assert isinstance(b, bytes)
|
130 |
+
return b
|
131 |
+
|
132 |
+
assert m.strlen(to_bytes("hi")) == 2
|
133 |
+
assert m.string_length(to_bytes("world")) == 5
|
134 |
+
assert m.string_length(to_bytes("a\x00b")) == 3
|
135 |
+
assert m.strlen(to_bytes("a\x00b")) == 1 # C-string limitation
|
136 |
+
|
137 |
+
# passing in a utf8 encoded string should work
|
138 |
+
assert m.string_length(u"💩".encode("utf8")) == 4
|
139 |
+
|
140 |
+
|
141 |
+
@pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")
|
142 |
+
def test_string_view(capture):
|
143 |
+
"""Tests support for C++17 string_view arguments and return values"""
|
144 |
+
assert m.string_view_chars("Hi") == [72, 105]
|
145 |
+
assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
146 |
+
assert m.string_view16_chars(u"Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82]
|
147 |
+
assert m.string_view32_chars(u"Hi 🎂") == [72, 105, 32, 127874]
|
148 |
+
if hasattr(m, "has_u8string"):
|
149 |
+
assert m.string_view8_chars("Hi") == [72, 105]
|
150 |
+
assert m.string_view8_chars(u"Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
151 |
+
|
152 |
+
assert m.string_view_return() == u"utf8 secret 🎂"
|
153 |
+
assert m.string_view16_return() == u"utf16 secret 🎂"
|
154 |
+
assert m.string_view32_return() == u"utf32 secret 🎂"
|
155 |
+
if hasattr(m, "has_u8string"):
|
156 |
+
assert m.string_view8_return() == u"utf8 secret 🎂"
|
157 |
+
|
158 |
+
with capture:
|
159 |
+
m.string_view_print("Hi")
|
160 |
+
m.string_view_print("utf8 🎂")
|
161 |
+
m.string_view16_print(u"utf16 🎂")
|
162 |
+
m.string_view32_print(u"utf32 🎂")
|
163 |
+
assert (
|
164 |
+
capture
|
165 |
+
== u"""
|
166 |
+
Hi 2
|
167 |
+
utf8 🎂 9
|
168 |
+
utf16 🎂 8
|
169 |
+
utf32 🎂 7
|
170 |
+
"""
|
171 |
+
)
|
172 |
+
if hasattr(m, "has_u8string"):
|
173 |
+
with capture:
|
174 |
+
m.string_view8_print("Hi")
|
175 |
+
m.string_view8_print(u"utf8 🎂")
|
176 |
+
assert (
|
177 |
+
capture
|
178 |
+
== u"""
|
179 |
+
Hi 2
|
180 |
+
utf8 🎂 9
|
181 |
+
"""
|
182 |
+
)
|
183 |
+
|
184 |
+
with capture:
|
185 |
+
m.string_view_print("Hi, ascii")
|
186 |
+
m.string_view_print("Hi, utf8 🎂")
|
187 |
+
m.string_view16_print(u"Hi, utf16 🎂")
|
188 |
+
m.string_view32_print(u"Hi, utf32 🎂")
|
189 |
+
assert (
|
190 |
+
capture
|
191 |
+
== u"""
|
192 |
+
Hi, ascii 9
|
193 |
+
Hi, utf8 🎂 13
|
194 |
+
Hi, utf16 🎂 12
|
195 |
+
Hi, utf32 🎂 11
|
196 |
+
"""
|
197 |
+
)
|
198 |
+
if hasattr(m, "has_u8string"):
|
199 |
+
with capture:
|
200 |
+
m.string_view8_print("Hi, ascii")
|
201 |
+
m.string_view8_print(u"Hi, utf8 🎂")
|
202 |
+
assert (
|
203 |
+
capture
|
204 |
+
== u"""
|
205 |
+
Hi, ascii 9
|
206 |
+
Hi, utf8 🎂 13
|
207 |
+
"""
|
208 |
+
)
|
209 |
+
|
210 |
+
|
211 |
+
def test_integer_casting():
|
212 |
+
"""Issue #929 - out-of-range integer values shouldn't be accepted"""
|
213 |
+
assert m.i32_str(-1) == "-1"
|
214 |
+
assert m.i64_str(-1) == "-1"
|
215 |
+
assert m.i32_str(2000000000) == "2000000000"
|
216 |
+
assert m.u32_str(2000000000) == "2000000000"
|
217 |
+
if env.PY2:
|
218 |
+
assert m.i32_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
|
219 |
+
assert m.i64_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
|
220 |
+
assert (
|
221 |
+
m.i64_str(long(-999999999999)) # noqa: F821 undefined name 'long'
|
222 |
+
== "-999999999999"
|
223 |
+
)
|
224 |
+
assert (
|
225 |
+
m.u64_str(long(999999999999)) # noqa: F821 undefined name 'long'
|
226 |
+
== "999999999999"
|
227 |
+
)
|
228 |
+
else:
|
229 |
+
assert m.i64_str(-999999999999) == "-999999999999"
|
230 |
+
assert m.u64_str(999999999999) == "999999999999"
|
231 |
+
|
232 |
+
with pytest.raises(TypeError) as excinfo:
|
233 |
+
m.u32_str(-1)
|
234 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
235 |
+
with pytest.raises(TypeError) as excinfo:
|
236 |
+
m.u64_str(-1)
|
237 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
238 |
+
with pytest.raises(TypeError) as excinfo:
|
239 |
+
m.i32_str(-3000000000)
|
240 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
241 |
+
with pytest.raises(TypeError) as excinfo:
|
242 |
+
m.i32_str(3000000000)
|
243 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
244 |
+
|
245 |
+
if env.PY2:
|
246 |
+
with pytest.raises(TypeError) as excinfo:
|
247 |
+
m.u32_str(long(-1)) # noqa: F821 undefined name 'long'
|
248 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
249 |
+
with pytest.raises(TypeError) as excinfo:
|
250 |
+
m.u64_str(long(-1)) # noqa: F821 undefined name 'long'
|
251 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
252 |
+
|
253 |
+
|
254 |
+
def test_int_convert():
|
255 |
+
class Int(object):
|
256 |
+
def __int__(self):
|
257 |
+
return 42
|
258 |
+
|
259 |
+
class NotInt(object):
|
260 |
+
pass
|
261 |
+
|
262 |
+
class Float(object):
|
263 |
+
def __float__(self):
|
264 |
+
return 41.99999
|
265 |
+
|
266 |
+
class Index(object):
|
267 |
+
def __index__(self):
|
268 |
+
return 42
|
269 |
+
|
270 |
+
class IntAndIndex(object):
|
271 |
+
def __int__(self):
|
272 |
+
return 42
|
273 |
+
|
274 |
+
def __index__(self):
|
275 |
+
return 0
|
276 |
+
|
277 |
+
class RaisingTypeErrorOnIndex(object):
|
278 |
+
def __index__(self):
|
279 |
+
raise TypeError
|
280 |
+
|
281 |
+
def __int__(self):
|
282 |
+
return 42
|
283 |
+
|
284 |
+
class RaisingValueErrorOnIndex(object):
|
285 |
+
def __index__(self):
|
286 |
+
raise ValueError
|
287 |
+
|
288 |
+
def __int__(self):
|
289 |
+
return 42
|
290 |
+
|
291 |
+
convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
|
292 |
+
|
293 |
+
def requires_conversion(v):
|
294 |
+
pytest.raises(TypeError, noconvert, v)
|
295 |
+
|
296 |
+
def cant_convert(v):
|
297 |
+
pytest.raises(TypeError, convert, v)
|
298 |
+
|
299 |
+
assert convert(7) == 7
|
300 |
+
assert noconvert(7) == 7
|
301 |
+
cant_convert(3.14159)
|
302 |
+
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
303 |
+
if (3, 8) <= env.PY < (3, 10):
|
304 |
+
with env.deprecated_call():
|
305 |
+
assert convert(Int()) == 42
|
306 |
+
else:
|
307 |
+
assert convert(Int()) == 42
|
308 |
+
requires_conversion(Int())
|
309 |
+
cant_convert(NotInt())
|
310 |
+
cant_convert(Float())
|
311 |
+
|
312 |
+
# Before Python 3.8, `PyLong_AsLong` does not pick up on `obj.__index__`,
|
313 |
+
# but pybind11 "backports" this behavior.
|
314 |
+
assert convert(Index()) == 42
|
315 |
+
assert noconvert(Index()) == 42
|
316 |
+
assert convert(IntAndIndex()) == 0 # Fishy; `int(DoubleThought)` == 42
|
317 |
+
assert noconvert(IntAndIndex()) == 0
|
318 |
+
assert convert(RaisingTypeErrorOnIndex()) == 42
|
319 |
+
requires_conversion(RaisingTypeErrorOnIndex())
|
320 |
+
assert convert(RaisingValueErrorOnIndex()) == 42
|
321 |
+
requires_conversion(RaisingValueErrorOnIndex())
|
322 |
+
|
323 |
+
|
324 |
+
def test_numpy_int_convert():
|
325 |
+
np = pytest.importorskip("numpy")
|
326 |
+
|
327 |
+
convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
|
328 |
+
|
329 |
+
def require_implicit(v):
|
330 |
+
pytest.raises(TypeError, noconvert, v)
|
331 |
+
|
332 |
+
# `np.intc` is an alias that corresponds to a C++ `int`
|
333 |
+
assert convert(np.intc(42)) == 42
|
334 |
+
assert noconvert(np.intc(42)) == 42
|
335 |
+
|
336 |
+
# The implicit conversion from np.float32 is undesirable but currently accepted.
|
337 |
+
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
338 |
+
if (3, 8) <= env.PY < (3, 10):
|
339 |
+
with env.deprecated_call():
|
340 |
+
assert convert(np.float32(3.14159)) == 3
|
341 |
+
else:
|
342 |
+
assert convert(np.float32(3.14159)) == 3
|
343 |
+
require_implicit(np.float32(3.14159))
|
344 |
+
|
345 |
+
|
346 |
+
def test_tuple(doc):
|
347 |
+
"""std::pair <-> tuple & std::tuple <-> tuple"""
|
348 |
+
assert m.pair_passthrough((True, "test")) == ("test", True)
|
349 |
+
assert m.tuple_passthrough((True, "test", 5)) == (5, "test", True)
|
350 |
+
# Any sequence can be cast to a std::pair or std::tuple
|
351 |
+
assert m.pair_passthrough([True, "test"]) == ("test", True)
|
352 |
+
assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True)
|
353 |
+
assert m.empty_tuple() == ()
|
354 |
+
|
355 |
+
assert (
|
356 |
+
doc(m.pair_passthrough)
|
357 |
+
== """
|
358 |
+
pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool]
|
359 |
+
|
360 |
+
Return a pair in reversed order
|
361 |
+
"""
|
362 |
+
)
|
363 |
+
assert (
|
364 |
+
doc(m.tuple_passthrough)
|
365 |
+
== """
|
366 |
+
tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool]
|
367 |
+
|
368 |
+
Return a triple in reversed order
|
369 |
+
"""
|
370 |
+
)
|
371 |
+
|
372 |
+
assert m.rvalue_pair() == ("rvalue", "rvalue")
|
373 |
+
assert m.lvalue_pair() == ("lvalue", "lvalue")
|
374 |
+
assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")
|
375 |
+
assert m.lvalue_tuple() == ("lvalue", "lvalue", "lvalue")
|
376 |
+
assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue")))
|
377 |
+
assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue")))
|
378 |
+
|
379 |
+
assert m.int_string_pair() == (2, "items")
|
380 |
+
|
381 |
+
|
382 |
+
def test_builtins_cast_return_none():
|
383 |
+
"""Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None"""
|
384 |
+
assert m.return_none_string() is None
|
385 |
+
assert m.return_none_char() is None
|
386 |
+
assert m.return_none_bool() is None
|
387 |
+
assert m.return_none_int() is None
|
388 |
+
assert m.return_none_float() is None
|
389 |
+
assert m.return_none_pair() is None
|
390 |
+
|
391 |
+
|
392 |
+
def test_none_deferred():
|
393 |
+
"""None passed as various argument types should defer to other overloads"""
|
394 |
+
assert not m.defer_none_cstring("abc")
|
395 |
+
assert m.defer_none_cstring(None)
|
396 |
+
assert not m.defer_none_custom(UserType())
|
397 |
+
assert m.defer_none_custom(None)
|
398 |
+
assert m.nodefer_none_void(None)
|
399 |
+
|
400 |
+
|
401 |
+
def test_void_caster():
|
402 |
+
assert m.load_nullptr_t(None) is None
|
403 |
+
assert m.cast_nullptr_t() is None
|
404 |
+
|
405 |
+
|
406 |
+
def test_reference_wrapper():
|
407 |
+
"""std::reference_wrapper for builtin and user types"""
|
408 |
+
assert m.refwrap_builtin(42) == 420
|
409 |
+
assert m.refwrap_usertype(UserType(42)) == 42
|
410 |
+
assert m.refwrap_usertype_const(UserType(42)) == 42
|
411 |
+
|
412 |
+
with pytest.raises(TypeError) as excinfo:
|
413 |
+
m.refwrap_builtin(None)
|
414 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
415 |
+
|
416 |
+
with pytest.raises(TypeError) as excinfo:
|
417 |
+
m.refwrap_usertype(None)
|
418 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
419 |
+
|
420 |
+
assert m.refwrap_lvalue().value == 1
|
421 |
+
assert m.refwrap_lvalue_const().value == 1
|
422 |
+
|
423 |
+
a1 = m.refwrap_list(copy=True)
|
424 |
+
a2 = m.refwrap_list(copy=True)
|
425 |
+
assert [x.value for x in a1] == [2, 3]
|
426 |
+
assert [x.value for x in a2] == [2, 3]
|
427 |
+
assert not a1[0] is a2[0] and not a1[1] is a2[1]
|
428 |
+
|
429 |
+
b1 = m.refwrap_list(copy=False)
|
430 |
+
b2 = m.refwrap_list(copy=False)
|
431 |
+
assert [x.value for x in b1] == [1, 2]
|
432 |
+
assert [x.value for x in b2] == [1, 2]
|
433 |
+
assert b1[0] is b2[0] and b1[1] is b2[1]
|
434 |
+
|
435 |
+
assert m.refwrap_iiw(IncType(5)) == 5
|
436 |
+
assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10]
|
437 |
+
|
438 |
+
|
439 |
+
def test_complex_cast():
|
440 |
+
"""std::complex casts"""
|
441 |
+
assert m.complex_cast(1) == "1.0"
|
442 |
+
assert m.complex_cast(2j) == "(0.0, 2.0)"
|
443 |
+
|
444 |
+
|
445 |
+
def test_bool_caster():
|
446 |
+
"""Test bool caster implicit conversions."""
|
447 |
+
convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
|
448 |
+
|
449 |
+
def require_implicit(v):
|
450 |
+
pytest.raises(TypeError, noconvert, v)
|
451 |
+
|
452 |
+
def cant_convert(v):
|
453 |
+
pytest.raises(TypeError, convert, v)
|
454 |
+
|
455 |
+
# straight up bool
|
456 |
+
assert convert(True) is True
|
457 |
+
assert convert(False) is False
|
458 |
+
assert noconvert(True) is True
|
459 |
+
assert noconvert(False) is False
|
460 |
+
|
461 |
+
# None requires implicit conversion
|
462 |
+
require_implicit(None)
|
463 |
+
assert convert(None) is False
|
464 |
+
|
465 |
+
class A(object):
|
466 |
+
def __init__(self, x):
|
467 |
+
self.x = x
|
468 |
+
|
469 |
+
def __nonzero__(self):
|
470 |
+
return self.x
|
471 |
+
|
472 |
+
def __bool__(self):
|
473 |
+
return self.x
|
474 |
+
|
475 |
+
class B(object):
|
476 |
+
pass
|
477 |
+
|
478 |
+
# Arbitrary objects are not accepted
|
479 |
+
cant_convert(object())
|
480 |
+
cant_convert(B())
|
481 |
+
|
482 |
+
# Objects with __nonzero__ / __bool__ defined can be converted
|
483 |
+
require_implicit(A(True))
|
484 |
+
assert convert(A(True)) is True
|
485 |
+
assert convert(A(False)) is False
|
486 |
+
|
487 |
+
|
488 |
+
def test_numpy_bool():
|
489 |
+
np = pytest.importorskip("numpy")
|
490 |
+
|
491 |
+
convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
|
492 |
+
|
493 |
+
def cant_convert(v):
|
494 |
+
pytest.raises(TypeError, convert, v)
|
495 |
+
|
496 |
+
# np.bool_ is not considered implicit
|
497 |
+
assert convert(np.bool_(True)) is True
|
498 |
+
assert convert(np.bool_(False)) is False
|
499 |
+
assert noconvert(np.bool_(True)) is True
|
500 |
+
assert noconvert(np.bool_(False)) is False
|
501 |
+
cant_convert(np.zeros(2, dtype="int"))
|
502 |
+
|
503 |
+
|
504 |
+
def test_int_long():
|
505 |
+
"""In Python 2, a C++ int should return a Python int rather than long
|
506 |
+
if possible: longs are not always accepted where ints are used (such
|
507 |
+
as the argument to sys.exit()). A C++ long long is always a Python
|
508 |
+
long."""
|
509 |
+
|
510 |
+
import sys
|
511 |
+
|
512 |
+
must_be_long = type(getattr(sys, "maxint", 1) + 1)
|
513 |
+
assert isinstance(m.int_cast(), int)
|
514 |
+
assert isinstance(m.long_cast(), int)
|
515 |
+
assert isinstance(m.longlong_cast(), must_be_long)
|
516 |
+
|
517 |
+
|
518 |
+
def test_void_caster_2():
|
519 |
+
assert m.test_void_caster()
|
520 |
+
|
521 |
+
|
522 |
+
def test_const_ref_caster():
|
523 |
+
"""Verifies that const-ref is propagated through type_caster cast_op.
|
524 |
+
The returned ConstRefCasted type is a minimal type that is constructed to
|
525 |
+
reference the casting mode used.
|
526 |
+
"""
|
527 |
+
x = False
|
528 |
+
assert m.takes(x) == 1
|
529 |
+
assert m.takes_move(x) == 1
|
530 |
+
|
531 |
+
assert m.takes_ptr(x) == 3
|
532 |
+
assert m.takes_ref(x) == 2
|
533 |
+
assert m.takes_ref_wrap(x) == 2
|
534 |
+
|
535 |
+
assert m.takes_const_ptr(x) == 5
|
536 |
+
assert m.takes_const_ref(x) == 4
|
537 |
+
assert m.takes_const_ref_wrap(x) == 4
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_call_policies.cpp
ADDED
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_call_policies.cpp -- keep_alive and call_guard
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "pybind11_tests.h"
|
11 |
+
|
12 |
+
struct CustomGuard {
|
13 |
+
static bool enabled;
|
14 |
+
|
15 |
+
CustomGuard() { enabled = true; }
|
16 |
+
~CustomGuard() { enabled = false; }
|
17 |
+
|
18 |
+
static const char *report_status() { return enabled ? "guarded" : "unguarded"; }
|
19 |
+
};
|
20 |
+
bool CustomGuard::enabled = false;
|
21 |
+
|
22 |
+
struct DependentGuard {
|
23 |
+
static bool enabled;
|
24 |
+
|
25 |
+
DependentGuard() { enabled = CustomGuard::enabled; }
|
26 |
+
~DependentGuard() { enabled = false; }
|
27 |
+
|
28 |
+
static const char *report_status() { return enabled ? "guarded" : "unguarded"; }
|
29 |
+
};
|
30 |
+
bool DependentGuard::enabled = false;
|
31 |
+
|
32 |
+
TEST_SUBMODULE(call_policies, m) {
|
33 |
+
// Parent/Child are used in:
|
34 |
+
// test_keep_alive_argument, test_keep_alive_return_value, test_alive_gc_derived,
|
35 |
+
// test_alive_gc_multi_derived, test_return_none, test_keep_alive_constructor
|
36 |
+
class Child {
|
37 |
+
public:
|
38 |
+
Child() { py::print("Allocating child."); }
|
39 |
+
Child(const Child &) = default;
|
40 |
+
Child(Child &&) = default;
|
41 |
+
~Child() { py::print("Releasing child."); }
|
42 |
+
};
|
43 |
+
py::class_<Child>(m, "Child")
|
44 |
+
.def(py::init<>());
|
45 |
+
|
46 |
+
class Parent {
|
47 |
+
public:
|
48 |
+
Parent() { py::print("Allocating parent."); }
|
49 |
+
Parent(const Parent& parent) = default;
|
50 |
+
~Parent() { py::print("Releasing parent."); }
|
51 |
+
void addChild(Child *) { }
|
52 |
+
Child *returnChild() { return new Child(); }
|
53 |
+
Child *returnNullChild() { return nullptr; }
|
54 |
+
static Child *staticFunction(Parent*) { return new Child(); }
|
55 |
+
};
|
56 |
+
py::class_<Parent>(m, "Parent")
|
57 |
+
.def(py::init<>())
|
58 |
+
.def(py::init([](Child *) { return new Parent(); }), py::keep_alive<1, 2>())
|
59 |
+
.def("addChild", &Parent::addChild)
|
60 |
+
.def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>())
|
61 |
+
.def("returnChild", &Parent::returnChild)
|
62 |
+
.def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>())
|
63 |
+
.def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>())
|
64 |
+
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>())
|
65 |
+
.def_static(
|
66 |
+
"staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>());
|
67 |
+
|
68 |
+
m.def("free_function", [](Parent*, Child*) {}, py::keep_alive<1, 2>());
|
69 |
+
m.def("invalid_arg_index", []{}, py::keep_alive<0, 1>());
|
70 |
+
|
71 |
+
#if !defined(PYPY_VERSION)
|
72 |
+
// test_alive_gc
|
73 |
+
class ParentGC : public Parent {
|
74 |
+
public:
|
75 |
+
using Parent::Parent;
|
76 |
+
};
|
77 |
+
py::class_<ParentGC, Parent>(m, "ParentGC", py::dynamic_attr())
|
78 |
+
.def(py::init<>());
|
79 |
+
#endif
|
80 |
+
|
81 |
+
// test_call_guard
|
82 |
+
m.def("unguarded_call", &CustomGuard::report_status);
|
83 |
+
m.def("guarded_call", &CustomGuard::report_status, py::call_guard<CustomGuard>());
|
84 |
+
|
85 |
+
m.def("multiple_guards_correct_order", []() {
|
86 |
+
return CustomGuard::report_status() + std::string(" & ") + DependentGuard::report_status();
|
87 |
+
}, py::call_guard<CustomGuard, DependentGuard>());
|
88 |
+
|
89 |
+
m.def("multiple_guards_wrong_order", []() {
|
90 |
+
return DependentGuard::report_status() + std::string(" & ") + CustomGuard::report_status();
|
91 |
+
}, py::call_guard<DependentGuard, CustomGuard>());
|
92 |
+
|
93 |
+
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
|
94 |
+
// `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well,
|
95 |
+
// but it's unclear how to test it without `PyGILState_GetThisThreadState`.
|
96 |
+
auto report_gil_status = []() {
|
97 |
+
auto is_gil_held = false;
|
98 |
+
if (auto tstate = py::detail::get_thread_state_unchecked())
|
99 |
+
is_gil_held = (tstate == PyGILState_GetThisThreadState());
|
100 |
+
|
101 |
+
return is_gil_held ? "GIL held" : "GIL released";
|
102 |
+
};
|
103 |
+
|
104 |
+
m.def("with_gil", report_gil_status);
|
105 |
+
m.def("without_gil", report_gil_status, py::call_guard<py::gil_scoped_release>());
|
106 |
+
#endif
|
107 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_call_policies.py
ADDED
@@ -0,0 +1,249 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
import env # noqa: F401
|
5 |
+
|
6 |
+
from pybind11_tests import call_policies as m
|
7 |
+
from pybind11_tests import ConstructorStats
|
8 |
+
|
9 |
+
|
10 |
+
@pytest.mark.xfail("env.PYPY", reason="sometimes comes out 1 off on PyPy", strict=False)
|
11 |
+
def test_keep_alive_argument(capture):
|
12 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
13 |
+
with capture:
|
14 |
+
p = m.Parent()
|
15 |
+
assert capture == "Allocating parent."
|
16 |
+
with capture:
|
17 |
+
p.addChild(m.Child())
|
18 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
19 |
+
assert (
|
20 |
+
capture
|
21 |
+
== """
|
22 |
+
Allocating child.
|
23 |
+
Releasing child.
|
24 |
+
"""
|
25 |
+
)
|
26 |
+
with capture:
|
27 |
+
del p
|
28 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
29 |
+
assert capture == "Releasing parent."
|
30 |
+
|
31 |
+
with capture:
|
32 |
+
p = m.Parent()
|
33 |
+
assert capture == "Allocating parent."
|
34 |
+
with capture:
|
35 |
+
p.addChildKeepAlive(m.Child())
|
36 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
37 |
+
assert capture == "Allocating child."
|
38 |
+
with capture:
|
39 |
+
del p
|
40 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
41 |
+
assert (
|
42 |
+
capture
|
43 |
+
== """
|
44 |
+
Releasing parent.
|
45 |
+
Releasing child.
|
46 |
+
"""
|
47 |
+
)
|
48 |
+
|
49 |
+
p = m.Parent()
|
50 |
+
c = m.Child()
|
51 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
52 |
+
m.free_function(p, c)
|
53 |
+
del c
|
54 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
55 |
+
del p
|
56 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
57 |
+
|
58 |
+
with pytest.raises(RuntimeError) as excinfo:
|
59 |
+
m.invalid_arg_index()
|
60 |
+
assert str(excinfo.value) == "Could not activate keep_alive!"
|
61 |
+
|
62 |
+
|
63 |
+
def test_keep_alive_return_value(capture):
|
64 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
65 |
+
with capture:
|
66 |
+
p = m.Parent()
|
67 |
+
assert capture == "Allocating parent."
|
68 |
+
with capture:
|
69 |
+
p.returnChild()
|
70 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
71 |
+
assert (
|
72 |
+
capture
|
73 |
+
== """
|
74 |
+
Allocating child.
|
75 |
+
Releasing child.
|
76 |
+
"""
|
77 |
+
)
|
78 |
+
with capture:
|
79 |
+
del p
|
80 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
81 |
+
assert capture == "Releasing parent."
|
82 |
+
|
83 |
+
with capture:
|
84 |
+
p = m.Parent()
|
85 |
+
assert capture == "Allocating parent."
|
86 |
+
with capture:
|
87 |
+
p.returnChildKeepAlive()
|
88 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
89 |
+
assert capture == "Allocating child."
|
90 |
+
with capture:
|
91 |
+
del p
|
92 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
93 |
+
assert (
|
94 |
+
capture
|
95 |
+
== """
|
96 |
+
Releasing parent.
|
97 |
+
Releasing child.
|
98 |
+
"""
|
99 |
+
)
|
100 |
+
|
101 |
+
p = m.Parent()
|
102 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
103 |
+
with capture:
|
104 |
+
m.Parent.staticFunction(p)
|
105 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
106 |
+
assert capture == "Allocating child."
|
107 |
+
with capture:
|
108 |
+
del p
|
109 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
110 |
+
assert (
|
111 |
+
capture
|
112 |
+
== """
|
113 |
+
Releasing parent.
|
114 |
+
Releasing child.
|
115 |
+
"""
|
116 |
+
)
|
117 |
+
|
118 |
+
|
119 |
+
# https://foss.heptapod.net/pypy/pypy/-/issues/2447
|
120 |
+
@pytest.mark.xfail("env.PYPY", reason="_PyObject_GetDictPtr is unimplemented")
|
121 |
+
def test_alive_gc(capture):
|
122 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
123 |
+
p = m.ParentGC()
|
124 |
+
p.addChildKeepAlive(m.Child())
|
125 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
126 |
+
lst = [p]
|
127 |
+
lst.append(lst) # creates a circular reference
|
128 |
+
with capture:
|
129 |
+
del p, lst
|
130 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
131 |
+
assert (
|
132 |
+
capture
|
133 |
+
== """
|
134 |
+
Releasing parent.
|
135 |
+
Releasing child.
|
136 |
+
"""
|
137 |
+
)
|
138 |
+
|
139 |
+
|
140 |
+
def test_alive_gc_derived(capture):
|
141 |
+
class Derived(m.Parent):
|
142 |
+
pass
|
143 |
+
|
144 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
145 |
+
p = Derived()
|
146 |
+
p.addChildKeepAlive(m.Child())
|
147 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
148 |
+
lst = [p]
|
149 |
+
lst.append(lst) # creates a circular reference
|
150 |
+
with capture:
|
151 |
+
del p, lst
|
152 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
153 |
+
assert (
|
154 |
+
capture
|
155 |
+
== """
|
156 |
+
Releasing parent.
|
157 |
+
Releasing child.
|
158 |
+
"""
|
159 |
+
)
|
160 |
+
|
161 |
+
|
162 |
+
def test_alive_gc_multi_derived(capture):
|
163 |
+
class Derived(m.Parent, m.Child):
|
164 |
+
def __init__(self):
|
165 |
+
m.Parent.__init__(self)
|
166 |
+
m.Child.__init__(self)
|
167 |
+
|
168 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
169 |
+
p = Derived()
|
170 |
+
p.addChildKeepAlive(m.Child())
|
171 |
+
# +3 rather than +2 because Derived corresponds to two registered instances
|
172 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 3
|
173 |
+
lst = [p]
|
174 |
+
lst.append(lst) # creates a circular reference
|
175 |
+
with capture:
|
176 |
+
del p, lst
|
177 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
178 |
+
assert (
|
179 |
+
capture
|
180 |
+
== """
|
181 |
+
Releasing parent.
|
182 |
+
Releasing child.
|
183 |
+
Releasing child.
|
184 |
+
"""
|
185 |
+
)
|
186 |
+
|
187 |
+
|
188 |
+
def test_return_none(capture):
|
189 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
190 |
+
with capture:
|
191 |
+
p = m.Parent()
|
192 |
+
assert capture == "Allocating parent."
|
193 |
+
with capture:
|
194 |
+
p.returnNullChildKeepAliveChild()
|
195 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
196 |
+
assert capture == ""
|
197 |
+
with capture:
|
198 |
+
del p
|
199 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
200 |
+
assert capture == "Releasing parent."
|
201 |
+
|
202 |
+
with capture:
|
203 |
+
p = m.Parent()
|
204 |
+
assert capture == "Allocating parent."
|
205 |
+
with capture:
|
206 |
+
p.returnNullChildKeepAliveParent()
|
207 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
208 |
+
assert capture == ""
|
209 |
+
with capture:
|
210 |
+
del p
|
211 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
212 |
+
assert capture == "Releasing parent."
|
213 |
+
|
214 |
+
|
215 |
+
def test_keep_alive_constructor(capture):
|
216 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
217 |
+
|
218 |
+
with capture:
|
219 |
+
p = m.Parent(m.Child())
|
220 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
221 |
+
assert (
|
222 |
+
capture
|
223 |
+
== """
|
224 |
+
Allocating child.
|
225 |
+
Allocating parent.
|
226 |
+
"""
|
227 |
+
)
|
228 |
+
with capture:
|
229 |
+
del p
|
230 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
231 |
+
assert (
|
232 |
+
capture
|
233 |
+
== """
|
234 |
+
Releasing parent.
|
235 |
+
Releasing child.
|
236 |
+
"""
|
237 |
+
)
|
238 |
+
|
239 |
+
|
240 |
+
def test_call_guard():
|
241 |
+
assert m.unguarded_call() == "unguarded"
|
242 |
+
assert m.guarded_call() == "guarded"
|
243 |
+
|
244 |
+
assert m.multiple_guards_correct_order() == "guarded & guarded"
|
245 |
+
assert m.multiple_guards_wrong_order() == "unguarded & guarded"
|
246 |
+
|
247 |
+
if hasattr(m, "with_gil"):
|
248 |
+
assert m.with_gil() == "GIL held"
|
249 |
+
assert m.without_gil() == "GIL released"
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_callbacks.cpp
ADDED
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_callbacks.cpp -- callbacks
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "pybind11_tests.h"
|
11 |
+
#include "constructor_stats.h"
|
12 |
+
#include <pybind11/functional.h>
|
13 |
+
#include <thread>
|
14 |
+
|
15 |
+
|
16 |
+
int dummy_function(int i) { return i + 1; }
|
17 |
+
|
18 |
+
TEST_SUBMODULE(callbacks, m) {
|
19 |
+
// test_callbacks, test_function_signatures
|
20 |
+
m.def("test_callback1", [](const py::object &func) { return func(); });
|
21 |
+
m.def("test_callback2", [](const py::object &func) { return func("Hello", 'x', true, 5); });
|
22 |
+
m.def("test_callback3", [](const std::function<int(int)> &func) {
|
23 |
+
return "func(43) = " + std::to_string(func(43)); });
|
24 |
+
m.def("test_callback4", []() -> std::function<int(int)> { return [](int i) { return i+1; }; });
|
25 |
+
m.def("test_callback5", []() {
|
26 |
+
return py::cpp_function([](int i) { return i+1; }, py::arg("number"));
|
27 |
+
});
|
28 |
+
|
29 |
+
// test_keyword_args_and_generalized_unpacking
|
30 |
+
m.def("test_tuple_unpacking", [](const py::function &f) {
|
31 |
+
auto t1 = py::make_tuple(2, 3);
|
32 |
+
auto t2 = py::make_tuple(5, 6);
|
33 |
+
return f("positional", 1, *t1, 4, *t2);
|
34 |
+
});
|
35 |
+
|
36 |
+
m.def("test_dict_unpacking", [](const py::function &f) {
|
37 |
+
auto d1 = py::dict("key"_a="value", "a"_a=1);
|
38 |
+
auto d2 = py::dict();
|
39 |
+
auto d3 = py::dict("b"_a=2);
|
40 |
+
return f("positional", 1, **d1, **d2, **d3);
|
41 |
+
});
|
42 |
+
|
43 |
+
m.def("test_keyword_args", [](const py::function &f) { return f("x"_a = 10, "y"_a = 20); });
|
44 |
+
|
45 |
+
m.def("test_unpacking_and_keywords1", [](const py::function &f) {
|
46 |
+
auto args = py::make_tuple(2);
|
47 |
+
auto kwargs = py::dict("d"_a=4);
|
48 |
+
return f(1, *args, "c"_a=3, **kwargs);
|
49 |
+
});
|
50 |
+
|
51 |
+
m.def("test_unpacking_and_keywords2", [](const py::function &f) {
|
52 |
+
auto kwargs1 = py::dict("a"_a=1);
|
53 |
+
auto kwargs2 = py::dict("c"_a=3, "d"_a=4);
|
54 |
+
return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5,
|
55 |
+
"key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5);
|
56 |
+
});
|
57 |
+
|
58 |
+
m.def("test_unpacking_error1", [](const py::function &f) {
|
59 |
+
auto kwargs = py::dict("x"_a=3);
|
60 |
+
return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword
|
61 |
+
});
|
62 |
+
|
63 |
+
m.def("test_unpacking_error2", [](const py::function &f) {
|
64 |
+
auto kwargs = py::dict("x"_a=3);
|
65 |
+
return f(**kwargs, "x"_a=1); // duplicate keyword after **
|
66 |
+
});
|
67 |
+
|
68 |
+
m.def("test_arg_conversion_error1",
|
69 |
+
[](const py::function &f) { f(234, UnregisteredType(), "kw"_a = 567); });
|
70 |
+
|
71 |
+
m.def("test_arg_conversion_error2", [](const py::function &f) {
|
72 |
+
f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567);
|
73 |
+
});
|
74 |
+
|
75 |
+
// test_lambda_closure_cleanup
|
76 |
+
struct Payload {
|
77 |
+
Payload() { print_default_created(this); }
|
78 |
+
~Payload() { print_destroyed(this); }
|
79 |
+
Payload(const Payload &) { print_copy_created(this); }
|
80 |
+
Payload(Payload &&) noexcept { print_move_created(this); }
|
81 |
+
};
|
82 |
+
// Export the payload constructor statistics for testing purposes:
|
83 |
+
m.def("payload_cstats", &ConstructorStats::get<Payload>);
|
84 |
+
/* Test cleanup of lambda closure */
|
85 |
+
m.def("test_cleanup", []() -> std::function<void()> {
|
86 |
+
Payload p;
|
87 |
+
|
88 |
+
return [p]() {
|
89 |
+
/* p should be cleaned up when the returned function is garbage collected */
|
90 |
+
(void) p;
|
91 |
+
};
|
92 |
+
});
|
93 |
+
|
94 |
+
// test_cpp_function_roundtrip
|
95 |
+
/* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
|
96 |
+
m.def("dummy_function", &dummy_function);
|
97 |
+
m.def("dummy_function_overloaded", [](int i, int j) { return i + j; });
|
98 |
+
m.def("dummy_function_overloaded", &dummy_function);
|
99 |
+
m.def("dummy_function2", [](int i, int j) { return i + j; });
|
100 |
+
m.def("roundtrip", [](std::function<int(int)> f, bool expect_none = false) {
|
101 |
+
if (expect_none && f)
|
102 |
+
throw std::runtime_error("Expected None to be converted to empty std::function");
|
103 |
+
return f;
|
104 |
+
}, py::arg("f"), py::arg("expect_none")=false);
|
105 |
+
m.def("test_dummy_function", [](const std::function<int(int)> &f) -> std::string {
|
106 |
+
using fn_type = int (*)(int);
|
107 |
+
auto result = f.target<fn_type>();
|
108 |
+
if (!result) {
|
109 |
+
auto r = f(1);
|
110 |
+
return "can't convert to function pointer: eval(1) = " + std::to_string(r);
|
111 |
+
}
|
112 |
+
if (*result == dummy_function) {
|
113 |
+
auto r = (*result)(1);
|
114 |
+
return "matches dummy_function: eval(1) = " + std::to_string(r);
|
115 |
+
}
|
116 |
+
return "argument does NOT match dummy_function. This should never happen!";
|
117 |
+
|
118 |
+
});
|
119 |
+
|
120 |
+
class AbstractBase {
|
121 |
+
public:
|
122 |
+
// [workaround(intel)] = default does not work here
|
123 |
+
// Defaulting this destructor results in linking errors with the Intel compiler
|
124 |
+
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
|
125 |
+
virtual ~AbstractBase() {} // NOLINT(modernize-use-equals-default)
|
126 |
+
virtual unsigned int func() = 0;
|
127 |
+
};
|
128 |
+
m.def("func_accepting_func_accepting_base",
|
129 |
+
[](const std::function<double(AbstractBase &)> &) {});
|
130 |
+
|
131 |
+
struct MovableObject {
|
132 |
+
bool valid = true;
|
133 |
+
|
134 |
+
MovableObject() = default;
|
135 |
+
MovableObject(const MovableObject &) = default;
|
136 |
+
MovableObject &operator=(const MovableObject &) = default;
|
137 |
+
MovableObject(MovableObject &&o) noexcept : valid(o.valid) { o.valid = false; }
|
138 |
+
MovableObject &operator=(MovableObject &&o) noexcept {
|
139 |
+
valid = o.valid;
|
140 |
+
o.valid = false;
|
141 |
+
return *this;
|
142 |
+
}
|
143 |
+
};
|
144 |
+
py::class_<MovableObject>(m, "MovableObject");
|
145 |
+
|
146 |
+
// test_movable_object
|
147 |
+
m.def("callback_with_movable", [](const std::function<void(MovableObject &)> &f) {
|
148 |
+
auto x = MovableObject();
|
149 |
+
f(x); // lvalue reference shouldn't move out object
|
150 |
+
return x.valid; // must still return `true`
|
151 |
+
});
|
152 |
+
|
153 |
+
// test_bound_method_callback
|
154 |
+
struct CppBoundMethodTest {};
|
155 |
+
py::class_<CppBoundMethodTest>(m, "CppBoundMethodTest")
|
156 |
+
.def(py::init<>())
|
157 |
+
.def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; });
|
158 |
+
|
159 |
+
// This checks that builtin functions can be passed as callbacks
|
160 |
+
// rather than throwing RuntimeError due to trying to extract as capsule
|
161 |
+
m.def("test_sum_builtin", [](const std::function<double(py::iterable)> &sum_builtin, const py::iterable &i) {
|
162 |
+
return sum_builtin(i);
|
163 |
+
});
|
164 |
+
|
165 |
+
// test async Python callbacks
|
166 |
+
using callback_f = std::function<void(int)>;
|
167 |
+
m.def("test_async_callback", [](const callback_f &f, const py::list &work) {
|
168 |
+
// make detached thread that calls `f` with piece of work after a little delay
|
169 |
+
auto start_f = [f](int j) {
|
170 |
+
auto invoke_f = [f, j] {
|
171 |
+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
172 |
+
f(j);
|
173 |
+
};
|
174 |
+
auto t = std::thread(std::move(invoke_f));
|
175 |
+
t.detach();
|
176 |
+
};
|
177 |
+
|
178 |
+
// spawn worker threads
|
179 |
+
for (auto i : work)
|
180 |
+
start_f(py::cast<int>(i));
|
181 |
+
});
|
182 |
+
|
183 |
+
m.def("callback_num_times", [](const py::function &f, std::size_t num) {
|
184 |
+
for (std::size_t i = 0; i < num; i++) {
|
185 |
+
f();
|
186 |
+
}
|
187 |
+
});
|
188 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_callbacks.py
ADDED
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
from pybind11_tests import callbacks as m
|
4 |
+
from threading import Thread
|
5 |
+
import time
|
6 |
+
import env # NOQA: F401
|
7 |
+
|
8 |
+
|
9 |
+
def test_callbacks():
|
10 |
+
from functools import partial
|
11 |
+
|
12 |
+
def func1():
|
13 |
+
return "func1"
|
14 |
+
|
15 |
+
def func2(a, b, c, d):
|
16 |
+
return "func2", a, b, c, d
|
17 |
+
|
18 |
+
def func3(a):
|
19 |
+
return "func3({})".format(a)
|
20 |
+
|
21 |
+
assert m.test_callback1(func1) == "func1"
|
22 |
+
assert m.test_callback2(func2) == ("func2", "Hello", "x", True, 5)
|
23 |
+
assert m.test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4)
|
24 |
+
assert m.test_callback1(partial(func3, "partial")) == "func3(partial)"
|
25 |
+
assert m.test_callback3(lambda i: i + 1) == "func(43) = 44"
|
26 |
+
|
27 |
+
f = m.test_callback4()
|
28 |
+
assert f(43) == 44
|
29 |
+
f = m.test_callback5()
|
30 |
+
assert f(number=43) == 44
|
31 |
+
|
32 |
+
|
33 |
+
def test_bound_method_callback():
|
34 |
+
# Bound Python method:
|
35 |
+
class MyClass:
|
36 |
+
def double(self, val):
|
37 |
+
return 2 * val
|
38 |
+
|
39 |
+
z = MyClass()
|
40 |
+
assert m.test_callback3(z.double) == "func(43) = 86"
|
41 |
+
|
42 |
+
z = m.CppBoundMethodTest()
|
43 |
+
assert m.test_callback3(z.triple) == "func(43) = 129"
|
44 |
+
|
45 |
+
|
46 |
+
def test_keyword_args_and_generalized_unpacking():
|
47 |
+
def f(*args, **kwargs):
|
48 |
+
return args, kwargs
|
49 |
+
|
50 |
+
assert m.test_tuple_unpacking(f) == (("positional", 1, 2, 3, 4, 5, 6), {})
|
51 |
+
assert m.test_dict_unpacking(f) == (
|
52 |
+
("positional", 1),
|
53 |
+
{"key": "value", "a": 1, "b": 2},
|
54 |
+
)
|
55 |
+
assert m.test_keyword_args(f) == ((), {"x": 10, "y": 20})
|
56 |
+
assert m.test_unpacking_and_keywords1(f) == ((1, 2), {"c": 3, "d": 4})
|
57 |
+
assert m.test_unpacking_and_keywords2(f) == (
|
58 |
+
("positional", 1, 2, 3, 4, 5),
|
59 |
+
{"key": "value", "a": 1, "b": 2, "c": 3, "d": 4, "e": 5},
|
60 |
+
)
|
61 |
+
|
62 |
+
with pytest.raises(TypeError) as excinfo:
|
63 |
+
m.test_unpacking_error1(f)
|
64 |
+
assert "Got multiple values for keyword argument" in str(excinfo.value)
|
65 |
+
|
66 |
+
with pytest.raises(TypeError) as excinfo:
|
67 |
+
m.test_unpacking_error2(f)
|
68 |
+
assert "Got multiple values for keyword argument" in str(excinfo.value)
|
69 |
+
|
70 |
+
with pytest.raises(RuntimeError) as excinfo:
|
71 |
+
m.test_arg_conversion_error1(f)
|
72 |
+
assert "Unable to convert call argument" in str(excinfo.value)
|
73 |
+
|
74 |
+
with pytest.raises(RuntimeError) as excinfo:
|
75 |
+
m.test_arg_conversion_error2(f)
|
76 |
+
assert "Unable to convert call argument" in str(excinfo.value)
|
77 |
+
|
78 |
+
|
79 |
+
def test_lambda_closure_cleanup():
|
80 |
+
m.test_cleanup()
|
81 |
+
cstats = m.payload_cstats()
|
82 |
+
assert cstats.alive() == 0
|
83 |
+
assert cstats.copy_constructions == 1
|
84 |
+
assert cstats.move_constructions >= 1
|
85 |
+
|
86 |
+
|
87 |
+
def test_cpp_function_roundtrip():
|
88 |
+
"""Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer"""
|
89 |
+
|
90 |
+
assert (
|
91 |
+
m.test_dummy_function(m.dummy_function) == "matches dummy_function: eval(1) = 2"
|
92 |
+
)
|
93 |
+
assert (
|
94 |
+
m.test_dummy_function(m.roundtrip(m.dummy_function))
|
95 |
+
== "matches dummy_function: eval(1) = 2"
|
96 |
+
)
|
97 |
+
assert (
|
98 |
+
m.test_dummy_function(m.dummy_function_overloaded)
|
99 |
+
== "matches dummy_function: eval(1) = 2"
|
100 |
+
)
|
101 |
+
assert m.roundtrip(None, expect_none=True) is None
|
102 |
+
assert (
|
103 |
+
m.test_dummy_function(lambda x: x + 2)
|
104 |
+
== "can't convert to function pointer: eval(1) = 3"
|
105 |
+
)
|
106 |
+
|
107 |
+
with pytest.raises(TypeError) as excinfo:
|
108 |
+
m.test_dummy_function(m.dummy_function2)
|
109 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
110 |
+
|
111 |
+
with pytest.raises(TypeError) as excinfo:
|
112 |
+
m.test_dummy_function(lambda x, y: x + y)
|
113 |
+
assert any(
|
114 |
+
s in str(excinfo.value)
|
115 |
+
for s in ("missing 1 required positional argument", "takes exactly 2 arguments")
|
116 |
+
)
|
117 |
+
|
118 |
+
|
119 |
+
def test_function_signatures(doc):
|
120 |
+
assert doc(m.test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str"
|
121 |
+
assert doc(m.test_callback4) == "test_callback4() -> Callable[[int], int]"
|
122 |
+
|
123 |
+
|
124 |
+
def test_movable_object():
|
125 |
+
assert m.callback_with_movable(lambda _: None) is True
|
126 |
+
|
127 |
+
|
128 |
+
@pytest.mark.skipif(
|
129 |
+
"env.PYPY",
|
130 |
+
reason="PyPy segfaults on here. See discussion on #1413.",
|
131 |
+
)
|
132 |
+
def test_python_builtins():
|
133 |
+
"""Test if python builtins like sum() can be used as callbacks"""
|
134 |
+
assert m.test_sum_builtin(sum, [1, 2, 3]) == 6
|
135 |
+
assert m.test_sum_builtin(sum, []) == 0
|
136 |
+
|
137 |
+
|
138 |
+
def test_async_callbacks():
|
139 |
+
# serves as state for async callback
|
140 |
+
class Item:
|
141 |
+
def __init__(self, value):
|
142 |
+
self.value = value
|
143 |
+
|
144 |
+
res = []
|
145 |
+
|
146 |
+
# generate stateful lambda that will store result in `res`
|
147 |
+
def gen_f():
|
148 |
+
s = Item(3)
|
149 |
+
return lambda j: res.append(s.value + j)
|
150 |
+
|
151 |
+
# do some work async
|
152 |
+
work = [1, 2, 3, 4]
|
153 |
+
m.test_async_callback(gen_f(), work)
|
154 |
+
# wait until work is done
|
155 |
+
from time import sleep
|
156 |
+
|
157 |
+
sleep(0.5)
|
158 |
+
assert sum(res) == sum(x + 3 for x in work)
|
159 |
+
|
160 |
+
|
161 |
+
def test_async_async_callbacks():
|
162 |
+
t = Thread(target=test_async_callbacks)
|
163 |
+
t.start()
|
164 |
+
t.join()
|
165 |
+
|
166 |
+
|
167 |
+
def test_callback_num_times():
|
168 |
+
# Super-simple micro-benchmarking related to PR #2919.
|
169 |
+
# Example runtimes (Intel Xeon 2.2GHz, fully optimized):
|
170 |
+
# num_millions 1, repeats 2: 0.1 secs
|
171 |
+
# num_millions 20, repeats 10: 11.5 secs
|
172 |
+
one_million = 1000000
|
173 |
+
num_millions = 1 # Try 20 for actual micro-benchmarking.
|
174 |
+
repeats = 2 # Try 10.
|
175 |
+
rates = []
|
176 |
+
for rep in range(repeats):
|
177 |
+
t0 = time.time()
|
178 |
+
m.callback_num_times(lambda: None, num_millions * one_million)
|
179 |
+
td = time.time() - t0
|
180 |
+
rate = num_millions / td if td else 0
|
181 |
+
rates.append(rate)
|
182 |
+
if not rep:
|
183 |
+
print()
|
184 |
+
print(
|
185 |
+
"callback_num_times: {:d} million / {:.3f} seconds = {:.3f} million / second".format(
|
186 |
+
num_millions, td, rate
|
187 |
+
)
|
188 |
+
)
|
189 |
+
if len(rates) > 1:
|
190 |
+
print("Min Mean Max")
|
191 |
+
print(
|
192 |
+
"{:6.3f} {:6.3f} {:6.3f}".format(
|
193 |
+
min(rates), sum(rates) / len(rates), max(rates)
|
194 |
+
)
|
195 |
+
)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_chrono.cpp
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_chrono.cpp -- test conversions to/from std::chrono types
|
3 |
+
|
4 |
+
Copyright (c) 2016 Trent Houliston <[email protected]> and
|
5 |
+
Wenzel Jakob <[email protected]>
|
6 |
+
|
7 |
+
All rights reserved. Use of this source code is governed by a
|
8 |
+
BSD-style license that can be found in the LICENSE file.
|
9 |
+
*/
|
10 |
+
|
11 |
+
#include "pybind11_tests.h"
|
12 |
+
#include <pybind11/chrono.h>
|
13 |
+
#include <chrono>
|
14 |
+
|
15 |
+
struct different_resolutions {
|
16 |
+
using time_point_h = std::chrono::time_point<
|
17 |
+
std::chrono::system_clock, std::chrono::hours>;
|
18 |
+
using time_point_m = std::chrono::time_point<
|
19 |
+
std::chrono::system_clock, std::chrono::minutes>;
|
20 |
+
using time_point_s = std::chrono::time_point<
|
21 |
+
std::chrono::system_clock, std::chrono::seconds>;
|
22 |
+
using time_point_ms = std::chrono::time_point<
|
23 |
+
std::chrono::system_clock, std::chrono::milliseconds>;
|
24 |
+
using time_point_us = std::chrono::time_point<
|
25 |
+
std::chrono::system_clock, std::chrono::microseconds>;
|
26 |
+
time_point_h timestamp_h;
|
27 |
+
time_point_m timestamp_m;
|
28 |
+
time_point_s timestamp_s;
|
29 |
+
time_point_ms timestamp_ms;
|
30 |
+
time_point_us timestamp_us;
|
31 |
+
};
|
32 |
+
|
33 |
+
TEST_SUBMODULE(chrono, m) {
|
34 |
+
using system_time = std::chrono::system_clock::time_point;
|
35 |
+
using steady_time = std::chrono::steady_clock::time_point;
|
36 |
+
|
37 |
+
using timespan = std::chrono::duration<int64_t, std::nano>;
|
38 |
+
using timestamp = std::chrono::time_point<std::chrono::system_clock, timespan>;
|
39 |
+
|
40 |
+
// test_chrono_system_clock
|
41 |
+
// Return the current time off the wall clock
|
42 |
+
m.def("test_chrono1", []() { return std::chrono::system_clock::now(); });
|
43 |
+
|
44 |
+
// test_chrono_system_clock_roundtrip
|
45 |
+
// Round trip the passed in system clock time
|
46 |
+
m.def("test_chrono2", [](system_time t) { return t; });
|
47 |
+
|
48 |
+
// test_chrono_duration_roundtrip
|
49 |
+
// Round trip the passed in duration
|
50 |
+
m.def("test_chrono3", [](std::chrono::system_clock::duration d) { return d; });
|
51 |
+
|
52 |
+
// test_chrono_duration_subtraction_equivalence
|
53 |
+
// Difference between two passed in time_points
|
54 |
+
m.def("test_chrono4", [](system_time a, system_time b) { return a - b; });
|
55 |
+
|
56 |
+
// test_chrono_steady_clock
|
57 |
+
// Return the current time off the steady_clock
|
58 |
+
m.def("test_chrono5", []() { return std::chrono::steady_clock::now(); });
|
59 |
+
|
60 |
+
// test_chrono_steady_clock_roundtrip
|
61 |
+
// Round trip a steady clock timepoint
|
62 |
+
m.def("test_chrono6", [](steady_time t) { return t; });
|
63 |
+
|
64 |
+
// test_floating_point_duration
|
65 |
+
// Roundtrip a duration in microseconds from a float argument
|
66 |
+
m.def("test_chrono7", [](std::chrono::microseconds t) { return t; });
|
67 |
+
// Float durations (issue #719)
|
68 |
+
m.def("test_chrono_float_diff", [](std::chrono::duration<float> a, std::chrono::duration<float> b) {
|
69 |
+
return a - b; });
|
70 |
+
|
71 |
+
m.def("test_nano_timepoint", [](timestamp start, timespan delta) -> timestamp {
|
72 |
+
return start + delta;
|
73 |
+
});
|
74 |
+
|
75 |
+
// Test different resolutions
|
76 |
+
py::class_<different_resolutions>(m, "different_resolutions")
|
77 |
+
.def(py::init<>())
|
78 |
+
.def_readwrite("timestamp_h", &different_resolutions::timestamp_h)
|
79 |
+
.def_readwrite("timestamp_m", &different_resolutions::timestamp_m)
|
80 |
+
.def_readwrite("timestamp_s", &different_resolutions::timestamp_s)
|
81 |
+
.def_readwrite("timestamp_ms", &different_resolutions::timestamp_ms)
|
82 |
+
.def_readwrite("timestamp_us", &different_resolutions::timestamp_us)
|
83 |
+
;
|
84 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_chrono.py
ADDED
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
from pybind11_tests import chrono as m
|
3 |
+
import datetime
|
4 |
+
import pytest
|
5 |
+
|
6 |
+
import env # noqa: F401
|
7 |
+
|
8 |
+
|
9 |
+
def test_chrono_system_clock():
|
10 |
+
|
11 |
+
# Get the time from both c++ and datetime
|
12 |
+
date0 = datetime.datetime.today()
|
13 |
+
date1 = m.test_chrono1()
|
14 |
+
date2 = datetime.datetime.today()
|
15 |
+
|
16 |
+
# The returned value should be a datetime
|
17 |
+
assert isinstance(date1, datetime.datetime)
|
18 |
+
|
19 |
+
# The numbers should vary by a very small amount (time it took to execute)
|
20 |
+
diff_python = abs(date2 - date0)
|
21 |
+
diff = abs(date1 - date2)
|
22 |
+
|
23 |
+
# There should never be a days difference
|
24 |
+
assert diff.days == 0
|
25 |
+
|
26 |
+
# Since datetime.datetime.today() calls time.time(), and on some platforms
|
27 |
+
# that has 1 second accuracy, we compare this way
|
28 |
+
assert diff.seconds <= diff_python.seconds
|
29 |
+
|
30 |
+
|
31 |
+
def test_chrono_system_clock_roundtrip():
|
32 |
+
date1 = datetime.datetime.today()
|
33 |
+
|
34 |
+
# Roundtrip the time
|
35 |
+
date2 = m.test_chrono2(date1)
|
36 |
+
|
37 |
+
# The returned value should be a datetime
|
38 |
+
assert isinstance(date2, datetime.datetime)
|
39 |
+
|
40 |
+
# They should be identical (no information lost on roundtrip)
|
41 |
+
diff = abs(date1 - date2)
|
42 |
+
assert diff == datetime.timedelta(0)
|
43 |
+
|
44 |
+
|
45 |
+
def test_chrono_system_clock_roundtrip_date():
|
46 |
+
date1 = datetime.date.today()
|
47 |
+
|
48 |
+
# Roundtrip the time
|
49 |
+
datetime2 = m.test_chrono2(date1)
|
50 |
+
date2 = datetime2.date()
|
51 |
+
time2 = datetime2.time()
|
52 |
+
|
53 |
+
# The returned value should be a datetime
|
54 |
+
assert isinstance(datetime2, datetime.datetime)
|
55 |
+
assert isinstance(date2, datetime.date)
|
56 |
+
assert isinstance(time2, datetime.time)
|
57 |
+
|
58 |
+
# They should be identical (no information lost on roundtrip)
|
59 |
+
diff = abs(date1 - date2)
|
60 |
+
assert diff.days == 0
|
61 |
+
assert diff.seconds == 0
|
62 |
+
assert diff.microseconds == 0
|
63 |
+
|
64 |
+
# Year, Month & Day should be the same after the round trip
|
65 |
+
assert date1 == date2
|
66 |
+
|
67 |
+
# There should be no time information
|
68 |
+
assert time2.hour == 0
|
69 |
+
assert time2.minute == 0
|
70 |
+
assert time2.second == 0
|
71 |
+
assert time2.microsecond == 0
|
72 |
+
|
73 |
+
|
74 |
+
SKIP_TZ_ENV_ON_WIN = pytest.mark.skipif(
|
75 |
+
"env.WIN", reason="TZ environment variable only supported on POSIX"
|
76 |
+
)
|
77 |
+
|
78 |
+
|
79 |
+
@pytest.mark.parametrize(
|
80 |
+
"time1",
|
81 |
+
[
|
82 |
+
datetime.datetime.today().time(),
|
83 |
+
datetime.time(0, 0, 0),
|
84 |
+
datetime.time(0, 0, 0, 1),
|
85 |
+
datetime.time(0, 28, 45, 109827),
|
86 |
+
datetime.time(0, 59, 59, 999999),
|
87 |
+
datetime.time(1, 0, 0),
|
88 |
+
datetime.time(5, 59, 59, 0),
|
89 |
+
datetime.time(5, 59, 59, 1),
|
90 |
+
],
|
91 |
+
)
|
92 |
+
@pytest.mark.parametrize(
|
93 |
+
"tz",
|
94 |
+
[
|
95 |
+
None,
|
96 |
+
pytest.param("Europe/Brussels", marks=SKIP_TZ_ENV_ON_WIN),
|
97 |
+
pytest.param("Asia/Pyongyang", marks=SKIP_TZ_ENV_ON_WIN),
|
98 |
+
pytest.param("America/New_York", marks=SKIP_TZ_ENV_ON_WIN),
|
99 |
+
],
|
100 |
+
)
|
101 |
+
def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch):
|
102 |
+
if tz is not None:
|
103 |
+
monkeypatch.setenv("TZ", "/usr/share/zoneinfo/{}".format(tz))
|
104 |
+
|
105 |
+
# Roundtrip the time
|
106 |
+
datetime2 = m.test_chrono2(time1)
|
107 |
+
date2 = datetime2.date()
|
108 |
+
time2 = datetime2.time()
|
109 |
+
|
110 |
+
# The returned value should be a datetime
|
111 |
+
assert isinstance(datetime2, datetime.datetime)
|
112 |
+
assert isinstance(date2, datetime.date)
|
113 |
+
assert isinstance(time2, datetime.time)
|
114 |
+
|
115 |
+
# Hour, Minute, Second & Microsecond should be the same after the round trip
|
116 |
+
assert time1 == time2
|
117 |
+
|
118 |
+
# There should be no date information (i.e. date = python base date)
|
119 |
+
assert date2.year == 1970
|
120 |
+
assert date2.month == 1
|
121 |
+
assert date2.day == 1
|
122 |
+
|
123 |
+
|
124 |
+
def test_chrono_duration_roundtrip():
|
125 |
+
|
126 |
+
# Get the difference between two times (a timedelta)
|
127 |
+
date1 = datetime.datetime.today()
|
128 |
+
date2 = datetime.datetime.today()
|
129 |
+
diff = date2 - date1
|
130 |
+
|
131 |
+
# Make sure this is a timedelta
|
132 |
+
assert isinstance(diff, datetime.timedelta)
|
133 |
+
|
134 |
+
cpp_diff = m.test_chrono3(diff)
|
135 |
+
|
136 |
+
assert cpp_diff == diff
|
137 |
+
|
138 |
+
# Negative timedelta roundtrip
|
139 |
+
diff = datetime.timedelta(microseconds=-1)
|
140 |
+
cpp_diff = m.test_chrono3(diff)
|
141 |
+
|
142 |
+
assert cpp_diff == diff
|
143 |
+
|
144 |
+
|
145 |
+
def test_chrono_duration_subtraction_equivalence():
|
146 |
+
|
147 |
+
date1 = datetime.datetime.today()
|
148 |
+
date2 = datetime.datetime.today()
|
149 |
+
|
150 |
+
diff = date2 - date1
|
151 |
+
cpp_diff = m.test_chrono4(date2, date1)
|
152 |
+
|
153 |
+
assert cpp_diff == diff
|
154 |
+
|
155 |
+
|
156 |
+
def test_chrono_duration_subtraction_equivalence_date():
|
157 |
+
|
158 |
+
date1 = datetime.date.today()
|
159 |
+
date2 = datetime.date.today()
|
160 |
+
|
161 |
+
diff = date2 - date1
|
162 |
+
cpp_diff = m.test_chrono4(date2, date1)
|
163 |
+
|
164 |
+
assert cpp_diff == diff
|
165 |
+
|
166 |
+
|
167 |
+
def test_chrono_steady_clock():
|
168 |
+
time1 = m.test_chrono5()
|
169 |
+
assert isinstance(time1, datetime.timedelta)
|
170 |
+
|
171 |
+
|
172 |
+
def test_chrono_steady_clock_roundtrip():
|
173 |
+
time1 = datetime.timedelta(days=10, seconds=10, microseconds=100)
|
174 |
+
time2 = m.test_chrono6(time1)
|
175 |
+
|
176 |
+
assert isinstance(time2, datetime.timedelta)
|
177 |
+
|
178 |
+
# They should be identical (no information lost on roundtrip)
|
179 |
+
assert time1 == time2
|
180 |
+
|
181 |
+
|
182 |
+
def test_floating_point_duration():
|
183 |
+
# Test using a floating point number in seconds
|
184 |
+
time = m.test_chrono7(35.525123)
|
185 |
+
|
186 |
+
assert isinstance(time, datetime.timedelta)
|
187 |
+
|
188 |
+
assert time.seconds == 35
|
189 |
+
assert 525122 <= time.microseconds <= 525123
|
190 |
+
|
191 |
+
diff = m.test_chrono_float_diff(43.789012, 1.123456)
|
192 |
+
assert diff.seconds == 42
|
193 |
+
assert 665556 <= diff.microseconds <= 665557
|
194 |
+
|
195 |
+
|
196 |
+
def test_nano_timepoint():
|
197 |
+
time = datetime.datetime.now()
|
198 |
+
time1 = m.test_nano_timepoint(time, datetime.timedelta(seconds=60))
|
199 |
+
assert time1 == time + datetime.timedelta(seconds=60)
|
200 |
+
|
201 |
+
|
202 |
+
def test_chrono_different_resolutions():
|
203 |
+
resolutions = m.different_resolutions()
|
204 |
+
time = datetime.datetime.now()
|
205 |
+
resolutions.timestamp_h = time
|
206 |
+
resolutions.timestamp_m = time
|
207 |
+
resolutions.timestamp_s = time
|
208 |
+
resolutions.timestamp_ms = time
|
209 |
+
resolutions.timestamp_us = time
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_class.cpp
ADDED
@@ -0,0 +1,534 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_class.cpp -- test py::class_ definitions and basic functionality
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#if defined(__INTEL_COMPILER) && __cplusplus >= 201703L
|
11 |
+
// Intel compiler requires a separate header file to support aligned new operators
|
12 |
+
// and does not set the __cpp_aligned_new feature macro.
|
13 |
+
// This header needs to be included before pybind11.
|
14 |
+
#include <aligned_new>
|
15 |
+
#endif
|
16 |
+
|
17 |
+
#include "pybind11_tests.h"
|
18 |
+
#include "constructor_stats.h"
|
19 |
+
#include "local_bindings.h"
|
20 |
+
#include <pybind11/stl.h>
|
21 |
+
|
22 |
+
#include <utility>
|
23 |
+
|
24 |
+
#if defined(_MSC_VER)
|
25 |
+
# pragma warning(disable: 4324) // warning C4324: structure was padded due to alignment specifier
|
26 |
+
#endif
|
27 |
+
|
28 |
+
// test_brace_initialization
|
29 |
+
struct NoBraceInitialization {
|
30 |
+
NoBraceInitialization(std::vector<int> v) : vec{std::move(v)} {}
|
31 |
+
template <typename T>
|
32 |
+
NoBraceInitialization(std::initializer_list<T> l) : vec(l) {}
|
33 |
+
|
34 |
+
std::vector<int> vec;
|
35 |
+
};
|
36 |
+
|
37 |
+
TEST_SUBMODULE(class_, m) {
|
38 |
+
// test_instance
|
39 |
+
struct NoConstructor {
|
40 |
+
NoConstructor() = default;
|
41 |
+
NoConstructor(const NoConstructor &) = default;
|
42 |
+
NoConstructor(NoConstructor &&) = default;
|
43 |
+
static NoConstructor *new_instance() {
|
44 |
+
auto *ptr = new NoConstructor();
|
45 |
+
print_created(ptr, "via new_instance");
|
46 |
+
return ptr;
|
47 |
+
}
|
48 |
+
~NoConstructor() { print_destroyed(this); }
|
49 |
+
};
|
50 |
+
|
51 |
+
py::class_<NoConstructor>(m, "NoConstructor")
|
52 |
+
.def_static("new_instance", &NoConstructor::new_instance, "Return an instance");
|
53 |
+
|
54 |
+
// test_inheritance
|
55 |
+
class Pet {
|
56 |
+
public:
|
57 |
+
Pet(const std::string &name, const std::string &species)
|
58 |
+
: m_name(name), m_species(species) {}
|
59 |
+
std::string name() const { return m_name; }
|
60 |
+
std::string species() const { return m_species; }
|
61 |
+
private:
|
62 |
+
std::string m_name;
|
63 |
+
std::string m_species;
|
64 |
+
};
|
65 |
+
|
66 |
+
class Dog : public Pet {
|
67 |
+
public:
|
68 |
+
Dog(const std::string &name) : Pet(name, "dog") {}
|
69 |
+
std::string bark() const { return "Woof!"; }
|
70 |
+
};
|
71 |
+
|
72 |
+
class Rabbit : public Pet {
|
73 |
+
public:
|
74 |
+
Rabbit(const std::string &name) : Pet(name, "parrot") {}
|
75 |
+
};
|
76 |
+
|
77 |
+
class Hamster : public Pet {
|
78 |
+
public:
|
79 |
+
Hamster(const std::string &name) : Pet(name, "rodent") {}
|
80 |
+
};
|
81 |
+
|
82 |
+
class Chimera : public Pet {
|
83 |
+
Chimera() : Pet("Kimmy", "chimera") {}
|
84 |
+
};
|
85 |
+
|
86 |
+
py::class_<Pet> pet_class(m, "Pet");
|
87 |
+
pet_class
|
88 |
+
.def(py::init<std::string, std::string>())
|
89 |
+
.def("name", &Pet::name)
|
90 |
+
.def("species", &Pet::species);
|
91 |
+
|
92 |
+
/* One way of declaring a subclass relationship: reference parent's class_ object */
|
93 |
+
py::class_<Dog>(m, "Dog", pet_class)
|
94 |
+
.def(py::init<std::string>());
|
95 |
+
|
96 |
+
/* Another way of declaring a subclass relationship: reference parent's C++ type */
|
97 |
+
py::class_<Rabbit, Pet>(m, "Rabbit")
|
98 |
+
.def(py::init<std::string>());
|
99 |
+
|
100 |
+
/* And another: list parent in class template arguments */
|
101 |
+
py::class_<Hamster, Pet>(m, "Hamster")
|
102 |
+
.def(py::init<std::string>());
|
103 |
+
|
104 |
+
/* Constructors are not inherited by default */
|
105 |
+
py::class_<Chimera, Pet>(m, "Chimera");
|
106 |
+
|
107 |
+
m.def("pet_name_species", [](const Pet &pet) { return pet.name() + " is a " + pet.species(); });
|
108 |
+
m.def("dog_bark", [](const Dog &dog) { return dog.bark(); });
|
109 |
+
|
110 |
+
// test_automatic_upcasting
|
111 |
+
struct BaseClass {
|
112 |
+
BaseClass() = default;
|
113 |
+
BaseClass(const BaseClass &) = default;
|
114 |
+
BaseClass(BaseClass &&) = default;
|
115 |
+
virtual ~BaseClass() = default;
|
116 |
+
};
|
117 |
+
struct DerivedClass1 : BaseClass { };
|
118 |
+
struct DerivedClass2 : BaseClass { };
|
119 |
+
|
120 |
+
py::class_<BaseClass>(m, "BaseClass").def(py::init<>());
|
121 |
+
py::class_<DerivedClass1>(m, "DerivedClass1").def(py::init<>());
|
122 |
+
py::class_<DerivedClass2>(m, "DerivedClass2").def(py::init<>());
|
123 |
+
|
124 |
+
m.def("return_class_1", []() -> BaseClass* { return new DerivedClass1(); });
|
125 |
+
m.def("return_class_2", []() -> BaseClass* { return new DerivedClass2(); });
|
126 |
+
m.def("return_class_n", [](int n) -> BaseClass* {
|
127 |
+
if (n == 1) return new DerivedClass1();
|
128 |
+
if (n == 2) return new DerivedClass2();
|
129 |
+
return new BaseClass();
|
130 |
+
});
|
131 |
+
m.def("return_none", []() -> BaseClass* { return nullptr; });
|
132 |
+
|
133 |
+
// test_isinstance
|
134 |
+
m.def("check_instances", [](const py::list &l) {
|
135 |
+
return py::make_tuple(
|
136 |
+
py::isinstance<py::tuple>(l[0]),
|
137 |
+
py::isinstance<py::dict>(l[1]),
|
138 |
+
py::isinstance<Pet>(l[2]),
|
139 |
+
py::isinstance<Pet>(l[3]),
|
140 |
+
py::isinstance<Dog>(l[4]),
|
141 |
+
py::isinstance<Rabbit>(l[5]),
|
142 |
+
py::isinstance<UnregisteredType>(l[6])
|
143 |
+
);
|
144 |
+
});
|
145 |
+
|
146 |
+
struct Invalid {};
|
147 |
+
|
148 |
+
// test_type
|
149 |
+
m.def("check_type", [](int category) {
|
150 |
+
// Currently not supported (via a fail at compile time)
|
151 |
+
// See https://github.com/pybind/pybind11/issues/2486
|
152 |
+
// if (category == 2)
|
153 |
+
// return py::type::of<int>();
|
154 |
+
if (category == 1)
|
155 |
+
return py::type::of<DerivedClass1>();
|
156 |
+
return py::type::of<Invalid>();
|
157 |
+
});
|
158 |
+
|
159 |
+
m.def("get_type_of", [](py::object ob) { return py::type::of(std::move(ob)); });
|
160 |
+
|
161 |
+
m.def("get_type_classic", [](py::handle h) {
|
162 |
+
return h.get_type();
|
163 |
+
});
|
164 |
+
|
165 |
+
m.def("as_type", [](const py::object &ob) { return py::type(ob); });
|
166 |
+
|
167 |
+
// test_mismatched_holder
|
168 |
+
struct MismatchBase1 { };
|
169 |
+
struct MismatchDerived1 : MismatchBase1 { };
|
170 |
+
|
171 |
+
struct MismatchBase2 { };
|
172 |
+
struct MismatchDerived2 : MismatchBase2 { };
|
173 |
+
|
174 |
+
m.def("mismatched_holder_1", []() {
|
175 |
+
auto mod = py::module_::import("__main__");
|
176 |
+
py::class_<MismatchBase1, std::shared_ptr<MismatchBase1>>(mod, "MismatchBase1");
|
177 |
+
py::class_<MismatchDerived1, MismatchBase1>(mod, "MismatchDerived1");
|
178 |
+
});
|
179 |
+
m.def("mismatched_holder_2", []() {
|
180 |
+
auto mod = py::module_::import("__main__");
|
181 |
+
py::class_<MismatchBase2>(mod, "MismatchBase2");
|
182 |
+
py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>,
|
183 |
+
MismatchBase2>(mod, "MismatchDerived2");
|
184 |
+
});
|
185 |
+
|
186 |
+
// test_override_static
|
187 |
+
// #511: problem with inheritance + overwritten def_static
|
188 |
+
struct MyBase {
|
189 |
+
static std::unique_ptr<MyBase> make() {
|
190 |
+
return std::unique_ptr<MyBase>(new MyBase());
|
191 |
+
}
|
192 |
+
};
|
193 |
+
|
194 |
+
struct MyDerived : MyBase {
|
195 |
+
static std::unique_ptr<MyDerived> make() {
|
196 |
+
return std::unique_ptr<MyDerived>(new MyDerived());
|
197 |
+
}
|
198 |
+
};
|
199 |
+
|
200 |
+
py::class_<MyBase>(m, "MyBase")
|
201 |
+
.def_static("make", &MyBase::make);
|
202 |
+
|
203 |
+
py::class_<MyDerived, MyBase>(m, "MyDerived")
|
204 |
+
.def_static("make", &MyDerived::make)
|
205 |
+
.def_static("make2", &MyDerived::make);
|
206 |
+
|
207 |
+
// test_implicit_conversion_life_support
|
208 |
+
struct ConvertibleFromUserType {
|
209 |
+
int i;
|
210 |
+
|
211 |
+
ConvertibleFromUserType(UserType u) : i(u.value()) { }
|
212 |
+
};
|
213 |
+
|
214 |
+
py::class_<ConvertibleFromUserType>(m, "AcceptsUserType")
|
215 |
+
.def(py::init<UserType>());
|
216 |
+
py::implicitly_convertible<UserType, ConvertibleFromUserType>();
|
217 |
+
|
218 |
+
m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; });
|
219 |
+
m.def("implicitly_convert_variable", [](const py::object &o) {
|
220 |
+
// `o` is `UserType` and `r` is a reference to a temporary created by implicit
|
221 |
+
// conversion. This is valid when called inside a bound function because the temp
|
222 |
+
// object is attached to the same life support system as the arguments.
|
223 |
+
const auto &r = o.cast<const ConvertibleFromUserType &>();
|
224 |
+
return r.i;
|
225 |
+
});
|
226 |
+
m.add_object("implicitly_convert_variable_fail", [&] {
|
227 |
+
auto f = [](PyObject *, PyObject *args) -> PyObject * {
|
228 |
+
auto o = py::reinterpret_borrow<py::tuple>(args)[0];
|
229 |
+
try { // It should fail here because there is no life support.
|
230 |
+
o.cast<const ConvertibleFromUserType &>();
|
231 |
+
} catch (const py::cast_error &e) {
|
232 |
+
return py::str(e.what()).release().ptr();
|
233 |
+
}
|
234 |
+
return py::str().release().ptr();
|
235 |
+
};
|
236 |
+
|
237 |
+
auto def = new PyMethodDef{"f", f, METH_VARARGS, nullptr};
|
238 |
+
py::capsule def_capsule(def, [](void *ptr) { delete reinterpret_cast<PyMethodDef *>(ptr); });
|
239 |
+
return py::reinterpret_steal<py::object>(PyCFunction_NewEx(def, def_capsule.ptr(), m.ptr()));
|
240 |
+
}());
|
241 |
+
|
242 |
+
// test_operator_new_delete
|
243 |
+
struct HasOpNewDel {
|
244 |
+
std::uint64_t i;
|
245 |
+
static void *operator new(size_t s) { py::print("A new", s); return ::operator new(s); }
|
246 |
+
static void *operator new(size_t s, void *ptr) { py::print("A placement-new", s); return ptr; }
|
247 |
+
static void operator delete(void *p) { py::print("A delete"); return ::operator delete(p); }
|
248 |
+
};
|
249 |
+
struct HasOpNewDelSize {
|
250 |
+
std::uint32_t i;
|
251 |
+
static void *operator new(size_t s) { py::print("B new", s); return ::operator new(s); }
|
252 |
+
static void *operator new(size_t s, void *ptr) { py::print("B placement-new", s); return ptr; }
|
253 |
+
static void operator delete(void *p, size_t s) { py::print("B delete", s); return ::operator delete(p); }
|
254 |
+
};
|
255 |
+
struct AliasedHasOpNewDelSize {
|
256 |
+
std::uint64_t i;
|
257 |
+
static void *operator new(size_t s) { py::print("C new", s); return ::operator new(s); }
|
258 |
+
static void *operator new(size_t s, void *ptr) { py::print("C placement-new", s); return ptr; }
|
259 |
+
static void operator delete(void *p, size_t s) { py::print("C delete", s); return ::operator delete(p); }
|
260 |
+
virtual ~AliasedHasOpNewDelSize() = default;
|
261 |
+
AliasedHasOpNewDelSize() = default;
|
262 |
+
AliasedHasOpNewDelSize(const AliasedHasOpNewDelSize&) = delete;
|
263 |
+
};
|
264 |
+
struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize {
|
265 |
+
PyAliasedHasOpNewDelSize() = default;
|
266 |
+
PyAliasedHasOpNewDelSize(int) { }
|
267 |
+
std::uint64_t j;
|
268 |
+
};
|
269 |
+
struct HasOpNewDelBoth {
|
270 |
+
std::uint32_t i[8];
|
271 |
+
static void *operator new(size_t s) { py::print("D new", s); return ::operator new(s); }
|
272 |
+
static void *operator new(size_t s, void *ptr) { py::print("D placement-new", s); return ptr; }
|
273 |
+
static void operator delete(void *p) { py::print("D delete"); return ::operator delete(p); }
|
274 |
+
static void operator delete(void *p, size_t s) { py::print("D wrong delete", s); return ::operator delete(p); }
|
275 |
+
};
|
276 |
+
py::class_<HasOpNewDel>(m, "HasOpNewDel").def(py::init<>());
|
277 |
+
py::class_<HasOpNewDelSize>(m, "HasOpNewDelSize").def(py::init<>());
|
278 |
+
py::class_<HasOpNewDelBoth>(m, "HasOpNewDelBoth").def(py::init<>());
|
279 |
+
py::class_<AliasedHasOpNewDelSize, PyAliasedHasOpNewDelSize> aliased(m, "AliasedHasOpNewDelSize");
|
280 |
+
aliased.def(py::init<>());
|
281 |
+
aliased.attr("size_noalias") = py::int_(sizeof(AliasedHasOpNewDelSize));
|
282 |
+
aliased.attr("size_alias") = py::int_(sizeof(PyAliasedHasOpNewDelSize));
|
283 |
+
|
284 |
+
// This test is actually part of test_local_bindings (test_duplicate_local), but we need a
|
285 |
+
// definition in a different compilation unit within the same module:
|
286 |
+
bind_local<LocalExternal, 17>(m, "LocalExternal", py::module_local());
|
287 |
+
|
288 |
+
// test_bind_protected_functions
|
289 |
+
class ProtectedA {
|
290 |
+
protected:
|
291 |
+
int foo() const { return value; }
|
292 |
+
|
293 |
+
private:
|
294 |
+
int value = 42;
|
295 |
+
};
|
296 |
+
|
297 |
+
class PublicistA : public ProtectedA {
|
298 |
+
public:
|
299 |
+
using ProtectedA::foo;
|
300 |
+
};
|
301 |
+
|
302 |
+
py::class_<ProtectedA>(m, "ProtectedA")
|
303 |
+
.def(py::init<>())
|
304 |
+
#if !defined(_MSC_VER) || _MSC_VER >= 1910
|
305 |
+
.def("foo", &PublicistA::foo);
|
306 |
+
#else
|
307 |
+
.def("foo", static_cast<int (ProtectedA::*)() const>(&PublicistA::foo));
|
308 |
+
#endif
|
309 |
+
|
310 |
+
class ProtectedB {
|
311 |
+
public:
|
312 |
+
virtual ~ProtectedB() = default;
|
313 |
+
ProtectedB() = default;
|
314 |
+
ProtectedB(const ProtectedB &) = delete;
|
315 |
+
|
316 |
+
protected:
|
317 |
+
virtual int foo() const { return value; }
|
318 |
+
|
319 |
+
private:
|
320 |
+
int value = 42;
|
321 |
+
};
|
322 |
+
|
323 |
+
class TrampolineB : public ProtectedB {
|
324 |
+
public:
|
325 |
+
int foo() const override { PYBIND11_OVERRIDE(int, ProtectedB, foo, ); }
|
326 |
+
};
|
327 |
+
|
328 |
+
class PublicistB : public ProtectedB {
|
329 |
+
public:
|
330 |
+
// [workaround(intel)] = default does not work here
|
331 |
+
// Removing or defaulting this destructor results in linking errors with the Intel compiler
|
332 |
+
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
|
333 |
+
~PublicistB() override {}; // NOLINT(modernize-use-equals-default)
|
334 |
+
using ProtectedB::foo;
|
335 |
+
};
|
336 |
+
|
337 |
+
py::class_<ProtectedB, TrampolineB>(m, "ProtectedB")
|
338 |
+
.def(py::init<>())
|
339 |
+
#if !defined(_MSC_VER) || _MSC_VER >= 1910
|
340 |
+
.def("foo", &PublicistB::foo);
|
341 |
+
#else
|
342 |
+
.def("foo", static_cast<int (ProtectedB::*)() const>(&PublicistB::foo));
|
343 |
+
#endif
|
344 |
+
|
345 |
+
// test_brace_initialization
|
346 |
+
struct BraceInitialization {
|
347 |
+
int field1;
|
348 |
+
std::string field2;
|
349 |
+
};
|
350 |
+
|
351 |
+
py::class_<BraceInitialization>(m, "BraceInitialization")
|
352 |
+
.def(py::init<int, const std::string &>())
|
353 |
+
.def_readwrite("field1", &BraceInitialization::field1)
|
354 |
+
.def_readwrite("field2", &BraceInitialization::field2);
|
355 |
+
// We *don't* want to construct using braces when the given constructor argument maps to a
|
356 |
+
// constructor, because brace initialization could go to the wrong place (in particular when
|
357 |
+
// there is also an `initializer_list<T>`-accept constructor):
|
358 |
+
py::class_<NoBraceInitialization>(m, "NoBraceInitialization")
|
359 |
+
.def(py::init<std::vector<int>>())
|
360 |
+
.def_readonly("vec", &NoBraceInitialization::vec);
|
361 |
+
|
362 |
+
// test_reentrant_implicit_conversion_failure
|
363 |
+
// #1035: issue with runaway reentrant implicit conversion
|
364 |
+
struct BogusImplicitConversion {
|
365 |
+
BogusImplicitConversion(const BogusImplicitConversion &) = default;
|
366 |
+
};
|
367 |
+
|
368 |
+
py::class_<BogusImplicitConversion>(m, "BogusImplicitConversion")
|
369 |
+
.def(py::init<const BogusImplicitConversion &>());
|
370 |
+
|
371 |
+
py::implicitly_convertible<int, BogusImplicitConversion>();
|
372 |
+
|
373 |
+
// test_qualname
|
374 |
+
// #1166: nested class docstring doesn't show nested name
|
375 |
+
// Also related: tests that __qualname__ is set properly
|
376 |
+
struct NestBase {};
|
377 |
+
struct Nested {};
|
378 |
+
py::class_<NestBase> base(m, "NestBase");
|
379 |
+
base.def(py::init<>());
|
380 |
+
py::class_<Nested>(base, "Nested")
|
381 |
+
.def(py::init<>())
|
382 |
+
.def("fn", [](Nested &, int, NestBase &, Nested &) {})
|
383 |
+
.def("fa", [](Nested &, int, NestBase &, Nested &) {},
|
384 |
+
"a"_a, "b"_a, "c"_a);
|
385 |
+
base.def("g", [](NestBase &, Nested &) {});
|
386 |
+
base.def("h", []() { return NestBase(); });
|
387 |
+
|
388 |
+
// test_error_after_conversion
|
389 |
+
// The second-pass path through dispatcher() previously didn't
|
390 |
+
// remember which overload was used, and would crash trying to
|
391 |
+
// generate a useful error message
|
392 |
+
|
393 |
+
struct NotRegistered {};
|
394 |
+
struct StringWrapper { std::string str; };
|
395 |
+
m.def("test_error_after_conversions", [](int) {});
|
396 |
+
m.def("test_error_after_conversions",
|
397 |
+
[](const StringWrapper &) -> NotRegistered { return {}; });
|
398 |
+
py::class_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>());
|
399 |
+
py::implicitly_convertible<std::string, StringWrapper>();
|
400 |
+
|
401 |
+
#if defined(PYBIND11_CPP17)
|
402 |
+
struct alignas(1024) Aligned {
|
403 |
+
std::uintptr_t ptr() const { return (uintptr_t) this; }
|
404 |
+
};
|
405 |
+
py::class_<Aligned>(m, "Aligned")
|
406 |
+
.def(py::init<>())
|
407 |
+
.def("ptr", &Aligned::ptr);
|
408 |
+
#endif
|
409 |
+
|
410 |
+
// test_final
|
411 |
+
struct IsFinal final {};
|
412 |
+
py::class_<IsFinal>(m, "IsFinal", py::is_final());
|
413 |
+
|
414 |
+
// test_non_final_final
|
415 |
+
struct IsNonFinalFinal {};
|
416 |
+
py::class_<IsNonFinalFinal>(m, "IsNonFinalFinal", py::is_final());
|
417 |
+
|
418 |
+
// test_exception_rvalue_abort
|
419 |
+
struct PyPrintDestructor {
|
420 |
+
PyPrintDestructor() = default;
|
421 |
+
~PyPrintDestructor() {
|
422 |
+
py::print("Print from destructor");
|
423 |
+
}
|
424 |
+
void throw_something() { throw std::runtime_error("error"); }
|
425 |
+
};
|
426 |
+
py::class_<PyPrintDestructor>(m, "PyPrintDestructor")
|
427 |
+
.def(py::init<>())
|
428 |
+
.def("throw_something", &PyPrintDestructor::throw_something);
|
429 |
+
|
430 |
+
// test_multiple_instances_with_same_pointer
|
431 |
+
struct SamePointer {};
|
432 |
+
static SamePointer samePointer;
|
433 |
+
py::class_<SamePointer, std::unique_ptr<SamePointer, py::nodelete>>(m, "SamePointer")
|
434 |
+
.def(py::init([]() { return &samePointer; }));
|
435 |
+
|
436 |
+
struct Empty {};
|
437 |
+
py::class_<Empty>(m, "Empty")
|
438 |
+
.def(py::init<>());
|
439 |
+
|
440 |
+
// test_base_and_derived_nested_scope
|
441 |
+
struct BaseWithNested {
|
442 |
+
struct Nested {};
|
443 |
+
};
|
444 |
+
|
445 |
+
struct DerivedWithNested : BaseWithNested {
|
446 |
+
struct Nested {};
|
447 |
+
};
|
448 |
+
|
449 |
+
py::class_<BaseWithNested> baseWithNested_class(m, "BaseWithNested");
|
450 |
+
py::class_<DerivedWithNested, BaseWithNested> derivedWithNested_class(m, "DerivedWithNested");
|
451 |
+
py::class_<BaseWithNested::Nested>(baseWithNested_class, "Nested")
|
452 |
+
.def_static("get_name", []() { return "BaseWithNested::Nested"; });
|
453 |
+
py::class_<DerivedWithNested::Nested>(derivedWithNested_class, "Nested")
|
454 |
+
.def_static("get_name", []() { return "DerivedWithNested::Nested"; });
|
455 |
+
|
456 |
+
// test_register_duplicate_class
|
457 |
+
struct Duplicate {};
|
458 |
+
struct OtherDuplicate {};
|
459 |
+
struct DuplicateNested {};
|
460 |
+
struct OtherDuplicateNested {};
|
461 |
+
|
462 |
+
m.def("register_duplicate_class_name", [](const py::module_ &m) {
|
463 |
+
py::class_<Duplicate>(m, "Duplicate");
|
464 |
+
py::class_<OtherDuplicate>(m, "Duplicate");
|
465 |
+
});
|
466 |
+
m.def("register_duplicate_class_type", [](const py::module_ &m) {
|
467 |
+
py::class_<OtherDuplicate>(m, "OtherDuplicate");
|
468 |
+
py::class_<OtherDuplicate>(m, "YetAnotherDuplicate");
|
469 |
+
});
|
470 |
+
m.def("register_duplicate_nested_class_name", [](const py::object >) {
|
471 |
+
py::class_<DuplicateNested>(gt, "DuplicateNested");
|
472 |
+
py::class_<OtherDuplicateNested>(gt, "DuplicateNested");
|
473 |
+
});
|
474 |
+
m.def("register_duplicate_nested_class_type", [](const py::object >) {
|
475 |
+
py::class_<OtherDuplicateNested>(gt, "OtherDuplicateNested");
|
476 |
+
py::class_<OtherDuplicateNested>(gt, "YetAnotherDuplicateNested");
|
477 |
+
});
|
478 |
+
}
|
479 |
+
|
480 |
+
template <int N> class BreaksBase { public:
|
481 |
+
virtual ~BreaksBase() = default;
|
482 |
+
BreaksBase() = default;
|
483 |
+
BreaksBase(const BreaksBase&) = delete;
|
484 |
+
};
|
485 |
+
template <int N> class BreaksTramp : public BreaksBase<N> {};
|
486 |
+
// These should all compile just fine:
|
487 |
+
using DoesntBreak1 = py::class_<BreaksBase<1>, std::unique_ptr<BreaksBase<1>>, BreaksTramp<1>>;
|
488 |
+
using DoesntBreak2 = py::class_<BreaksBase<2>, BreaksTramp<2>, std::unique_ptr<BreaksBase<2>>>;
|
489 |
+
using DoesntBreak3 = py::class_<BreaksBase<3>, std::unique_ptr<BreaksBase<3>>>;
|
490 |
+
using DoesntBreak4 = py::class_<BreaksBase<4>, BreaksTramp<4>>;
|
491 |
+
using DoesntBreak5 = py::class_<BreaksBase<5>>;
|
492 |
+
using DoesntBreak6 = py::class_<BreaksBase<6>, std::shared_ptr<BreaksBase<6>>, BreaksTramp<6>>;
|
493 |
+
using DoesntBreak7 = py::class_<BreaksBase<7>, BreaksTramp<7>, std::shared_ptr<BreaksBase<7>>>;
|
494 |
+
using DoesntBreak8 = py::class_<BreaksBase<8>, std::shared_ptr<BreaksBase<8>>>;
|
495 |
+
#define CHECK_BASE(N) static_assert(std::is_same<typename DoesntBreak##N::type, BreaksBase<N>>::value, \
|
496 |
+
"DoesntBreak" #N " has wrong type!")
|
497 |
+
CHECK_BASE(1); CHECK_BASE(2); CHECK_BASE(3); CHECK_BASE(4); CHECK_BASE(5); CHECK_BASE(6); CHECK_BASE(7); CHECK_BASE(8);
|
498 |
+
#define CHECK_ALIAS(N) static_assert(DoesntBreak##N::has_alias && std::is_same<typename DoesntBreak##N::type_alias, BreaksTramp<N>>::value, \
|
499 |
+
"DoesntBreak" #N " has wrong type_alias!")
|
500 |
+
#define CHECK_NOALIAS(N) static_assert(!DoesntBreak##N::has_alias && std::is_void<typename DoesntBreak##N::type_alias>::value, \
|
501 |
+
"DoesntBreak" #N " has type alias, but shouldn't!")
|
502 |
+
CHECK_ALIAS(1); CHECK_ALIAS(2); CHECK_NOALIAS(3); CHECK_ALIAS(4); CHECK_NOALIAS(5); CHECK_ALIAS(6); CHECK_ALIAS(7); CHECK_NOALIAS(8);
|
503 |
+
#define CHECK_HOLDER(N, TYPE) static_assert(std::is_same<typename DoesntBreak##N::holder_type, std::TYPE##_ptr<BreaksBase<N>>>::value, \
|
504 |
+
"DoesntBreak" #N " has wrong holder_type!")
|
505 |
+
CHECK_HOLDER(1, unique); CHECK_HOLDER(2, unique); CHECK_HOLDER(3, unique); CHECK_HOLDER(4, unique); CHECK_HOLDER(5, unique);
|
506 |
+
CHECK_HOLDER(6, shared); CHECK_HOLDER(7, shared); CHECK_HOLDER(8, shared);
|
507 |
+
|
508 |
+
// There's no nice way to test that these fail because they fail to compile; leave them here,
|
509 |
+
// though, so that they can be manually tested by uncommenting them (and seeing that compilation
|
510 |
+
// failures occurs).
|
511 |
+
|
512 |
+
// We have to actually look into the type: the typedef alone isn't enough to instantiate the type:
|
513 |
+
#define CHECK_BROKEN(N) static_assert(std::is_same<typename Breaks##N::type, BreaksBase<-N>>::value, \
|
514 |
+
"Breaks1 has wrong type!");
|
515 |
+
|
516 |
+
//// Two holder classes:
|
517 |
+
//typedef py::class_<BreaksBase<-1>, std::unique_ptr<BreaksBase<-1>>, std::unique_ptr<BreaksBase<-1>>> Breaks1;
|
518 |
+
//CHECK_BROKEN(1);
|
519 |
+
//// Two aliases:
|
520 |
+
//typedef py::class_<BreaksBase<-2>, BreaksTramp<-2>, BreaksTramp<-2>> Breaks2;
|
521 |
+
//CHECK_BROKEN(2);
|
522 |
+
//// Holder + 2 aliases
|
523 |
+
//typedef py::class_<BreaksBase<-3>, std::unique_ptr<BreaksBase<-3>>, BreaksTramp<-3>, BreaksTramp<-3>> Breaks3;
|
524 |
+
//CHECK_BROKEN(3);
|
525 |
+
//// Alias + 2 holders
|
526 |
+
//typedef py::class_<BreaksBase<-4>, std::unique_ptr<BreaksBase<-4>>, BreaksTramp<-4>, std::shared_ptr<BreaksBase<-4>>> Breaks4;
|
527 |
+
//CHECK_BROKEN(4);
|
528 |
+
//// Invalid option (not a subclass or holder)
|
529 |
+
//typedef py::class_<BreaksBase<-5>, BreaksTramp<-4>> Breaks5;
|
530 |
+
//CHECK_BROKEN(5);
|
531 |
+
//// Invalid option: multiple inheritance not supported:
|
532 |
+
//template <> struct BreaksBase<-8> : BreaksBase<-6>, BreaksBase<-7> {};
|
533 |
+
//typedef py::class_<BreaksBase<-8>, BreaksBase<-6>, BreaksBase<-7>> Breaks8;
|
534 |
+
//CHECK_BROKEN(8);
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_class.py
ADDED
@@ -0,0 +1,466 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
import env # noqa: F401
|
5 |
+
|
6 |
+
from pybind11_tests import class_ as m
|
7 |
+
from pybind11_tests import UserType, ConstructorStats
|
8 |
+
|
9 |
+
|
10 |
+
def test_repr():
|
11 |
+
# In Python 3.3+, repr() accesses __qualname__
|
12 |
+
assert "pybind11_type" in repr(type(UserType))
|
13 |
+
assert "UserType" in repr(UserType)
|
14 |
+
|
15 |
+
|
16 |
+
def test_instance(msg):
|
17 |
+
with pytest.raises(TypeError) as excinfo:
|
18 |
+
m.NoConstructor()
|
19 |
+
assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!"
|
20 |
+
|
21 |
+
instance = m.NoConstructor.new_instance()
|
22 |
+
|
23 |
+
cstats = ConstructorStats.get(m.NoConstructor)
|
24 |
+
assert cstats.alive() == 1
|
25 |
+
del instance
|
26 |
+
assert cstats.alive() == 0
|
27 |
+
|
28 |
+
|
29 |
+
def test_type():
|
30 |
+
assert m.check_type(1) == m.DerivedClass1
|
31 |
+
with pytest.raises(RuntimeError) as execinfo:
|
32 |
+
m.check_type(0)
|
33 |
+
|
34 |
+
assert "pybind11::detail::get_type_info: unable to find type info" in str(
|
35 |
+
execinfo.value
|
36 |
+
)
|
37 |
+
assert "Invalid" in str(execinfo.value)
|
38 |
+
|
39 |
+
# Currently not supported
|
40 |
+
# See https://github.com/pybind/pybind11/issues/2486
|
41 |
+
# assert m.check_type(2) == int
|
42 |
+
|
43 |
+
|
44 |
+
def test_type_of_py():
|
45 |
+
assert m.get_type_of(1) == int
|
46 |
+
assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
|
47 |
+
assert m.get_type_of(int) == type
|
48 |
+
|
49 |
+
|
50 |
+
def test_type_of_classic():
|
51 |
+
assert m.get_type_classic(1) == int
|
52 |
+
assert m.get_type_classic(m.DerivedClass1()) == m.DerivedClass1
|
53 |
+
assert m.get_type_classic(int) == type
|
54 |
+
|
55 |
+
|
56 |
+
def test_type_of_py_nodelete():
|
57 |
+
# If the above test deleted the class, this will segfault
|
58 |
+
assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
|
59 |
+
|
60 |
+
|
61 |
+
def test_as_type_py():
|
62 |
+
assert m.as_type(int) == int
|
63 |
+
|
64 |
+
with pytest.raises(TypeError):
|
65 |
+
assert m.as_type(1) == int
|
66 |
+
|
67 |
+
with pytest.raises(TypeError):
|
68 |
+
assert m.as_type(m.DerivedClass1()) == m.DerivedClass1
|
69 |
+
|
70 |
+
|
71 |
+
def test_docstrings(doc):
|
72 |
+
assert doc(UserType) == "A `py::class_` type for testing"
|
73 |
+
assert UserType.__name__ == "UserType"
|
74 |
+
assert UserType.__module__ == "pybind11_tests"
|
75 |
+
assert UserType.get_value.__name__ == "get_value"
|
76 |
+
assert UserType.get_value.__module__ == "pybind11_tests"
|
77 |
+
|
78 |
+
assert (
|
79 |
+
doc(UserType.get_value)
|
80 |
+
== """
|
81 |
+
get_value(self: m.UserType) -> int
|
82 |
+
|
83 |
+
Get value using a method
|
84 |
+
"""
|
85 |
+
)
|
86 |
+
assert doc(UserType.value) == "Get/set value using a property"
|
87 |
+
|
88 |
+
assert (
|
89 |
+
doc(m.NoConstructor.new_instance)
|
90 |
+
== """
|
91 |
+
new_instance() -> m.class_.NoConstructor
|
92 |
+
|
93 |
+
Return an instance
|
94 |
+
"""
|
95 |
+
)
|
96 |
+
|
97 |
+
|
98 |
+
def test_qualname(doc):
|
99 |
+
"""Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we
|
100 |
+
backport the attribute) and that generated docstrings properly use it and the module name"""
|
101 |
+
assert m.NestBase.__qualname__ == "NestBase"
|
102 |
+
assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
|
103 |
+
|
104 |
+
assert (
|
105 |
+
doc(m.NestBase.__init__)
|
106 |
+
== """
|
107 |
+
__init__(self: m.class_.NestBase) -> None
|
108 |
+
"""
|
109 |
+
)
|
110 |
+
assert (
|
111 |
+
doc(m.NestBase.g)
|
112 |
+
== """
|
113 |
+
g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None
|
114 |
+
"""
|
115 |
+
)
|
116 |
+
assert (
|
117 |
+
doc(m.NestBase.Nested.__init__)
|
118 |
+
== """
|
119 |
+
__init__(self: m.class_.NestBase.Nested) -> None
|
120 |
+
"""
|
121 |
+
)
|
122 |
+
assert (
|
123 |
+
doc(m.NestBase.Nested.fn)
|
124 |
+
== """
|
125 |
+
fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
|
126 |
+
""" # noqa: E501 line too long
|
127 |
+
)
|
128 |
+
assert (
|
129 |
+
doc(m.NestBase.Nested.fa)
|
130 |
+
== """
|
131 |
+
fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
|
132 |
+
""" # noqa: E501 line too long
|
133 |
+
)
|
134 |
+
assert m.NestBase.__module__ == "pybind11_tests.class_"
|
135 |
+
assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
|
136 |
+
|
137 |
+
|
138 |
+
def test_inheritance(msg):
|
139 |
+
roger = m.Rabbit("Rabbit")
|
140 |
+
assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
|
141 |
+
assert m.pet_name_species(roger) == "Rabbit is a parrot"
|
142 |
+
|
143 |
+
polly = m.Pet("Polly", "parrot")
|
144 |
+
assert polly.name() + " is a " + polly.species() == "Polly is a parrot"
|
145 |
+
assert m.pet_name_species(polly) == "Polly is a parrot"
|
146 |
+
|
147 |
+
molly = m.Dog("Molly")
|
148 |
+
assert molly.name() + " is a " + molly.species() == "Molly is a dog"
|
149 |
+
assert m.pet_name_species(molly) == "Molly is a dog"
|
150 |
+
|
151 |
+
fred = m.Hamster("Fred")
|
152 |
+
assert fred.name() + " is a " + fred.species() == "Fred is a rodent"
|
153 |
+
|
154 |
+
assert m.dog_bark(molly) == "Woof!"
|
155 |
+
|
156 |
+
with pytest.raises(TypeError) as excinfo:
|
157 |
+
m.dog_bark(polly)
|
158 |
+
assert (
|
159 |
+
msg(excinfo.value)
|
160 |
+
== """
|
161 |
+
dog_bark(): incompatible function arguments. The following argument types are supported:
|
162 |
+
1. (arg0: m.class_.Dog) -> str
|
163 |
+
|
164 |
+
Invoked with: <m.class_.Pet object at 0>
|
165 |
+
"""
|
166 |
+
)
|
167 |
+
|
168 |
+
with pytest.raises(TypeError) as excinfo:
|
169 |
+
m.Chimera("lion", "goat")
|
170 |
+
assert "No constructor defined!" in str(excinfo.value)
|
171 |
+
|
172 |
+
|
173 |
+
def test_inheritance_init(msg):
|
174 |
+
|
175 |
+
# Single base
|
176 |
+
class Python(m.Pet):
|
177 |
+
def __init__(self):
|
178 |
+
pass
|
179 |
+
|
180 |
+
with pytest.raises(TypeError) as exc_info:
|
181 |
+
Python()
|
182 |
+
expected = "m.class_.Pet.__init__() must be called when overriding __init__"
|
183 |
+
assert msg(exc_info.value) == expected
|
184 |
+
|
185 |
+
# Multiple bases
|
186 |
+
class RabbitHamster(m.Rabbit, m.Hamster):
|
187 |
+
def __init__(self):
|
188 |
+
m.Rabbit.__init__(self, "RabbitHamster")
|
189 |
+
|
190 |
+
with pytest.raises(TypeError) as exc_info:
|
191 |
+
RabbitHamster()
|
192 |
+
expected = "m.class_.Hamster.__init__() must be called when overriding __init__"
|
193 |
+
assert msg(exc_info.value) == expected
|
194 |
+
|
195 |
+
|
196 |
+
def test_automatic_upcasting():
|
197 |
+
assert type(m.return_class_1()).__name__ == "DerivedClass1"
|
198 |
+
assert type(m.return_class_2()).__name__ == "DerivedClass2"
|
199 |
+
assert type(m.return_none()).__name__ == "NoneType"
|
200 |
+
# Repeat these a few times in a random order to ensure no invalid caching is applied
|
201 |
+
assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
|
202 |
+
assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
|
203 |
+
assert type(m.return_class_n(0)).__name__ == "BaseClass"
|
204 |
+
assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
|
205 |
+
assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
|
206 |
+
assert type(m.return_class_n(0)).__name__ == "BaseClass"
|
207 |
+
assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
|
208 |
+
|
209 |
+
|
210 |
+
def test_isinstance():
|
211 |
+
objects = [tuple(), dict(), m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4
|
212 |
+
expected = (True, True, True, True, True, False, False)
|
213 |
+
assert m.check_instances(objects) == expected
|
214 |
+
|
215 |
+
|
216 |
+
def test_mismatched_holder():
|
217 |
+
import re
|
218 |
+
|
219 |
+
with pytest.raises(RuntimeError) as excinfo:
|
220 |
+
m.mismatched_holder_1()
|
221 |
+
assert re.match(
|
222 |
+
'generic_type: type ".*MismatchDerived1" does not have a non-default '
|
223 |
+
'holder type while its base ".*MismatchBase1" does',
|
224 |
+
str(excinfo.value),
|
225 |
+
)
|
226 |
+
|
227 |
+
with pytest.raises(RuntimeError) as excinfo:
|
228 |
+
m.mismatched_holder_2()
|
229 |
+
assert re.match(
|
230 |
+
'generic_type: type ".*MismatchDerived2" has a non-default holder type '
|
231 |
+
'while its base ".*MismatchBase2" does not',
|
232 |
+
str(excinfo.value),
|
233 |
+
)
|
234 |
+
|
235 |
+
|
236 |
+
def test_override_static():
|
237 |
+
"""#511: problem with inheritance + overwritten def_static"""
|
238 |
+
b = m.MyBase.make()
|
239 |
+
d1 = m.MyDerived.make2()
|
240 |
+
d2 = m.MyDerived.make()
|
241 |
+
|
242 |
+
assert isinstance(b, m.MyBase)
|
243 |
+
assert isinstance(d1, m.MyDerived)
|
244 |
+
assert isinstance(d2, m.MyDerived)
|
245 |
+
|
246 |
+
|
247 |
+
def test_implicit_conversion_life_support():
|
248 |
+
"""Ensure the lifetime of temporary objects created for implicit conversions"""
|
249 |
+
assert m.implicitly_convert_argument(UserType(5)) == 5
|
250 |
+
assert m.implicitly_convert_variable(UserType(5)) == 5
|
251 |
+
|
252 |
+
assert "outside a bound function" in m.implicitly_convert_variable_fail(UserType(5))
|
253 |
+
|
254 |
+
|
255 |
+
def test_operator_new_delete(capture):
|
256 |
+
"""Tests that class-specific operator new/delete functions are invoked"""
|
257 |
+
|
258 |
+
class SubAliased(m.AliasedHasOpNewDelSize):
|
259 |
+
pass
|
260 |
+
|
261 |
+
with capture:
|
262 |
+
a = m.HasOpNewDel()
|
263 |
+
b = m.HasOpNewDelSize()
|
264 |
+
d = m.HasOpNewDelBoth()
|
265 |
+
assert (
|
266 |
+
capture
|
267 |
+
== """
|
268 |
+
A new 8
|
269 |
+
B new 4
|
270 |
+
D new 32
|
271 |
+
"""
|
272 |
+
)
|
273 |
+
sz_alias = str(m.AliasedHasOpNewDelSize.size_alias)
|
274 |
+
sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias)
|
275 |
+
with capture:
|
276 |
+
c = m.AliasedHasOpNewDelSize()
|
277 |
+
c2 = SubAliased()
|
278 |
+
assert capture == ("C new " + sz_noalias + "\n" + "C new " + sz_alias + "\n")
|
279 |
+
|
280 |
+
with capture:
|
281 |
+
del a
|
282 |
+
pytest.gc_collect()
|
283 |
+
del b
|
284 |
+
pytest.gc_collect()
|
285 |
+
del d
|
286 |
+
pytest.gc_collect()
|
287 |
+
assert (
|
288 |
+
capture
|
289 |
+
== """
|
290 |
+
A delete
|
291 |
+
B delete 4
|
292 |
+
D delete
|
293 |
+
"""
|
294 |
+
)
|
295 |
+
|
296 |
+
with capture:
|
297 |
+
del c
|
298 |
+
pytest.gc_collect()
|
299 |
+
del c2
|
300 |
+
pytest.gc_collect()
|
301 |
+
assert capture == ("C delete " + sz_noalias + "\n" + "C delete " + sz_alias + "\n")
|
302 |
+
|
303 |
+
|
304 |
+
def test_bind_protected_functions():
|
305 |
+
"""Expose protected member functions to Python using a helper class"""
|
306 |
+
a = m.ProtectedA()
|
307 |
+
assert a.foo() == 42
|
308 |
+
|
309 |
+
b = m.ProtectedB()
|
310 |
+
assert b.foo() == 42
|
311 |
+
|
312 |
+
class C(m.ProtectedB):
|
313 |
+
def __init__(self):
|
314 |
+
m.ProtectedB.__init__(self)
|
315 |
+
|
316 |
+
def foo(self):
|
317 |
+
return 0
|
318 |
+
|
319 |
+
c = C()
|
320 |
+
assert c.foo() == 0
|
321 |
+
|
322 |
+
|
323 |
+
def test_brace_initialization():
|
324 |
+
"""Tests that simple POD classes can be constructed using C++11 brace initialization"""
|
325 |
+
a = m.BraceInitialization(123, "test")
|
326 |
+
assert a.field1 == 123
|
327 |
+
assert a.field2 == "test"
|
328 |
+
|
329 |
+
# Tests that a non-simple class doesn't get brace initialization (if the
|
330 |
+
# class defines an initializer_list constructor, in particular, it would
|
331 |
+
# win over the expected constructor).
|
332 |
+
b = m.NoBraceInitialization([123, 456])
|
333 |
+
assert b.vec == [123, 456]
|
334 |
+
|
335 |
+
|
336 |
+
@pytest.mark.xfail("env.PYPY")
|
337 |
+
def test_class_refcount():
|
338 |
+
"""Instances must correctly increase/decrease the reference count of their types (#1029)"""
|
339 |
+
from sys import getrefcount
|
340 |
+
|
341 |
+
class PyDog(m.Dog):
|
342 |
+
pass
|
343 |
+
|
344 |
+
for cls in m.Dog, PyDog:
|
345 |
+
refcount_1 = getrefcount(cls)
|
346 |
+
molly = [cls("Molly") for _ in range(10)]
|
347 |
+
refcount_2 = getrefcount(cls)
|
348 |
+
|
349 |
+
del molly
|
350 |
+
pytest.gc_collect()
|
351 |
+
refcount_3 = getrefcount(cls)
|
352 |
+
|
353 |
+
assert refcount_1 == refcount_3
|
354 |
+
assert refcount_2 > refcount_1
|
355 |
+
|
356 |
+
|
357 |
+
def test_reentrant_implicit_conversion_failure(msg):
|
358 |
+
# ensure that there is no runaway reentrant implicit conversion (#1035)
|
359 |
+
with pytest.raises(TypeError) as excinfo:
|
360 |
+
m.BogusImplicitConversion(0)
|
361 |
+
assert (
|
362 |
+
msg(excinfo.value)
|
363 |
+
== """
|
364 |
+
__init__(): incompatible constructor arguments. The following argument types are supported:
|
365 |
+
1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
|
366 |
+
|
367 |
+
Invoked with: 0
|
368 |
+
"""
|
369 |
+
)
|
370 |
+
|
371 |
+
|
372 |
+
def test_error_after_conversions():
|
373 |
+
with pytest.raises(TypeError) as exc_info:
|
374 |
+
m.test_error_after_conversions("hello")
|
375 |
+
assert str(exc_info.value).startswith(
|
376 |
+
"Unable to convert function return value to a Python type!"
|
377 |
+
)
|
378 |
+
|
379 |
+
|
380 |
+
def test_aligned():
|
381 |
+
if hasattr(m, "Aligned"):
|
382 |
+
p = m.Aligned().ptr()
|
383 |
+
assert p % 1024 == 0
|
384 |
+
|
385 |
+
|
386 |
+
# https://foss.heptapod.net/pypy/pypy/-/issues/2742
|
387 |
+
@pytest.mark.xfail("env.PYPY")
|
388 |
+
def test_final():
|
389 |
+
with pytest.raises(TypeError) as exc_info:
|
390 |
+
|
391 |
+
class PyFinalChild(m.IsFinal):
|
392 |
+
pass
|
393 |
+
|
394 |
+
assert str(exc_info.value).endswith("is not an acceptable base type")
|
395 |
+
|
396 |
+
|
397 |
+
# https://foss.heptapod.net/pypy/pypy/-/issues/2742
|
398 |
+
@pytest.mark.xfail("env.PYPY")
|
399 |
+
def test_non_final_final():
|
400 |
+
with pytest.raises(TypeError) as exc_info:
|
401 |
+
|
402 |
+
class PyNonFinalFinalChild(m.IsNonFinalFinal):
|
403 |
+
pass
|
404 |
+
|
405 |
+
assert str(exc_info.value).endswith("is not an acceptable base type")
|
406 |
+
|
407 |
+
|
408 |
+
# https://github.com/pybind/pybind11/issues/1878
|
409 |
+
def test_exception_rvalue_abort():
|
410 |
+
with pytest.raises(RuntimeError):
|
411 |
+
m.PyPrintDestructor().throw_something()
|
412 |
+
|
413 |
+
|
414 |
+
# https://github.com/pybind/pybind11/issues/1568
|
415 |
+
def test_multiple_instances_with_same_pointer(capture):
|
416 |
+
n = 100
|
417 |
+
instances = [m.SamePointer() for _ in range(n)]
|
418 |
+
for i in range(n):
|
419 |
+
# We need to reuse the same allocated memory for with a different type,
|
420 |
+
# to ensure the bug in `deregister_instance_impl` is detected. Otherwise
|
421 |
+
# `Py_TYPE(self) == Py_TYPE(it->second)` will still succeed, even though
|
422 |
+
# the `instance` is already deleted.
|
423 |
+
instances[i] = m.Empty()
|
424 |
+
# No assert: if this does not trigger the error
|
425 |
+
# pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
|
426 |
+
# and just completes without crashing, we're good.
|
427 |
+
|
428 |
+
|
429 |
+
# https://github.com/pybind/pybind11/issues/1624
|
430 |
+
def test_base_and_derived_nested_scope():
|
431 |
+
assert issubclass(m.DerivedWithNested, m.BaseWithNested)
|
432 |
+
assert m.BaseWithNested.Nested != m.DerivedWithNested.Nested
|
433 |
+
assert m.BaseWithNested.Nested.get_name() == "BaseWithNested::Nested"
|
434 |
+
assert m.DerivedWithNested.Nested.get_name() == "DerivedWithNested::Nested"
|
435 |
+
|
436 |
+
|
437 |
+
def test_register_duplicate_class():
|
438 |
+
import types
|
439 |
+
|
440 |
+
module_scope = types.ModuleType("module_scope")
|
441 |
+
with pytest.raises(RuntimeError) as exc_info:
|
442 |
+
m.register_duplicate_class_name(module_scope)
|
443 |
+
expected = (
|
444 |
+
'generic_type: cannot initialize type "Duplicate": '
|
445 |
+
"an object with that name is already defined"
|
446 |
+
)
|
447 |
+
assert str(exc_info.value) == expected
|
448 |
+
with pytest.raises(RuntimeError) as exc_info:
|
449 |
+
m.register_duplicate_class_type(module_scope)
|
450 |
+
expected = 'generic_type: type "YetAnotherDuplicate" is already registered!'
|
451 |
+
assert str(exc_info.value) == expected
|
452 |
+
|
453 |
+
class ClassScope:
|
454 |
+
pass
|
455 |
+
|
456 |
+
with pytest.raises(RuntimeError) as exc_info:
|
457 |
+
m.register_duplicate_nested_class_name(ClassScope)
|
458 |
+
expected = (
|
459 |
+
'generic_type: cannot initialize type "DuplicateNested": '
|
460 |
+
"an object with that name is already defined"
|
461 |
+
)
|
462 |
+
assert str(exc_info.value) == expected
|
463 |
+
with pytest.raises(RuntimeError) as exc_info:
|
464 |
+
m.register_duplicate_nested_class_type(ClassScope)
|
465 |
+
expected = 'generic_type: type "YetAnotherDuplicateNested" is already registered!'
|
466 |
+
assert str(exc_info.value) == expected
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/CMakeLists.txt
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Built-in in CMake 3.5+
|
2 |
+
include(CMakeParseArguments)
|
3 |
+
|
4 |
+
add_custom_target(test_cmake_build)
|
5 |
+
|
6 |
+
function(pybind11_add_build_test name)
|
7 |
+
cmake_parse_arguments(ARG "INSTALL" "" "" ${ARGN})
|
8 |
+
|
9 |
+
set(build_options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}")
|
10 |
+
|
11 |
+
if(PYBIND11_FINDPYTHON)
|
12 |
+
list(APPEND build_options "-DPYBIND11_FINDPYTHON=${PYBIND11_FINDPYTHON}")
|
13 |
+
|
14 |
+
if(DEFINED Python_ROOT_DIR)
|
15 |
+
list(APPEND build_options "-DPython_ROOT_DIR=${Python_ROOT_DIR}")
|
16 |
+
endif()
|
17 |
+
|
18 |
+
list(APPEND build_options "-DPython_EXECUTABLE=${Python_EXECUTABLE}")
|
19 |
+
else()
|
20 |
+
list(APPEND build_options "-DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}")
|
21 |
+
endif()
|
22 |
+
|
23 |
+
if(DEFINED CMAKE_CXX_STANDARD)
|
24 |
+
list(APPEND build_options "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}")
|
25 |
+
endif()
|
26 |
+
|
27 |
+
if(NOT ARG_INSTALL)
|
28 |
+
list(APPEND build_options "-Dpybind11_SOURCE_DIR=${pybind11_SOURCE_DIR}")
|
29 |
+
else()
|
30 |
+
list(APPEND build_options "-DCMAKE_PREFIX_PATH=${pybind11_BINARY_DIR}/mock_install")
|
31 |
+
endif()
|
32 |
+
|
33 |
+
add_custom_target(
|
34 |
+
test_build_${name}
|
35 |
+
${CMAKE_CTEST_COMMAND}
|
36 |
+
--build-and-test
|
37 |
+
"${CMAKE_CURRENT_SOURCE_DIR}/${name}"
|
38 |
+
"${CMAKE_CURRENT_BINARY_DIR}/${name}"
|
39 |
+
--build-config
|
40 |
+
Release
|
41 |
+
--build-noclean
|
42 |
+
--build-generator
|
43 |
+
${CMAKE_GENERATOR}
|
44 |
+
$<$<BOOL:${CMAKE_GENERATOR_PLATFORM}>:--build-generator-platform>
|
45 |
+
${CMAKE_GENERATOR_PLATFORM}
|
46 |
+
--build-makeprogram
|
47 |
+
${CMAKE_MAKE_PROGRAM}
|
48 |
+
--build-target
|
49 |
+
check_${name}
|
50 |
+
--build-options
|
51 |
+
${build_options})
|
52 |
+
if(ARG_INSTALL)
|
53 |
+
add_dependencies(test_build_${name} mock_install)
|
54 |
+
endif()
|
55 |
+
add_dependencies(test_cmake_build test_build_${name})
|
56 |
+
endfunction()
|
57 |
+
|
58 |
+
possibly_uninitialized(PYTHON_MODULE_EXTENSION Python_INTERPRETER_ID)
|
59 |
+
|
60 |
+
pybind11_add_build_test(subdirectory_function)
|
61 |
+
pybind11_add_build_test(subdirectory_target)
|
62 |
+
if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy")
|
63 |
+
message(STATUS "Skipping embed test on PyPy")
|
64 |
+
else()
|
65 |
+
pybind11_add_build_test(subdirectory_embed)
|
66 |
+
endif()
|
67 |
+
|
68 |
+
if(PYBIND11_INSTALL)
|
69 |
+
add_custom_target(
|
70 |
+
mock_install ${CMAKE_COMMAND} "-DCMAKE_INSTALL_PREFIX=${pybind11_BINARY_DIR}/mock_install" -P
|
71 |
+
"${pybind11_BINARY_DIR}/cmake_install.cmake")
|
72 |
+
|
73 |
+
pybind11_add_build_test(installed_function INSTALL)
|
74 |
+
pybind11_add_build_test(installed_target INSTALL)
|
75 |
+
if(NOT ("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy"
|
76 |
+
))
|
77 |
+
pybind11_add_build_test(installed_embed INSTALL)
|
78 |
+
endif()
|
79 |
+
endif()
|
80 |
+
|
81 |
+
add_dependencies(check test_cmake_build)
|
82 |
+
|
83 |
+
add_subdirectory(subdirectory_target EXCLUDE_FROM_ALL)
|
84 |
+
add_subdirectory(subdirectory_embed EXCLUDE_FROM_ALL)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/embed.cpp
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <pybind11/embed.h>
|
2 |
+
namespace py = pybind11;
|
3 |
+
|
4 |
+
PYBIND11_EMBEDDED_MODULE(test_cmake_build, m) {
|
5 |
+
m.def("add", [](int i, int j) { return i + j; });
|
6 |
+
}
|
7 |
+
|
8 |
+
int main(int argc, char *argv[]) {
|
9 |
+
if (argc != 2)
|
10 |
+
throw std::runtime_error("Expected test.py file as the first argument");
|
11 |
+
auto test_py_file = argv[1];
|
12 |
+
|
13 |
+
py::scoped_interpreter guard{};
|
14 |
+
|
15 |
+
auto m = py::module_::import("test_cmake_build");
|
16 |
+
if (m.attr("add")(1, 2).cast<int>() != 3)
|
17 |
+
throw std::runtime_error("embed.cpp failed");
|
18 |
+
|
19 |
+
py::module_::import("sys").attr("argv") = py::make_tuple("test.py", "embed.cpp");
|
20 |
+
py::eval_file(test_py_file, py::globals());
|
21 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required(VERSION 3.4)
|
2 |
+
|
3 |
+
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
|
4 |
+
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
5 |
+
# the behavior using the following workaround:
|
6 |
+
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
7 |
+
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
8 |
+
else()
|
9 |
+
cmake_policy(VERSION 3.18)
|
10 |
+
endif()
|
11 |
+
|
12 |
+
project(test_installed_embed CXX)
|
13 |
+
|
14 |
+
find_package(pybind11 CONFIG REQUIRED)
|
15 |
+
message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
|
16 |
+
|
17 |
+
add_executable(test_installed_embed ../embed.cpp)
|
18 |
+
target_link_libraries(test_installed_embed PRIVATE pybind11::embed)
|
19 |
+
set_target_properties(test_installed_embed PROPERTIES OUTPUT_NAME test_cmake_build)
|
20 |
+
|
21 |
+
# Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::embed).
|
22 |
+
# This may be needed to resolve header conflicts, e.g. between Python release and debug headers.
|
23 |
+
set_target_properties(test_installed_embed PROPERTIES NO_SYSTEM_FROM_IMPORTED ON)
|
24 |
+
|
25 |
+
add_custom_target(check_installed_embed $<TARGET_FILE:test_installed_embed>
|
26 |
+
${PROJECT_SOURCE_DIR}/../test.py)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required(VERSION 3.4)
|
2 |
+
project(test_installed_module CXX)
|
3 |
+
|
4 |
+
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
|
5 |
+
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
6 |
+
# the behavior using the following workaround:
|
7 |
+
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
8 |
+
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
9 |
+
else()
|
10 |
+
cmake_policy(VERSION 3.18)
|
11 |
+
endif()
|
12 |
+
|
13 |
+
project(test_installed_function CXX)
|
14 |
+
|
15 |
+
find_package(pybind11 CONFIG REQUIRED)
|
16 |
+
message(
|
17 |
+
STATUS "Found pybind11 v${pybind11_VERSION} ${pybind11_VERSION_TYPE}: ${pybind11_INCLUDE_DIRS}")
|
18 |
+
|
19 |
+
pybind11_add_module(test_installed_function SHARED NO_EXTRAS ../main.cpp)
|
20 |
+
set_target_properties(test_installed_function PROPERTIES OUTPUT_NAME test_cmake_build)
|
21 |
+
|
22 |
+
if(DEFINED Python_EXECUTABLE)
|
23 |
+
set(_Python_EXECUTABLE "${Python_EXECUTABLE}")
|
24 |
+
elseif(DEFINED PYTHON_EXECUTABLE)
|
25 |
+
set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
26 |
+
else()
|
27 |
+
message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)")
|
28 |
+
endif()
|
29 |
+
|
30 |
+
add_custom_target(
|
31 |
+
check_installed_function
|
32 |
+
${CMAKE_COMMAND}
|
33 |
+
-E
|
34 |
+
env
|
35 |
+
PYTHONPATH=$<TARGET_FILE_DIR:test_installed_function>
|
36 |
+
${_Python_EXECUTABLE}
|
37 |
+
${PROJECT_SOURCE_DIR}/../test.py
|
38 |
+
${PROJECT_NAME})
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required(VERSION 3.4)
|
2 |
+
|
3 |
+
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
|
4 |
+
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
5 |
+
# the behavior using the following workaround:
|
6 |
+
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
7 |
+
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
8 |
+
else()
|
9 |
+
cmake_policy(VERSION 3.18)
|
10 |
+
endif()
|
11 |
+
|
12 |
+
project(test_installed_target CXX)
|
13 |
+
|
14 |
+
find_package(pybind11 CONFIG REQUIRED)
|
15 |
+
message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
|
16 |
+
|
17 |
+
add_library(test_installed_target MODULE ../main.cpp)
|
18 |
+
|
19 |
+
target_link_libraries(test_installed_target PRIVATE pybind11::module)
|
20 |
+
set_target_properties(test_installed_target PROPERTIES OUTPUT_NAME test_cmake_build)
|
21 |
+
|
22 |
+
# Make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib
|
23 |
+
pybind11_extension(test_installed_target)
|
24 |
+
|
25 |
+
# Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::module).
|
26 |
+
# This may be needed to resolve header conflicts, e.g. between Python release and debug headers.
|
27 |
+
set_target_properties(test_installed_target PROPERTIES NO_SYSTEM_FROM_IMPORTED ON)
|
28 |
+
|
29 |
+
if(DEFINED Python_EXECUTABLE)
|
30 |
+
set(_Python_EXECUTABLE "${Python_EXECUTABLE}")
|
31 |
+
elseif(DEFINED PYTHON_EXECUTABLE)
|
32 |
+
set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
33 |
+
else()
|
34 |
+
message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)")
|
35 |
+
endif()
|
36 |
+
|
37 |
+
add_custom_target(
|
38 |
+
check_installed_target
|
39 |
+
${CMAKE_COMMAND}
|
40 |
+
-E
|
41 |
+
env
|
42 |
+
PYTHONPATH=$<TARGET_FILE_DIR:test_installed_target>
|
43 |
+
${_Python_EXECUTABLE}
|
44 |
+
${PROJECT_SOURCE_DIR}/../test.py
|
45 |
+
${PROJECT_NAME})
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/main.cpp
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <pybind11/pybind11.h>
|
2 |
+
namespace py = pybind11;
|
3 |
+
|
4 |
+
PYBIND11_MODULE(test_cmake_build, m) {
|
5 |
+
m.def("add", [](int i, int j) { return i + j; });
|
6 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required(VERSION 3.4)
|
2 |
+
|
3 |
+
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
|
4 |
+
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
5 |
+
# the behavior using the following workaround:
|
6 |
+
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
7 |
+
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
8 |
+
else()
|
9 |
+
cmake_policy(VERSION 3.18)
|
10 |
+
endif()
|
11 |
+
|
12 |
+
project(test_subdirectory_embed CXX)
|
13 |
+
|
14 |
+
set(PYBIND11_INSTALL
|
15 |
+
ON
|
16 |
+
CACHE BOOL "")
|
17 |
+
set(PYBIND11_EXPORT_NAME test_export)
|
18 |
+
|
19 |
+
add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
|
20 |
+
|
21 |
+
# Test basic target functionality
|
22 |
+
add_executable(test_subdirectory_embed ../embed.cpp)
|
23 |
+
target_link_libraries(test_subdirectory_embed PRIVATE pybind11::embed)
|
24 |
+
set_target_properties(test_subdirectory_embed PROPERTIES OUTPUT_NAME test_cmake_build)
|
25 |
+
|
26 |
+
add_custom_target(check_subdirectory_embed $<TARGET_FILE:test_subdirectory_embed>
|
27 |
+
"${PROJECT_SOURCE_DIR}/../test.py")
|
28 |
+
|
29 |
+
# Test custom export group -- PYBIND11_EXPORT_NAME
|
30 |
+
add_library(test_embed_lib ../embed.cpp)
|
31 |
+
target_link_libraries(test_embed_lib PRIVATE pybind11::embed)
|
32 |
+
|
33 |
+
install(
|
34 |
+
TARGETS test_embed_lib
|
35 |
+
EXPORT test_export
|
36 |
+
ARCHIVE DESTINATION bin
|
37 |
+
LIBRARY DESTINATION lib
|
38 |
+
RUNTIME DESTINATION lib)
|
39 |
+
install(EXPORT test_export DESTINATION lib/cmake/test_export/test_export-Targets.cmake)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required(VERSION 3.4)
|
2 |
+
|
3 |
+
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
|
4 |
+
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
5 |
+
# the behavior using the following workaround:
|
6 |
+
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
7 |
+
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
8 |
+
else()
|
9 |
+
cmake_policy(VERSION 3.18)
|
10 |
+
endif()
|
11 |
+
|
12 |
+
project(test_subdirectory_function CXX)
|
13 |
+
|
14 |
+
add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
|
15 |
+
pybind11_add_module(test_subdirectory_function ../main.cpp)
|
16 |
+
set_target_properties(test_subdirectory_function PROPERTIES OUTPUT_NAME test_cmake_build)
|
17 |
+
|
18 |
+
if(DEFINED Python_EXECUTABLE)
|
19 |
+
set(_Python_EXECUTABLE "${Python_EXECUTABLE}")
|
20 |
+
elseif(DEFINED PYTHON_EXECUTABLE)
|
21 |
+
set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
22 |
+
else()
|
23 |
+
message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)")
|
24 |
+
endif()
|
25 |
+
|
26 |
+
add_custom_target(
|
27 |
+
check_subdirectory_function
|
28 |
+
${CMAKE_COMMAND}
|
29 |
+
-E
|
30 |
+
env
|
31 |
+
PYTHONPATH=$<TARGET_FILE_DIR:test_subdirectory_function>
|
32 |
+
${_Python_EXECUTABLE}
|
33 |
+
${PROJECT_SOURCE_DIR}/../test.py
|
34 |
+
${PROJECT_NAME})
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required(VERSION 3.4)
|
2 |
+
|
3 |
+
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
|
4 |
+
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
5 |
+
# the behavior using the following workaround:
|
6 |
+
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
7 |
+
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
8 |
+
else()
|
9 |
+
cmake_policy(VERSION 3.18)
|
10 |
+
endif()
|
11 |
+
|
12 |
+
project(test_subdirectory_target CXX)
|
13 |
+
|
14 |
+
add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
|
15 |
+
|
16 |
+
add_library(test_subdirectory_target MODULE ../main.cpp)
|
17 |
+
set_target_properties(test_subdirectory_target PROPERTIES OUTPUT_NAME test_cmake_build)
|
18 |
+
|
19 |
+
target_link_libraries(test_subdirectory_target PRIVATE pybind11::module)
|
20 |
+
|
21 |
+
# Make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib
|
22 |
+
pybind11_extension(test_subdirectory_target)
|
23 |
+
|
24 |
+
if(DEFINED Python_EXECUTABLE)
|
25 |
+
set(_Python_EXECUTABLE "${Python_EXECUTABLE}")
|
26 |
+
elseif(DEFINED PYTHON_EXECUTABLE)
|
27 |
+
set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
28 |
+
else()
|
29 |
+
message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)")
|
30 |
+
endif()
|
31 |
+
|
32 |
+
add_custom_target(
|
33 |
+
check_subdirectory_target
|
34 |
+
${CMAKE_COMMAND}
|
35 |
+
-E
|
36 |
+
env
|
37 |
+
PYTHONPATH=$<TARGET_FILE_DIR:test_subdirectory_target>
|
38 |
+
${_Python_EXECUTABLE}
|
39 |
+
${PROJECT_SOURCE_DIR}/../test.py
|
40 |
+
${PROJECT_NAME})
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_cmake_build/test.py
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import sys
|
3 |
+
import test_cmake_build
|
4 |
+
|
5 |
+
assert test_cmake_build.add(1, 2) == 3
|
6 |
+
print("{} imports, runs, and adds: 1 + 2 = 3".format(sys.argv[1]))
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_constants_and_functions.cpp
ADDED
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw
|
3 |
+
byte strings
|
4 |
+
|
5 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
6 |
+
|
7 |
+
All rights reserved. Use of this source code is governed by a
|
8 |
+
BSD-style license that can be found in the LICENSE file.
|
9 |
+
*/
|
10 |
+
|
11 |
+
#include "pybind11_tests.h"
|
12 |
+
|
13 |
+
enum MyEnum { EFirstEntry = 1, ESecondEntry };
|
14 |
+
|
15 |
+
std::string test_function1() {
|
16 |
+
return "test_function()";
|
17 |
+
}
|
18 |
+
|
19 |
+
std::string test_function2(MyEnum k) {
|
20 |
+
return "test_function(enum=" + std::to_string(k) + ")";
|
21 |
+
}
|
22 |
+
|
23 |
+
std::string test_function3(int i) {
|
24 |
+
return "test_function(" + std::to_string(i) + ")";
|
25 |
+
}
|
26 |
+
|
27 |
+
py::str test_function4() { return "test_function()"; }
|
28 |
+
py::str test_function4(char *) { return "test_function(char *)"; }
|
29 |
+
py::str test_function4(int, float) { return "test_function(int, float)"; }
|
30 |
+
py::str test_function4(float, int) { return "test_function(float, int)"; }
|
31 |
+
|
32 |
+
py::bytes return_bytes() {
|
33 |
+
const char *data = "\x01\x00\x02\x00";
|
34 |
+
return std::string(data, 4);
|
35 |
+
}
|
36 |
+
|
37 |
+
std::string print_bytes(const py::bytes &bytes) {
|
38 |
+
std::string ret = "bytes[";
|
39 |
+
const auto value = static_cast<std::string>(bytes);
|
40 |
+
for (size_t i = 0; i < value.length(); ++i) {
|
41 |
+
ret += std::to_string(static_cast<int>(value[i])) + " ";
|
42 |
+
}
|
43 |
+
ret.back() = ']';
|
44 |
+
return ret;
|
45 |
+
}
|
46 |
+
|
47 |
+
// Test that we properly handle C++17 exception specifiers (which are part of the function signature
|
48 |
+
// in C++17). These should all still work before C++17, but don't affect the function signature.
|
49 |
+
namespace test_exc_sp {
|
50 |
+
// [workaround(intel)] Unable to use noexcept instead of noexcept(true)
|
51 |
+
// Make the f1 test basically the same as the f2 test in C++17 mode for the Intel compiler as
|
52 |
+
// it fails to compile with a plain noexcept (tested with icc (ICC) 2021.1 Beta 20200827).
|
53 |
+
#if defined(__INTEL_COMPILER) && defined(PYBIND11_CPP17)
|
54 |
+
int f1(int x) noexcept(true) { return x+1; }
|
55 |
+
#else
|
56 |
+
int f1(int x) noexcept { return x+1; }
|
57 |
+
#endif
|
58 |
+
int f2(int x) noexcept(true) { return x+2; }
|
59 |
+
int f3(int x) noexcept(false) { return x+3; }
|
60 |
+
#if defined(__GNUG__) && !defined(__INTEL_COMPILER)
|
61 |
+
# pragma GCC diagnostic push
|
62 |
+
# pragma GCC diagnostic ignored "-Wdeprecated"
|
63 |
+
#endif
|
64 |
+
// NOLINTNEXTLINE(modernize-use-noexcept)
|
65 |
+
int f4(int x) throw() { return x+4; } // Deprecated equivalent to noexcept(true)
|
66 |
+
#if defined(__GNUG__) && !defined(__INTEL_COMPILER)
|
67 |
+
# pragma GCC diagnostic pop
|
68 |
+
#endif
|
69 |
+
struct C {
|
70 |
+
int m1(int x) noexcept { return x-1; }
|
71 |
+
int m2(int x) const noexcept { return x-2; }
|
72 |
+
int m3(int x) noexcept(true) { return x-3; }
|
73 |
+
int m4(int x) const noexcept(true) { return x-4; }
|
74 |
+
int m5(int x) noexcept(false) { return x-5; }
|
75 |
+
int m6(int x) const noexcept(false) { return x-6; }
|
76 |
+
#if defined(__GNUG__) && !defined(__INTEL_COMPILER)
|
77 |
+
# pragma GCC diagnostic push
|
78 |
+
# pragma GCC diagnostic ignored "-Wdeprecated"
|
79 |
+
#endif
|
80 |
+
// NOLINTNEXTLINE(modernize-use-noexcept)
|
81 |
+
int m7(int x) throw() { return x - 7; }
|
82 |
+
// NOLINTNEXTLINE(modernize-use-noexcept)
|
83 |
+
int m8(int x) const throw() { return x - 8; }
|
84 |
+
#if defined(__GNUG__) && !defined(__INTEL_COMPILER)
|
85 |
+
# pragma GCC diagnostic pop
|
86 |
+
#endif
|
87 |
+
};
|
88 |
+
} // namespace test_exc_sp
|
89 |
+
|
90 |
+
|
91 |
+
TEST_SUBMODULE(constants_and_functions, m) {
|
92 |
+
// test_constants
|
93 |
+
m.attr("some_constant") = py::int_(14);
|
94 |
+
|
95 |
+
// test_function_overloading
|
96 |
+
m.def("test_function", &test_function1);
|
97 |
+
m.def("test_function", &test_function2);
|
98 |
+
m.def("test_function", &test_function3);
|
99 |
+
|
100 |
+
#if defined(PYBIND11_OVERLOAD_CAST)
|
101 |
+
m.def("test_function", py::overload_cast<>(&test_function4));
|
102 |
+
m.def("test_function", py::overload_cast<char *>(&test_function4));
|
103 |
+
m.def("test_function", py::overload_cast<int, float>(&test_function4));
|
104 |
+
m.def("test_function", py::overload_cast<float, int>(&test_function4));
|
105 |
+
#else
|
106 |
+
m.def("test_function", static_cast<py::str (*)()>(&test_function4));
|
107 |
+
m.def("test_function", static_cast<py::str (*)(char *)>(&test_function4));
|
108 |
+
m.def("test_function", static_cast<py::str (*)(int, float)>(&test_function4));
|
109 |
+
m.def("test_function", static_cast<py::str (*)(float, int)>(&test_function4));
|
110 |
+
#endif
|
111 |
+
|
112 |
+
py::enum_<MyEnum>(m, "MyEnum")
|
113 |
+
.value("EFirstEntry", EFirstEntry)
|
114 |
+
.value("ESecondEntry", ESecondEntry)
|
115 |
+
.export_values();
|
116 |
+
|
117 |
+
// test_bytes
|
118 |
+
m.def("return_bytes", &return_bytes);
|
119 |
+
m.def("print_bytes", &print_bytes);
|
120 |
+
|
121 |
+
// test_exception_specifiers
|
122 |
+
using namespace test_exc_sp;
|
123 |
+
py::class_<C>(m, "C")
|
124 |
+
.def(py::init<>())
|
125 |
+
.def("m1", &C::m1)
|
126 |
+
.def("m2", &C::m2)
|
127 |
+
.def("m3", &C::m3)
|
128 |
+
.def("m4", &C::m4)
|
129 |
+
.def("m5", &C::m5)
|
130 |
+
.def("m6", &C::m6)
|
131 |
+
.def("m7", &C::m7)
|
132 |
+
.def("m8", &C::m8)
|
133 |
+
;
|
134 |
+
m.def("f1", f1);
|
135 |
+
m.def("f2", f2);
|
136 |
+
#if defined(__INTEL_COMPILER)
|
137 |
+
# pragma warning push
|
138 |
+
# pragma warning disable 878 // incompatible exception specifications
|
139 |
+
#endif
|
140 |
+
m.def("f3", f3);
|
141 |
+
#if defined(__INTEL_COMPILER)
|
142 |
+
# pragma warning pop
|
143 |
+
#endif
|
144 |
+
m.def("f4", f4);
|
145 |
+
|
146 |
+
// test_function_record_leaks
|
147 |
+
struct LargeCapture {
|
148 |
+
// This should always be enough to trigger the alternative branch
|
149 |
+
// where `sizeof(capture) > sizeof(rec->data)`
|
150 |
+
uint64_t zeros[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
151 |
+
};
|
152 |
+
m.def("register_large_capture_with_invalid_arguments", [](py::module_ m) {
|
153 |
+
LargeCapture capture; // VS 2015's MSVC is acting up if we create the array here
|
154 |
+
m.def("should_raise", [capture](int) { return capture.zeros[9] + 33; }, py::kw_only(), py::arg());
|
155 |
+
});
|
156 |
+
m.def("register_with_raising_repr", [](py::module_ m, const py::object &default_value) {
|
157 |
+
m.def(
|
158 |
+
"should_raise",
|
159 |
+
[](int, int, const py::object &) { return 42; },
|
160 |
+
"some docstring",
|
161 |
+
py::arg_v("x", 42),
|
162 |
+
py::arg_v("y", 42, "<the answer>"),
|
163 |
+
py::arg_v("z", default_value));
|
164 |
+
});
|
165 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_constants_and_functions.py
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
m = pytest.importorskip("pybind11_tests.constants_and_functions")
|
5 |
+
|
6 |
+
|
7 |
+
def test_constants():
|
8 |
+
assert m.some_constant == 14
|
9 |
+
|
10 |
+
|
11 |
+
def test_function_overloading():
|
12 |
+
assert m.test_function() == "test_function()"
|
13 |
+
assert m.test_function(7) == "test_function(7)"
|
14 |
+
assert m.test_function(m.MyEnum.EFirstEntry) == "test_function(enum=1)"
|
15 |
+
assert m.test_function(m.MyEnum.ESecondEntry) == "test_function(enum=2)"
|
16 |
+
|
17 |
+
assert m.test_function() == "test_function()"
|
18 |
+
assert m.test_function("abcd") == "test_function(char *)"
|
19 |
+
assert m.test_function(1, 1.0) == "test_function(int, float)"
|
20 |
+
assert m.test_function(1, 1.0) == "test_function(int, float)"
|
21 |
+
assert m.test_function(2.0, 2) == "test_function(float, int)"
|
22 |
+
|
23 |
+
|
24 |
+
def test_bytes():
|
25 |
+
assert m.print_bytes(m.return_bytes()) == "bytes[1 0 2 0]"
|
26 |
+
|
27 |
+
|
28 |
+
def test_exception_specifiers():
|
29 |
+
c = m.C()
|
30 |
+
assert c.m1(2) == 1
|
31 |
+
assert c.m2(3) == 1
|
32 |
+
assert c.m3(5) == 2
|
33 |
+
assert c.m4(7) == 3
|
34 |
+
assert c.m5(10) == 5
|
35 |
+
assert c.m6(14) == 8
|
36 |
+
assert c.m7(20) == 13
|
37 |
+
assert c.m8(29) == 21
|
38 |
+
|
39 |
+
assert m.f1(33) == 34
|
40 |
+
assert m.f2(53) == 55
|
41 |
+
assert m.f3(86) == 89
|
42 |
+
assert m.f4(140) == 144
|
43 |
+
|
44 |
+
|
45 |
+
def test_function_record_leaks():
|
46 |
+
class RaisingRepr:
|
47 |
+
def __repr__(self):
|
48 |
+
raise RuntimeError("Surprise!")
|
49 |
+
|
50 |
+
with pytest.raises(RuntimeError):
|
51 |
+
m.register_large_capture_with_invalid_arguments(m)
|
52 |
+
with pytest.raises(RuntimeError):
|
53 |
+
m.register_with_raising_repr(m, RaisingRepr())
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_copy_move.cpp
ADDED
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_copy_move_policies.cpp -- 'copy' and 'move' return value policies
|
3 |
+
and related tests
|
4 |
+
|
5 |
+
Copyright (c) 2016 Ben North <[email protected]>
|
6 |
+
|
7 |
+
All rights reserved. Use of this source code is governed by a
|
8 |
+
BSD-style license that can be found in the LICENSE file.
|
9 |
+
*/
|
10 |
+
|
11 |
+
#include "pybind11_tests.h"
|
12 |
+
#include "constructor_stats.h"
|
13 |
+
#include <pybind11/stl.h>
|
14 |
+
|
15 |
+
template <typename derived>
|
16 |
+
struct empty {
|
17 |
+
static const derived& get_one() { return instance_; }
|
18 |
+
static derived instance_;
|
19 |
+
};
|
20 |
+
|
21 |
+
struct lacking_copy_ctor : public empty<lacking_copy_ctor> {
|
22 |
+
lacking_copy_ctor() = default;
|
23 |
+
lacking_copy_ctor(const lacking_copy_ctor& other) = delete;
|
24 |
+
};
|
25 |
+
|
26 |
+
template <> lacking_copy_ctor empty<lacking_copy_ctor>::instance_ = {};
|
27 |
+
|
28 |
+
struct lacking_move_ctor : public empty<lacking_move_ctor> {
|
29 |
+
lacking_move_ctor() = default;
|
30 |
+
lacking_move_ctor(const lacking_move_ctor& other) = delete;
|
31 |
+
lacking_move_ctor(lacking_move_ctor&& other) = delete;
|
32 |
+
};
|
33 |
+
|
34 |
+
template <> lacking_move_ctor empty<lacking_move_ctor>::instance_ = {};
|
35 |
+
|
36 |
+
/* Custom type caster move/copy test classes */
|
37 |
+
class MoveOnlyInt {
|
38 |
+
public:
|
39 |
+
MoveOnlyInt() { print_default_created(this); }
|
40 |
+
MoveOnlyInt(int v) : value{v} { print_created(this, value); }
|
41 |
+
MoveOnlyInt(MoveOnlyInt &&m) noexcept {
|
42 |
+
print_move_created(this, m.value);
|
43 |
+
std::swap(value, m.value);
|
44 |
+
}
|
45 |
+
MoveOnlyInt &operator=(MoveOnlyInt &&m) noexcept {
|
46 |
+
print_move_assigned(this, m.value);
|
47 |
+
std::swap(value, m.value);
|
48 |
+
return *this;
|
49 |
+
}
|
50 |
+
MoveOnlyInt(const MoveOnlyInt &) = delete;
|
51 |
+
MoveOnlyInt &operator=(const MoveOnlyInt &) = delete;
|
52 |
+
~MoveOnlyInt() { print_destroyed(this); }
|
53 |
+
|
54 |
+
int value;
|
55 |
+
};
|
56 |
+
class MoveOrCopyInt {
|
57 |
+
public:
|
58 |
+
MoveOrCopyInt() { print_default_created(this); }
|
59 |
+
MoveOrCopyInt(int v) : value{v} { print_created(this, value); }
|
60 |
+
MoveOrCopyInt(MoveOrCopyInt &&m) noexcept {
|
61 |
+
print_move_created(this, m.value);
|
62 |
+
std::swap(value, m.value);
|
63 |
+
}
|
64 |
+
MoveOrCopyInt &operator=(MoveOrCopyInt &&m) noexcept {
|
65 |
+
print_move_assigned(this, m.value);
|
66 |
+
std::swap(value, m.value);
|
67 |
+
return *this;
|
68 |
+
}
|
69 |
+
MoveOrCopyInt(const MoveOrCopyInt &c) { print_copy_created(this, c.value); value = c.value; }
|
70 |
+
MoveOrCopyInt &operator=(const MoveOrCopyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; }
|
71 |
+
~MoveOrCopyInt() { print_destroyed(this); }
|
72 |
+
|
73 |
+
int value;
|
74 |
+
};
|
75 |
+
class CopyOnlyInt {
|
76 |
+
public:
|
77 |
+
CopyOnlyInt() { print_default_created(this); }
|
78 |
+
CopyOnlyInt(int v) : value{v} { print_created(this, value); }
|
79 |
+
CopyOnlyInt(const CopyOnlyInt &c) { print_copy_created(this, c.value); value = c.value; }
|
80 |
+
CopyOnlyInt &operator=(const CopyOnlyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; }
|
81 |
+
~CopyOnlyInt() { print_destroyed(this); }
|
82 |
+
|
83 |
+
int value;
|
84 |
+
};
|
85 |
+
PYBIND11_NAMESPACE_BEGIN(pybind11)
|
86 |
+
PYBIND11_NAMESPACE_BEGIN(detail)
|
87 |
+
template <> struct type_caster<MoveOnlyInt> {
|
88 |
+
PYBIND11_TYPE_CASTER(MoveOnlyInt, _("MoveOnlyInt"));
|
89 |
+
bool load(handle src, bool) { value = MoveOnlyInt(src.cast<int>()); return true; }
|
90 |
+
static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); }
|
91 |
+
};
|
92 |
+
|
93 |
+
template <> struct type_caster<MoveOrCopyInt> {
|
94 |
+
PYBIND11_TYPE_CASTER(MoveOrCopyInt, _("MoveOrCopyInt"));
|
95 |
+
bool load(handle src, bool) { value = MoveOrCopyInt(src.cast<int>()); return true; }
|
96 |
+
static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); }
|
97 |
+
};
|
98 |
+
|
99 |
+
template <> struct type_caster<CopyOnlyInt> {
|
100 |
+
protected:
|
101 |
+
CopyOnlyInt value;
|
102 |
+
public:
|
103 |
+
static constexpr auto name = _("CopyOnlyInt");
|
104 |
+
bool load(handle src, bool) { value = CopyOnlyInt(src.cast<int>()); return true; }
|
105 |
+
static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); }
|
106 |
+
static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) {
|
107 |
+
if (!src) return none().release();
|
108 |
+
return cast(*src, policy, parent);
|
109 |
+
}
|
110 |
+
operator CopyOnlyInt*() { return &value; }
|
111 |
+
operator CopyOnlyInt&() { return value; }
|
112 |
+
template <typename T> using cast_op_type = pybind11::detail::cast_op_type<T>;
|
113 |
+
};
|
114 |
+
PYBIND11_NAMESPACE_END(detail)
|
115 |
+
PYBIND11_NAMESPACE_END(pybind11)
|
116 |
+
|
117 |
+
TEST_SUBMODULE(copy_move_policies, m) {
|
118 |
+
// test_lacking_copy_ctor
|
119 |
+
py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
|
120 |
+
.def_static("get_one", &lacking_copy_ctor::get_one,
|
121 |
+
py::return_value_policy::copy);
|
122 |
+
// test_lacking_move_ctor
|
123 |
+
py::class_<lacking_move_ctor>(m, "lacking_move_ctor")
|
124 |
+
.def_static("get_one", &lacking_move_ctor::get_one,
|
125 |
+
py::return_value_policy::move);
|
126 |
+
|
127 |
+
// test_move_and_copy_casts
|
128 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
129 |
+
m.def("move_and_copy_casts", [](const py::object &o) {
|
130 |
+
int r = 0;
|
131 |
+
r += py::cast<MoveOrCopyInt>(o).value; /* moves */
|
132 |
+
r += py::cast<MoveOnlyInt>(o).value; /* moves */
|
133 |
+
r += py::cast<CopyOnlyInt>(o).value; /* copies */
|
134 |
+
auto m1(py::cast<MoveOrCopyInt>(o)); /* moves */
|
135 |
+
auto m2(py::cast<MoveOnlyInt>(o)); /* moves */
|
136 |
+
auto m3(py::cast<CopyOnlyInt>(o)); /* copies */
|
137 |
+
r += m1.value + m2.value + m3.value;
|
138 |
+
|
139 |
+
return r;
|
140 |
+
});
|
141 |
+
|
142 |
+
// test_move_and_copy_loads
|
143 |
+
m.def("move_only", [](MoveOnlyInt m) { return m.value; });
|
144 |
+
// Changing this breaks the existing test: needs careful review.
|
145 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
146 |
+
m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; });
|
147 |
+
// Changing this breaks the existing test: needs careful review.
|
148 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
149 |
+
m.def("copy_only", [](CopyOnlyInt m) { return m.value; });
|
150 |
+
m.def("move_pair", [](std::pair<MoveOnlyInt, MoveOrCopyInt> p) {
|
151 |
+
return p.first.value + p.second.value;
|
152 |
+
});
|
153 |
+
m.def("move_tuple", [](std::tuple<MoveOnlyInt, MoveOrCopyInt, MoveOnlyInt> t) {
|
154 |
+
return std::get<0>(t).value + std::get<1>(t).value + std::get<2>(t).value;
|
155 |
+
});
|
156 |
+
m.def("copy_tuple", [](std::tuple<CopyOnlyInt, CopyOnlyInt> t) {
|
157 |
+
return std::get<0>(t).value + std::get<1>(t).value;
|
158 |
+
});
|
159 |
+
m.def("move_copy_nested", [](std::pair<MoveOnlyInt, std::pair<std::tuple<MoveOrCopyInt, CopyOnlyInt, std::tuple<MoveOnlyInt>>, MoveOrCopyInt>> x) {
|
160 |
+
return x.first.value + std::get<0>(x.second.first).value + std::get<1>(x.second.first).value +
|
161 |
+
std::get<0>(std::get<2>(x.second.first)).value + x.second.second.value;
|
162 |
+
});
|
163 |
+
m.def("move_and_copy_cstats", []() {
|
164 |
+
ConstructorStats::gc();
|
165 |
+
// Reset counts to 0 so that previous tests don't affect later ones:
|
166 |
+
auto &mc = ConstructorStats::get<MoveOrCopyInt>();
|
167 |
+
mc.move_assignments = mc.move_constructions = mc.copy_assignments = mc.copy_constructions = 0;
|
168 |
+
auto &mo = ConstructorStats::get<MoveOnlyInt>();
|
169 |
+
mo.move_assignments = mo.move_constructions = mo.copy_assignments = mo.copy_constructions = 0;
|
170 |
+
auto &co = ConstructorStats::get<CopyOnlyInt>();
|
171 |
+
co.move_assignments = co.move_constructions = co.copy_assignments = co.copy_constructions = 0;
|
172 |
+
py::dict d;
|
173 |
+
d["MoveOrCopyInt"] = py::cast(mc, py::return_value_policy::reference);
|
174 |
+
d["MoveOnlyInt"] = py::cast(mo, py::return_value_policy::reference);
|
175 |
+
d["CopyOnlyInt"] = py::cast(co, py::return_value_policy::reference);
|
176 |
+
return d;
|
177 |
+
});
|
178 |
+
#ifdef PYBIND11_HAS_OPTIONAL
|
179 |
+
// test_move_and_copy_load_optional
|
180 |
+
m.attr("has_optional") = true;
|
181 |
+
m.def("move_optional", [](std::optional<MoveOnlyInt> o) {
|
182 |
+
return o->value;
|
183 |
+
});
|
184 |
+
m.def("move_or_copy_optional", [](std::optional<MoveOrCopyInt> o) {
|
185 |
+
return o->value;
|
186 |
+
});
|
187 |
+
m.def("copy_optional", [](std::optional<CopyOnlyInt> o) {
|
188 |
+
return o->value;
|
189 |
+
});
|
190 |
+
m.def("move_optional_tuple", [](std::optional<std::tuple<MoveOrCopyInt, MoveOnlyInt, CopyOnlyInt>> x) {
|
191 |
+
return std::get<0>(*x).value + std::get<1>(*x).value + std::get<2>(*x).value;
|
192 |
+
});
|
193 |
+
#else
|
194 |
+
m.attr("has_optional") = false;
|
195 |
+
#endif
|
196 |
+
|
197 |
+
// #70 compilation issue if operator new is not public - simple body added
|
198 |
+
// but not needed on most compilers; MSVC and nvcc don't like a local
|
199 |
+
// struct not having a method defined when declared, since it can not be
|
200 |
+
// added later.
|
201 |
+
struct PrivateOpNew {
|
202 |
+
int value = 1;
|
203 |
+
private:
|
204 |
+
void *operator new(size_t bytes) {
|
205 |
+
void *ptr = std::malloc(bytes);
|
206 |
+
if (ptr)
|
207 |
+
return ptr;
|
208 |
+
throw std::bad_alloc{};
|
209 |
+
}
|
210 |
+
};
|
211 |
+
py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
|
212 |
+
m.def("private_op_new_value", []() { return PrivateOpNew(); });
|
213 |
+
m.def("private_op_new_reference", []() -> const PrivateOpNew & {
|
214 |
+
static PrivateOpNew x{};
|
215 |
+
return x;
|
216 |
+
}, py::return_value_policy::reference);
|
217 |
+
|
218 |
+
// test_move_fallback
|
219 |
+
// #389: rvp::move should fall-through to copy on non-movable objects
|
220 |
+
struct MoveIssue1 {
|
221 |
+
int v;
|
222 |
+
MoveIssue1(int v) : v{v} {}
|
223 |
+
MoveIssue1(const MoveIssue1 &c) = default;
|
224 |
+
MoveIssue1(MoveIssue1 &&) = delete;
|
225 |
+
};
|
226 |
+
py::class_<MoveIssue1>(m, "MoveIssue1").def(py::init<int>()).def_readwrite("value", &MoveIssue1::v);
|
227 |
+
|
228 |
+
struct MoveIssue2 {
|
229 |
+
int v;
|
230 |
+
MoveIssue2(int v) : v{v} {}
|
231 |
+
MoveIssue2(MoveIssue2 &&) = default;
|
232 |
+
};
|
233 |
+
py::class_<MoveIssue2>(m, "MoveIssue2").def(py::init<int>()).def_readwrite("value", &MoveIssue2::v);
|
234 |
+
|
235 |
+
// #2742: Don't expect ownership of raw pointer to `new`ed object to be transferred with `py::return_value_policy::move`
|
236 |
+
m.def("get_moveissue1", [](int i) { return std::unique_ptr<MoveIssue1>(new MoveIssue1(i)); }, py::return_value_policy::move);
|
237 |
+
m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
|
238 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_copy_move.py
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
from pybind11_tests import copy_move_policies as m
|
4 |
+
|
5 |
+
|
6 |
+
def test_lacking_copy_ctor():
|
7 |
+
with pytest.raises(RuntimeError) as excinfo:
|
8 |
+
m.lacking_copy_ctor.get_one()
|
9 |
+
assert "is non-copyable!" in str(excinfo.value)
|
10 |
+
|
11 |
+
|
12 |
+
def test_lacking_move_ctor():
|
13 |
+
with pytest.raises(RuntimeError) as excinfo:
|
14 |
+
m.lacking_move_ctor.get_one()
|
15 |
+
assert "is neither movable nor copyable!" in str(excinfo.value)
|
16 |
+
|
17 |
+
|
18 |
+
def test_move_and_copy_casts():
|
19 |
+
"""Cast some values in C++ via custom type casters and count the number of moves/copies."""
|
20 |
+
|
21 |
+
cstats = m.move_and_copy_cstats()
|
22 |
+
c_m, c_mc, c_c = (
|
23 |
+
cstats["MoveOnlyInt"],
|
24 |
+
cstats["MoveOrCopyInt"],
|
25 |
+
cstats["CopyOnlyInt"],
|
26 |
+
)
|
27 |
+
|
28 |
+
# The type move constructions/assignments below each get incremented: the move assignment comes
|
29 |
+
# from the type_caster load; the move construction happens when extracting that via a cast or
|
30 |
+
# loading into an argument.
|
31 |
+
assert m.move_and_copy_casts(3) == 18
|
32 |
+
assert c_m.copy_assignments + c_m.copy_constructions == 0
|
33 |
+
assert c_m.move_assignments == 2
|
34 |
+
assert c_m.move_constructions >= 2
|
35 |
+
assert c_mc.alive() == 0
|
36 |
+
assert c_mc.copy_assignments + c_mc.copy_constructions == 0
|
37 |
+
assert c_mc.move_assignments == 2
|
38 |
+
assert c_mc.move_constructions >= 2
|
39 |
+
assert c_c.alive() == 0
|
40 |
+
assert c_c.copy_assignments == 2
|
41 |
+
assert c_c.copy_constructions >= 2
|
42 |
+
assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
|
43 |
+
|
44 |
+
|
45 |
+
def test_move_and_copy_loads():
|
46 |
+
"""Call some functions that load arguments via custom type casters and count the number of
|
47 |
+
moves/copies."""
|
48 |
+
|
49 |
+
cstats = m.move_and_copy_cstats()
|
50 |
+
c_m, c_mc, c_c = (
|
51 |
+
cstats["MoveOnlyInt"],
|
52 |
+
cstats["MoveOrCopyInt"],
|
53 |
+
cstats["CopyOnlyInt"],
|
54 |
+
)
|
55 |
+
|
56 |
+
assert m.move_only(10) == 10 # 1 move, c_m
|
57 |
+
assert m.move_or_copy(11) == 11 # 1 move, c_mc
|
58 |
+
assert m.copy_only(12) == 12 # 1 copy, c_c
|
59 |
+
assert m.move_pair((13, 14)) == 27 # 1 c_m move, 1 c_mc move
|
60 |
+
assert m.move_tuple((15, 16, 17)) == 48 # 2 c_m moves, 1 c_mc move
|
61 |
+
assert m.copy_tuple((18, 19)) == 37 # 2 c_c copies
|
62 |
+
# Direct constructions: 2 c_m moves, 2 c_mc moves, 1 c_c copy
|
63 |
+
# Extra moves/copies when moving pairs/tuples: 3 c_m, 3 c_mc, 2 c_c
|
64 |
+
assert m.move_copy_nested((1, ((2, 3, (4,)), 5))) == 15
|
65 |
+
|
66 |
+
assert c_m.copy_assignments + c_m.copy_constructions == 0
|
67 |
+
assert c_m.move_assignments == 6
|
68 |
+
assert c_m.move_constructions == 9
|
69 |
+
assert c_mc.copy_assignments + c_mc.copy_constructions == 0
|
70 |
+
assert c_mc.move_assignments == 5
|
71 |
+
assert c_mc.move_constructions == 8
|
72 |
+
assert c_c.copy_assignments == 4
|
73 |
+
assert c_c.copy_constructions == 6
|
74 |
+
assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
|
75 |
+
|
76 |
+
|
77 |
+
@pytest.mark.skipif(not m.has_optional, reason="no <optional>")
|
78 |
+
def test_move_and_copy_load_optional():
|
79 |
+
"""Tests move/copy loads of std::optional arguments"""
|
80 |
+
|
81 |
+
cstats = m.move_and_copy_cstats()
|
82 |
+
c_m, c_mc, c_c = (
|
83 |
+
cstats["MoveOnlyInt"],
|
84 |
+
cstats["MoveOrCopyInt"],
|
85 |
+
cstats["CopyOnlyInt"],
|
86 |
+
)
|
87 |
+
|
88 |
+
# The extra move/copy constructions below come from the std::optional move (which has to move
|
89 |
+
# its arguments):
|
90 |
+
assert m.move_optional(10) == 10 # c_m: 1 move assign, 2 move construct
|
91 |
+
assert m.move_or_copy_optional(11) == 11 # c_mc: 1 move assign, 2 move construct
|
92 |
+
assert m.copy_optional(12) == 12 # c_c: 1 copy assign, 2 copy construct
|
93 |
+
# 1 move assign + move construct moves each of c_m, c_mc, 1 c_c copy
|
94 |
+
# +1 move/copy construct each from moving the tuple
|
95 |
+
# +1 move/copy construct each from moving the optional (which moves the tuple again)
|
96 |
+
assert m.move_optional_tuple((3, 4, 5)) == 12
|
97 |
+
|
98 |
+
assert c_m.copy_assignments + c_m.copy_constructions == 0
|
99 |
+
assert c_m.move_assignments == 2
|
100 |
+
assert c_m.move_constructions == 5
|
101 |
+
assert c_mc.copy_assignments + c_mc.copy_constructions == 0
|
102 |
+
assert c_mc.move_assignments == 2
|
103 |
+
assert c_mc.move_constructions == 5
|
104 |
+
assert c_c.copy_assignments == 2
|
105 |
+
assert c_c.copy_constructions == 5
|
106 |
+
assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
|
107 |
+
|
108 |
+
|
109 |
+
def test_private_op_new():
|
110 |
+
"""An object with a private `operator new` cannot be returned by value"""
|
111 |
+
|
112 |
+
with pytest.raises(RuntimeError) as excinfo:
|
113 |
+
m.private_op_new_value()
|
114 |
+
assert "is neither movable nor copyable" in str(excinfo.value)
|
115 |
+
|
116 |
+
assert m.private_op_new_reference().value == 1
|
117 |
+
|
118 |
+
|
119 |
+
def test_move_fallback():
|
120 |
+
"""#389: rvp::move should fall-through to copy on non-movable objects"""
|
121 |
+
|
122 |
+
m1 = m.get_moveissue1(1)
|
123 |
+
assert m1.value == 1
|
124 |
+
m2 = m.get_moveissue2(2)
|
125 |
+
assert m2.value == 2
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_custom_type_casters.cpp
ADDED
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_custom_type_casters.cpp -- tests type_caster<T>
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "pybind11_tests.h"
|
11 |
+
#include "constructor_stats.h"
|
12 |
+
|
13 |
+
|
14 |
+
// py::arg/py::arg_v testing: these arguments just record their argument when invoked
|
15 |
+
class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; };
|
16 |
+
class ArgInspector2 { public: std::string arg = "(default arg inspector 2)"; };
|
17 |
+
class ArgAlwaysConverts { };
|
18 |
+
namespace pybind11 { namespace detail {
|
19 |
+
template <> struct type_caster<ArgInspector1> {
|
20 |
+
public:
|
21 |
+
PYBIND11_TYPE_CASTER(ArgInspector1, _("ArgInspector1"));
|
22 |
+
|
23 |
+
bool load(handle src, bool convert) {
|
24 |
+
value.arg = "loading ArgInspector1 argument " +
|
25 |
+
std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. "
|
26 |
+
"Argument value = " + (std::string) str(src);
|
27 |
+
return true;
|
28 |
+
}
|
29 |
+
|
30 |
+
static handle cast(const ArgInspector1 &src, return_value_policy, handle) {
|
31 |
+
return str(src.arg).release();
|
32 |
+
}
|
33 |
+
};
|
34 |
+
template <> struct type_caster<ArgInspector2> {
|
35 |
+
public:
|
36 |
+
PYBIND11_TYPE_CASTER(ArgInspector2, _("ArgInspector2"));
|
37 |
+
|
38 |
+
bool load(handle src, bool convert) {
|
39 |
+
value.arg = "loading ArgInspector2 argument " +
|
40 |
+
std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. "
|
41 |
+
"Argument value = " + (std::string) str(src);
|
42 |
+
return true;
|
43 |
+
}
|
44 |
+
|
45 |
+
static handle cast(const ArgInspector2 &src, return_value_policy, handle) {
|
46 |
+
return str(src.arg).release();
|
47 |
+
}
|
48 |
+
};
|
49 |
+
template <> struct type_caster<ArgAlwaysConverts> {
|
50 |
+
public:
|
51 |
+
PYBIND11_TYPE_CASTER(ArgAlwaysConverts, _("ArgAlwaysConverts"));
|
52 |
+
|
53 |
+
bool load(handle, bool convert) {
|
54 |
+
return convert;
|
55 |
+
}
|
56 |
+
|
57 |
+
static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) {
|
58 |
+
return py::none().release();
|
59 |
+
}
|
60 |
+
};
|
61 |
+
} // namespace detail
|
62 |
+
} // namespace pybind11
|
63 |
+
|
64 |
+
// test_custom_caster_destruction
|
65 |
+
class DestructionTester {
|
66 |
+
public:
|
67 |
+
DestructionTester() { print_default_created(this); }
|
68 |
+
~DestructionTester() { print_destroyed(this); }
|
69 |
+
DestructionTester(const DestructionTester &) { print_copy_created(this); }
|
70 |
+
DestructionTester(DestructionTester &&) noexcept { print_move_created(this); }
|
71 |
+
DestructionTester &operator=(const DestructionTester &) { print_copy_assigned(this); return *this; }
|
72 |
+
DestructionTester &operator=(DestructionTester &&) noexcept {
|
73 |
+
print_move_assigned(this);
|
74 |
+
return *this;
|
75 |
+
}
|
76 |
+
};
|
77 |
+
namespace pybind11 { namespace detail {
|
78 |
+
template <> struct type_caster<DestructionTester> {
|
79 |
+
PYBIND11_TYPE_CASTER(DestructionTester, _("DestructionTester"));
|
80 |
+
bool load(handle, bool) { return true; }
|
81 |
+
|
82 |
+
static handle cast(const DestructionTester &, return_value_policy, handle) {
|
83 |
+
return py::bool_(true).release();
|
84 |
+
}
|
85 |
+
};
|
86 |
+
} // namespace detail
|
87 |
+
} // namespace pybind11
|
88 |
+
|
89 |
+
TEST_SUBMODULE(custom_type_casters, m) {
|
90 |
+
// test_custom_type_casters
|
91 |
+
|
92 |
+
// test_noconvert_args
|
93 |
+
//
|
94 |
+
// Test converting. The ArgAlwaysConverts is just there to make the first no-conversion pass
|
95 |
+
// fail so that our call always ends up happening via the second dispatch (the one that allows
|
96 |
+
// some conversion).
|
97 |
+
class ArgInspector {
|
98 |
+
public:
|
99 |
+
ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; }
|
100 |
+
std::string g(const ArgInspector1 &a,
|
101 |
+
const ArgInspector1 &b,
|
102 |
+
int c,
|
103 |
+
ArgInspector2 *d,
|
104 |
+
ArgAlwaysConverts) {
|
105 |
+
return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg;
|
106 |
+
}
|
107 |
+
static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; }
|
108 |
+
};
|
109 |
+
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
|
110 |
+
py::class_<ArgInspector>(m, "ArgInspector")
|
111 |
+
.def(py::init<>())
|
112 |
+
.def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts())
|
113 |
+
.def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert()=13, "d"_a=ArgInspector2(), py::arg() = ArgAlwaysConverts())
|
114 |
+
.def_static("h", &ArgInspector::h, py::arg{}.noconvert(), py::arg() = ArgAlwaysConverts())
|
115 |
+
;
|
116 |
+
m.def(
|
117 |
+
"arg_inspect_func",
|
118 |
+
[](const ArgInspector2 &a, const ArgInspector1 &b, ArgAlwaysConverts) {
|
119 |
+
return a.arg + "\n" + b.arg;
|
120 |
+
},
|
121 |
+
py::arg{}.noconvert(false),
|
122 |
+
py::arg_v(nullptr, ArgInspector1()).noconvert(true),
|
123 |
+
py::arg() = ArgAlwaysConverts());
|
124 |
+
|
125 |
+
m.def("floats_preferred", [](double f) { return 0.5 * f; }, "f"_a);
|
126 |
+
m.def("floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert());
|
127 |
+
m.def("ints_preferred", [](int i) { return i / 2; }, "i"_a);
|
128 |
+
m.def("ints_only", [](int i) { return i / 2; }, "i"_a.noconvert());
|
129 |
+
|
130 |
+
// test_custom_caster_destruction
|
131 |
+
// Test that `take_ownership` works on types with a custom type caster when given a pointer
|
132 |
+
|
133 |
+
// default policy: don't take ownership:
|
134 |
+
m.def("custom_caster_no_destroy", []() { static auto *dt = new DestructionTester(); return dt; });
|
135 |
+
|
136 |
+
m.def("custom_caster_destroy", []() { return new DestructionTester(); },
|
137 |
+
py::return_value_policy::take_ownership); // Takes ownership: destroy when finished
|
138 |
+
m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); },
|
139 |
+
py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction)
|
140 |
+
m.def("destruction_tester_cstats", &ConstructorStats::get<DestructionTester>, py::return_value_policy::reference);
|
141 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_custom_type_casters.py
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
from pybind11_tests import custom_type_casters as m
|
4 |
+
|
5 |
+
|
6 |
+
def test_noconvert_args(msg):
|
7 |
+
a = m.ArgInspector()
|
8 |
+
assert (
|
9 |
+
msg(a.f("hi"))
|
10 |
+
== """
|
11 |
+
loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
|
12 |
+
"""
|
13 |
+
)
|
14 |
+
assert (
|
15 |
+
msg(a.g("this is a", "this is b"))
|
16 |
+
== """
|
17 |
+
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
|
18 |
+
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
19 |
+
13
|
20 |
+
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
|
21 |
+
""" # noqa: E501 line too long
|
22 |
+
)
|
23 |
+
assert (
|
24 |
+
msg(a.g("this is a", "this is b", 42))
|
25 |
+
== """
|
26 |
+
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
|
27 |
+
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
28 |
+
42
|
29 |
+
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
|
30 |
+
""" # noqa: E501 line too long
|
31 |
+
)
|
32 |
+
assert (
|
33 |
+
msg(a.g("this is a", "this is b", 42, "this is d"))
|
34 |
+
== """
|
35 |
+
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
|
36 |
+
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
37 |
+
42
|
38 |
+
loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d
|
39 |
+
"""
|
40 |
+
)
|
41 |
+
assert (
|
42 |
+
a.h("arg 1")
|
43 |
+
== "loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1"
|
44 |
+
)
|
45 |
+
assert (
|
46 |
+
msg(m.arg_inspect_func("A1", "A2"))
|
47 |
+
== """
|
48 |
+
loading ArgInspector2 argument WITH conversion allowed. Argument value = A1
|
49 |
+
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2
|
50 |
+
"""
|
51 |
+
)
|
52 |
+
|
53 |
+
assert m.floats_preferred(4) == 2.0
|
54 |
+
assert m.floats_only(4.0) == 2.0
|
55 |
+
with pytest.raises(TypeError) as excinfo:
|
56 |
+
m.floats_only(4)
|
57 |
+
assert (
|
58 |
+
msg(excinfo.value)
|
59 |
+
== """
|
60 |
+
floats_only(): incompatible function arguments. The following argument types are supported:
|
61 |
+
1. (f: float) -> float
|
62 |
+
|
63 |
+
Invoked with: 4
|
64 |
+
"""
|
65 |
+
)
|
66 |
+
|
67 |
+
assert m.ints_preferred(4) == 2
|
68 |
+
assert m.ints_preferred(True) == 0
|
69 |
+
with pytest.raises(TypeError) as excinfo:
|
70 |
+
m.ints_preferred(4.0)
|
71 |
+
assert (
|
72 |
+
msg(excinfo.value)
|
73 |
+
== """
|
74 |
+
ints_preferred(): incompatible function arguments. The following argument types are supported:
|
75 |
+
1. (i: int) -> int
|
76 |
+
|
77 |
+
Invoked with: 4.0
|
78 |
+
""" # noqa: E501 line too long
|
79 |
+
)
|
80 |
+
|
81 |
+
assert m.ints_only(4) == 2
|
82 |
+
with pytest.raises(TypeError) as excinfo:
|
83 |
+
m.ints_only(4.0)
|
84 |
+
assert (
|
85 |
+
msg(excinfo.value)
|
86 |
+
== """
|
87 |
+
ints_only(): incompatible function arguments. The following argument types are supported:
|
88 |
+
1. (i: int) -> int
|
89 |
+
|
90 |
+
Invoked with: 4.0
|
91 |
+
"""
|
92 |
+
)
|
93 |
+
|
94 |
+
|
95 |
+
def test_custom_caster_destruction():
|
96 |
+
"""Tests that returning a pointer to a type that gets converted with a custom type caster gets
|
97 |
+
destroyed when the function has py::return_value_policy::take_ownership policy applied."""
|
98 |
+
|
99 |
+
cstats = m.destruction_tester_cstats()
|
100 |
+
# This one *doesn't* have take_ownership: the pointer should be used but not destroyed:
|
101 |
+
z = m.custom_caster_no_destroy()
|
102 |
+
assert cstats.alive() == 1 and cstats.default_constructions == 1
|
103 |
+
assert z
|
104 |
+
|
105 |
+
# take_ownership applied: this constructs a new object, casts it, then destroys it:
|
106 |
+
z = m.custom_caster_destroy()
|
107 |
+
assert z
|
108 |
+
assert cstats.default_constructions == 2
|
109 |
+
|
110 |
+
# Same, but with a const pointer return (which should *not* inhibit destruction):
|
111 |
+
z = m.custom_caster_destroy_const()
|
112 |
+
assert z
|
113 |
+
assert cstats.default_constructions == 3
|
114 |
+
|
115 |
+
# Make sure we still only have the original object (from ..._no_destroy()) alive:
|
116 |
+
assert cstats.alive() == 1
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_docstring_options.cpp
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_docstring_options.cpp -- generation of docstrings and signatures
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "pybind11_tests.h"
|
11 |
+
|
12 |
+
TEST_SUBMODULE(docstring_options, m) {
|
13 |
+
// test_docstring_options
|
14 |
+
{
|
15 |
+
py::options options;
|
16 |
+
options.disable_function_signatures();
|
17 |
+
|
18 |
+
m.def("test_function1", [](int, int) {}, py::arg("a"), py::arg("b"));
|
19 |
+
m.def("test_function2", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
20 |
+
|
21 |
+
m.def("test_overloaded1", [](int) {}, py::arg("i"), "Overload docstring");
|
22 |
+
m.def("test_overloaded1", [](double) {}, py::arg("d"));
|
23 |
+
|
24 |
+
m.def("test_overloaded2", [](int) {}, py::arg("i"), "overload docstring 1");
|
25 |
+
m.def("test_overloaded2", [](double) {}, py::arg("d"), "overload docstring 2");
|
26 |
+
|
27 |
+
m.def("test_overloaded3", [](int) {}, py::arg("i"));
|
28 |
+
m.def("test_overloaded3", [](double) {}, py::arg("d"), "Overload docstr");
|
29 |
+
|
30 |
+
options.enable_function_signatures();
|
31 |
+
|
32 |
+
m.def("test_function3", [](int, int) {}, py::arg("a"), py::arg("b"));
|
33 |
+
m.def("test_function4", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
34 |
+
|
35 |
+
options.disable_function_signatures().disable_user_defined_docstrings();
|
36 |
+
|
37 |
+
m.def("test_function5", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
38 |
+
|
39 |
+
{
|
40 |
+
py::options nested_options;
|
41 |
+
nested_options.enable_user_defined_docstrings();
|
42 |
+
m.def("test_function6", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
m.def("test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
47 |
+
|
48 |
+
{
|
49 |
+
py::options options;
|
50 |
+
options.disable_user_defined_docstrings();
|
51 |
+
options.disable_function_signatures();
|
52 |
+
|
53 |
+
m.def("test_function8", []() {});
|
54 |
+
}
|
55 |
+
|
56 |
+
{
|
57 |
+
py::options options;
|
58 |
+
options.disable_user_defined_docstrings();
|
59 |
+
|
60 |
+
struct DocstringTestFoo {
|
61 |
+
int value;
|
62 |
+
void setValue(int v) { value = v; }
|
63 |
+
int getValue() const { return value; }
|
64 |
+
};
|
65 |
+
py::class_<DocstringTestFoo>(m, "DocstringTestFoo", "This is a class docstring")
|
66 |
+
.def_property("value_prop", &DocstringTestFoo::getValue, &DocstringTestFoo::setValue, "This is a property docstring")
|
67 |
+
;
|
68 |
+
}
|
69 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_docstring_options.py
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
from pybind11_tests import docstring_options as m
|
3 |
+
|
4 |
+
|
5 |
+
def test_docstring_options():
|
6 |
+
# options.disable_function_signatures()
|
7 |
+
assert not m.test_function1.__doc__
|
8 |
+
|
9 |
+
assert m.test_function2.__doc__ == "A custom docstring"
|
10 |
+
|
11 |
+
# docstring specified on just the first overload definition:
|
12 |
+
assert m.test_overloaded1.__doc__ == "Overload docstring"
|
13 |
+
|
14 |
+
# docstring on both overloads:
|
15 |
+
assert m.test_overloaded2.__doc__ == "overload docstring 1\noverload docstring 2"
|
16 |
+
|
17 |
+
# docstring on only second overload:
|
18 |
+
assert m.test_overloaded3.__doc__ == "Overload docstr"
|
19 |
+
|
20 |
+
# options.enable_function_signatures()
|
21 |
+
assert m.test_function3.__doc__.startswith("test_function3(a: int, b: int) -> None")
|
22 |
+
|
23 |
+
assert m.test_function4.__doc__.startswith("test_function4(a: int, b: int) -> None")
|
24 |
+
assert m.test_function4.__doc__.endswith("A custom docstring\n")
|
25 |
+
|
26 |
+
# options.disable_function_signatures()
|
27 |
+
# options.disable_user_defined_docstrings()
|
28 |
+
assert not m.test_function5.__doc__
|
29 |
+
|
30 |
+
# nested options.enable_user_defined_docstrings()
|
31 |
+
assert m.test_function6.__doc__ == "A custom docstring"
|
32 |
+
|
33 |
+
# RAII destructor
|
34 |
+
assert m.test_function7.__doc__.startswith("test_function7(a: int, b: int) -> None")
|
35 |
+
assert m.test_function7.__doc__.endswith("A custom docstring\n")
|
36 |
+
|
37 |
+
# when all options are disabled, no docstring (instead of an empty one) should be generated
|
38 |
+
assert m.test_function8.__doc__ is None
|
39 |
+
|
40 |
+
# Suppression of user-defined docstrings for non-function objects
|
41 |
+
assert not m.DocstringTestFoo.__doc__
|
42 |
+
assert not m.DocstringTestFoo.value_prop.__doc__
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_eigen.cpp
ADDED
@@ -0,0 +1,341 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/eigen.cpp -- automatic conversion of Eigen types
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "pybind11_tests.h"
|
11 |
+
#include "constructor_stats.h"
|
12 |
+
#include <pybind11/eigen.h>
|
13 |
+
#include <pybind11/stl.h>
|
14 |
+
|
15 |
+
#if defined(_MSC_VER)
|
16 |
+
# pragma warning(disable: 4996) // C4996: std::unary_negation is deprecated
|
17 |
+
#endif
|
18 |
+
|
19 |
+
#include <Eigen/Cholesky>
|
20 |
+
|
21 |
+
using MatrixXdR = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
|
22 |
+
|
23 |
+
|
24 |
+
|
25 |
+
// Sets/resets a testing reference matrix to have values of 10*r + c, where r and c are the
|
26 |
+
// (1-based) row/column number.
|
27 |
+
template <typename M> void reset_ref(M &x) {
|
28 |
+
for (int i = 0; i < x.rows(); i++) for (int j = 0; j < x.cols(); j++)
|
29 |
+
x(i, j) = 11 + 10*i + j;
|
30 |
+
}
|
31 |
+
|
32 |
+
// Returns a static, column-major matrix
|
33 |
+
Eigen::MatrixXd &get_cm() {
|
34 |
+
static Eigen::MatrixXd *x;
|
35 |
+
if (!x) {
|
36 |
+
x = new Eigen::MatrixXd(3, 3);
|
37 |
+
reset_ref(*x);
|
38 |
+
}
|
39 |
+
return *x;
|
40 |
+
}
|
41 |
+
// Likewise, but row-major
|
42 |
+
MatrixXdR &get_rm() {
|
43 |
+
static MatrixXdR *x;
|
44 |
+
if (!x) {
|
45 |
+
x = new MatrixXdR(3, 3);
|
46 |
+
reset_ref(*x);
|
47 |
+
}
|
48 |
+
return *x;
|
49 |
+
}
|
50 |
+
// Resets the values of the static matrices returned by get_cm()/get_rm()
|
51 |
+
void reset_refs() {
|
52 |
+
reset_ref(get_cm());
|
53 |
+
reset_ref(get_rm());
|
54 |
+
}
|
55 |
+
|
56 |
+
// Returns element 2,1 from a matrix (used to test copy/nocopy)
|
57 |
+
double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); };
|
58 |
+
|
59 |
+
// Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix
|
60 |
+
// reference is referencing rows/columns correctly).
|
61 |
+
template <typename MatrixArgType> Eigen::MatrixXd adjust_matrix(MatrixArgType m) {
|
62 |
+
Eigen::MatrixXd ret(m);
|
63 |
+
for (int c = 0; c < m.cols(); c++)
|
64 |
+
for (int r = 0; r < m.rows(); r++)
|
65 |
+
ret(r, c) += 10*r + 100*c; // NOLINT(clang-analyzer-core.uninitialized.Assign)
|
66 |
+
return ret;
|
67 |
+
}
|
68 |
+
|
69 |
+
struct CustomOperatorNew {
|
70 |
+
CustomOperatorNew() = default;
|
71 |
+
|
72 |
+
Eigen::Matrix4d a = Eigen::Matrix4d::Zero();
|
73 |
+
Eigen::Matrix4d b = Eigen::Matrix4d::Identity();
|
74 |
+
|
75 |
+
EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
|
76 |
+
};
|
77 |
+
|
78 |
+
TEST_SUBMODULE(eigen, m) {
|
79 |
+
using FixedMatrixR = Eigen::Matrix<float, 5, 6, Eigen::RowMajor>;
|
80 |
+
using FixedMatrixC = Eigen::Matrix<float, 5, 6>;
|
81 |
+
using DenseMatrixR = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
|
82 |
+
using DenseMatrixC = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic>;
|
83 |
+
using FourRowMatrixC = Eigen::Matrix<float, 4, Eigen::Dynamic>;
|
84 |
+
using FourColMatrixC = Eigen::Matrix<float, Eigen::Dynamic, 4>;
|
85 |
+
using FourRowMatrixR = Eigen::Matrix<float, 4, Eigen::Dynamic>;
|
86 |
+
using FourColMatrixR = Eigen::Matrix<float, Eigen::Dynamic, 4>;
|
87 |
+
using SparseMatrixR = Eigen::SparseMatrix<float, Eigen::RowMajor>;
|
88 |
+
using SparseMatrixC = Eigen::SparseMatrix<float>;
|
89 |
+
|
90 |
+
// various tests
|
91 |
+
m.def("double_col", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2.0f * x; });
|
92 |
+
m.def("double_row", [](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2.0f * x; });
|
93 |
+
m.def("double_complex", [](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; });
|
94 |
+
m.def("double_threec", [](py::EigenDRef<Eigen::Vector3f> x) { x *= 2; });
|
95 |
+
m.def("double_threer", [](py::EigenDRef<Eigen::RowVector3f> x) { x *= 2; });
|
96 |
+
m.def("double_mat_cm", [](const Eigen::MatrixXf &x) -> Eigen::MatrixXf { return 2.0f * x; });
|
97 |
+
m.def("double_mat_rm", [](const DenseMatrixR &x) -> DenseMatrixR { return 2.0f * x; });
|
98 |
+
|
99 |
+
// test_eigen_ref_to_python
|
100 |
+
// Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended
|
101 |
+
m.def("cholesky1",
|
102 |
+
[](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
|
103 |
+
m.def("cholesky2", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
|
104 |
+
m.def("cholesky3", [](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
|
105 |
+
m.def("cholesky4", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd {
|
106 |
+
return x.llt().matrixL();
|
107 |
+
});
|
108 |
+
|
109 |
+
// test_eigen_ref_mutators
|
110 |
+
// Mutators: these add some value to the given element using Eigen, but Eigen should be mapping into
|
111 |
+
// the numpy array data and so the result should show up there. There are three versions: one that
|
112 |
+
// works on a contiguous-row matrix (numpy's default), one for a contiguous-column matrix, and one
|
113 |
+
// for any matrix.
|
114 |
+
auto add_rm = [](Eigen::Ref<MatrixXdR> x, int r, int c, double v) { x(r,c) += v; };
|
115 |
+
auto add_cm = [](Eigen::Ref<Eigen::MatrixXd> x, int r, int c, double v) { x(r,c) += v; };
|
116 |
+
|
117 |
+
// Mutators (Eigen maps into numpy variables):
|
118 |
+
m.def("add_rm", add_rm); // Only takes row-contiguous
|
119 |
+
m.def("add_cm", add_cm); // Only takes column-contiguous
|
120 |
+
// Overloaded versions that will accept either row or column contiguous:
|
121 |
+
m.def("add1", add_rm);
|
122 |
+
m.def("add1", add_cm);
|
123 |
+
m.def("add2", add_cm);
|
124 |
+
m.def("add2", add_rm);
|
125 |
+
// This one accepts a matrix of any stride:
|
126 |
+
m.def("add_any", [](py::EigenDRef<Eigen::MatrixXd> x, int r, int c, double v) { x(r,c) += v; });
|
127 |
+
|
128 |
+
// Return mutable references (numpy maps into eigen variables)
|
129 |
+
m.def("get_cm_ref", []() { return Eigen::Ref<Eigen::MatrixXd>(get_cm()); });
|
130 |
+
m.def("get_rm_ref", []() { return Eigen::Ref<MatrixXdR>(get_rm()); });
|
131 |
+
// The same references, but non-mutable (numpy maps into eigen variables, but is !writeable)
|
132 |
+
m.def("get_cm_const_ref", []() { return Eigen::Ref<const Eigen::MatrixXd>(get_cm()); });
|
133 |
+
m.def("get_rm_const_ref", []() { return Eigen::Ref<const MatrixXdR>(get_rm()); });
|
134 |
+
|
135 |
+
m.def("reset_refs", reset_refs); // Restores get_{cm,rm}_ref to original values
|
136 |
+
|
137 |
+
// Increments and returns ref to (same) matrix
|
138 |
+
m.def("incr_matrix", [](Eigen::Ref<Eigen::MatrixXd> m, double v) {
|
139 |
+
m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v);
|
140 |
+
return m;
|
141 |
+
}, py::return_value_policy::reference);
|
142 |
+
|
143 |
+
// Same, but accepts a matrix of any strides
|
144 |
+
m.def("incr_matrix_any", [](py::EigenDRef<Eigen::MatrixXd> m, double v) {
|
145 |
+
m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v);
|
146 |
+
return m;
|
147 |
+
}, py::return_value_policy::reference);
|
148 |
+
|
149 |
+
// Returns an eigen slice of even rows
|
150 |
+
m.def("even_rows", [](py::EigenDRef<Eigen::MatrixXd> m) {
|
151 |
+
return py::EigenDMap<Eigen::MatrixXd>(
|
152 |
+
m.data(), (m.rows() + 1) / 2, m.cols(),
|
153 |
+
py::EigenDStride(m.outerStride(), 2 * m.innerStride()));
|
154 |
+
}, py::return_value_policy::reference);
|
155 |
+
|
156 |
+
// Returns an eigen slice of even columns
|
157 |
+
m.def("even_cols", [](py::EigenDRef<Eigen::MatrixXd> m) {
|
158 |
+
return py::EigenDMap<Eigen::MatrixXd>(
|
159 |
+
m.data(), m.rows(), (m.cols() + 1) / 2,
|
160 |
+
py::EigenDStride(2 * m.outerStride(), m.innerStride()));
|
161 |
+
}, py::return_value_policy::reference);
|
162 |
+
|
163 |
+
// Returns diagonals: a vector-like object with an inner stride != 1
|
164 |
+
m.def("diagonal", [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal(); });
|
165 |
+
m.def("diagonal_1", [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal<1>(); });
|
166 |
+
m.def("diagonal_n", [](const Eigen::Ref<const Eigen::MatrixXd> &x, int index) { return x.diagonal(index); });
|
167 |
+
|
168 |
+
// Return a block of a matrix (gives non-standard strides)
|
169 |
+
m.def("block", [](const Eigen::Ref<const Eigen::MatrixXd> &x, int start_row, int start_col, int block_rows, int block_cols) {
|
170 |
+
return x.block(start_row, start_col, block_rows, block_cols);
|
171 |
+
});
|
172 |
+
|
173 |
+
// test_eigen_return_references, test_eigen_keepalive
|
174 |
+
// return value referencing/copying tests:
|
175 |
+
class ReturnTester {
|
176 |
+
Eigen::MatrixXd mat = create();
|
177 |
+
public:
|
178 |
+
ReturnTester() { print_created(this); }
|
179 |
+
~ReturnTester() { print_destroyed(this); }
|
180 |
+
static Eigen::MatrixXd create() { return Eigen::MatrixXd::Ones(10, 10); }
|
181 |
+
static const Eigen::MatrixXd createConst() { return Eigen::MatrixXd::Ones(10, 10); }
|
182 |
+
Eigen::MatrixXd &get() { return mat; }
|
183 |
+
Eigen::MatrixXd *getPtr() { return &mat; }
|
184 |
+
const Eigen::MatrixXd &view() { return mat; }
|
185 |
+
const Eigen::MatrixXd *viewPtr() { return &mat; }
|
186 |
+
Eigen::Ref<Eigen::MatrixXd> ref() { return mat; }
|
187 |
+
Eigen::Ref<const Eigen::MatrixXd> refConst() { return mat; }
|
188 |
+
Eigen::Block<Eigen::MatrixXd> block(int r, int c, int nrow, int ncol) { return mat.block(r, c, nrow, ncol); }
|
189 |
+
Eigen::Block<const Eigen::MatrixXd> blockConst(int r, int c, int nrow, int ncol) const { return mat.block(r, c, nrow, ncol); }
|
190 |
+
py::EigenDMap<Eigen::Matrix2d> corners() { return py::EigenDMap<Eigen::Matrix2d>(mat.data(),
|
191 |
+
py::EigenDStride(mat.outerStride() * (mat.outerSize()-1), mat.innerStride() * (mat.innerSize()-1))); }
|
192 |
+
py::EigenDMap<const Eigen::Matrix2d> cornersConst() const { return py::EigenDMap<const Eigen::Matrix2d>(mat.data(),
|
193 |
+
py::EigenDStride(mat.outerStride() * (mat.outerSize()-1), mat.innerStride() * (mat.innerSize()-1))); }
|
194 |
+
};
|
195 |
+
using rvp = py::return_value_policy;
|
196 |
+
py::class_<ReturnTester>(m, "ReturnTester")
|
197 |
+
.def(py::init<>())
|
198 |
+
.def_static("create", &ReturnTester::create)
|
199 |
+
.def_static("create_const", &ReturnTester::createConst)
|
200 |
+
.def("get", &ReturnTester::get, rvp::reference_internal)
|
201 |
+
.def("get_ptr", &ReturnTester::getPtr, rvp::reference_internal)
|
202 |
+
.def("view", &ReturnTester::view, rvp::reference_internal)
|
203 |
+
.def("view_ptr", &ReturnTester::view, rvp::reference_internal)
|
204 |
+
.def("copy_get", &ReturnTester::get) // Default rvp: copy
|
205 |
+
.def("copy_view", &ReturnTester::view) // "
|
206 |
+
.def("ref", &ReturnTester::ref) // Default for Ref is to reference
|
207 |
+
.def("ref_const", &ReturnTester::refConst) // Likewise, but const
|
208 |
+
.def("ref_safe", &ReturnTester::ref, rvp::reference_internal)
|
209 |
+
.def("ref_const_safe", &ReturnTester::refConst, rvp::reference_internal)
|
210 |
+
.def("copy_ref", &ReturnTester::ref, rvp::copy)
|
211 |
+
.def("copy_ref_const", &ReturnTester::refConst, rvp::copy)
|
212 |
+
.def("block", &ReturnTester::block)
|
213 |
+
.def("block_safe", &ReturnTester::block, rvp::reference_internal)
|
214 |
+
.def("block_const", &ReturnTester::blockConst, rvp::reference_internal)
|
215 |
+
.def("copy_block", &ReturnTester::block, rvp::copy)
|
216 |
+
.def("corners", &ReturnTester::corners, rvp::reference_internal)
|
217 |
+
.def("corners_const", &ReturnTester::cornersConst, rvp::reference_internal)
|
218 |
+
;
|
219 |
+
|
220 |
+
// test_special_matrix_objects
|
221 |
+
// Returns a DiagonalMatrix with diagonal (1,2,3,...)
|
222 |
+
m.def("incr_diag", [](int k) {
|
223 |
+
Eigen::DiagonalMatrix<int, Eigen::Dynamic> m(k);
|
224 |
+
for (int i = 0; i < k; i++) m.diagonal()[i] = i+1;
|
225 |
+
return m;
|
226 |
+
});
|
227 |
+
|
228 |
+
// Returns a SelfAdjointView referencing the lower triangle of m
|
229 |
+
m.def("symmetric_lower", [](const Eigen::MatrixXi &m) {
|
230 |
+
return m.selfadjointView<Eigen::Lower>();
|
231 |
+
});
|
232 |
+
// Returns a SelfAdjointView referencing the lower triangle of m
|
233 |
+
m.def("symmetric_upper", [](const Eigen::MatrixXi &m) {
|
234 |
+
return m.selfadjointView<Eigen::Upper>();
|
235 |
+
});
|
236 |
+
|
237 |
+
// Test matrix for various functions below.
|
238 |
+
Eigen::MatrixXf mat(5, 6);
|
239 |
+
mat << 0, 3, 0, 0, 0, 11,
|
240 |
+
22, 0, 0, 0, 17, 11,
|
241 |
+
7, 5, 0, 1, 0, 11,
|
242 |
+
0, 0, 0, 0, 0, 11,
|
243 |
+
0, 0, 14, 0, 8, 11;
|
244 |
+
|
245 |
+
// test_fixed, and various other tests
|
246 |
+
m.def("fixed_r", [mat]() -> FixedMatrixR { return FixedMatrixR(mat); });
|
247 |
+
m.def("fixed_r_const", [mat]() -> const FixedMatrixR { return FixedMatrixR(mat); });
|
248 |
+
m.def("fixed_c", [mat]() -> FixedMatrixC { return FixedMatrixC(mat); });
|
249 |
+
m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; });
|
250 |
+
m.def("fixed_copy_c", [](const FixedMatrixC &m) -> FixedMatrixC { return m; });
|
251 |
+
// test_mutator_descriptors
|
252 |
+
m.def("fixed_mutator_r", [](const Eigen::Ref<FixedMatrixR> &) {});
|
253 |
+
m.def("fixed_mutator_c", [](const Eigen::Ref<FixedMatrixC> &) {});
|
254 |
+
m.def("fixed_mutator_a", [](const py::EigenDRef<FixedMatrixC> &) {});
|
255 |
+
// test_dense
|
256 |
+
m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); });
|
257 |
+
m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); });
|
258 |
+
m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; });
|
259 |
+
m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; });
|
260 |
+
// test_sparse, test_sparse_signature
|
261 |
+
m.def("sparse_r", [mat]() -> SparseMatrixR {
|
262 |
+
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
263 |
+
return Eigen::SparseView<Eigen::MatrixXf>(mat);
|
264 |
+
});
|
265 |
+
m.def("sparse_c", [mat]() -> SparseMatrixC { return Eigen::SparseView<Eigen::MatrixXf>(mat); });
|
266 |
+
m.def("sparse_copy_r", [](const SparseMatrixR &m) -> SparseMatrixR { return m; });
|
267 |
+
m.def("sparse_copy_c", [](const SparseMatrixC &m) -> SparseMatrixC { return m; });
|
268 |
+
// test_partially_fixed
|
269 |
+
m.def("partial_copy_four_rm_r", [](const FourRowMatrixR &m) -> FourRowMatrixR { return m; });
|
270 |
+
m.def("partial_copy_four_rm_c", [](const FourColMatrixR &m) -> FourColMatrixR { return m; });
|
271 |
+
m.def("partial_copy_four_cm_r", [](const FourRowMatrixC &m) -> FourRowMatrixC { return m; });
|
272 |
+
m.def("partial_copy_four_cm_c", [](const FourColMatrixC &m) -> FourColMatrixC { return m; });
|
273 |
+
|
274 |
+
// test_cpp_casting
|
275 |
+
// Test that we can cast a numpy object to a Eigen::MatrixXd explicitly
|
276 |
+
m.def("cpp_copy", [](py::handle m) { return m.cast<Eigen::MatrixXd>()(1, 0); });
|
277 |
+
m.def("cpp_ref_c", [](py::handle m) { return m.cast<Eigen::Ref<Eigen::MatrixXd>>()(1, 0); });
|
278 |
+
m.def("cpp_ref_r", [](py::handle m) { return m.cast<Eigen::Ref<MatrixXdR>>()(1, 0); });
|
279 |
+
m.def("cpp_ref_any", [](py::handle m) { return m.cast<py::EigenDRef<Eigen::MatrixXd>>()(1, 0); });
|
280 |
+
|
281 |
+
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
|
282 |
+
|
283 |
+
// test_nocopy_wrapper
|
284 |
+
// Test that we can prevent copying into an argument that would normally copy: First a version
|
285 |
+
// that would allow copying (if types or strides don't match) for comparison:
|
286 |
+
m.def("get_elem", &get_elem);
|
287 |
+
// Now this alternative that calls the tells pybind to fail rather than copy:
|
288 |
+
m.def(
|
289 |
+
"get_elem_nocopy",
|
290 |
+
[](const Eigen::Ref<const Eigen::MatrixXd> &m) -> double { return get_elem(m); },
|
291 |
+
py::arg{}.noconvert());
|
292 |
+
// Also test a row-major-only no-copy const ref:
|
293 |
+
m.def("get_elem_rm_nocopy", [](Eigen::Ref<const Eigen::Matrix<long, -1, -1, Eigen::RowMajor>> &m) -> long { return m(2, 1); },
|
294 |
+
py::arg{}.noconvert());
|
295 |
+
|
296 |
+
// test_issue738
|
297 |
+
// Issue #738: 1xN or Nx1 2D matrices were neither accepted nor properly copied with an
|
298 |
+
// incompatible stride value on the length-1 dimension--but that should be allowed (without
|
299 |
+
// requiring a copy!) because the stride value can be safely ignored on a size-1 dimension.
|
300 |
+
m.def("iss738_f1", &adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>, py::arg{}.noconvert());
|
301 |
+
m.def("iss738_f2", &adjust_matrix<const Eigen::Ref<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>> &>, py::arg{}.noconvert());
|
302 |
+
|
303 |
+
// test_issue1105
|
304 |
+
// Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense
|
305 |
+
// eigen Vector or RowVector, the argument would fail to load because the numpy copy would
|
306 |
+
// fail: numpy won't broadcast a Nx1 into a 1-dimensional vector.
|
307 |
+
m.def("iss1105_col", [](const Eigen::VectorXd &) { return true; });
|
308 |
+
m.def("iss1105_row", [](const Eigen::RowVectorXd &) { return true; });
|
309 |
+
|
310 |
+
// test_named_arguments
|
311 |
+
// Make sure named arguments are working properly:
|
312 |
+
m.def(
|
313 |
+
"matrix_multiply",
|
314 |
+
[](const py::EigenDRef<const Eigen::MatrixXd> &A,
|
315 |
+
const py::EigenDRef<const Eigen::MatrixXd> &B) -> Eigen::MatrixXd {
|
316 |
+
if (A.cols() != B.rows())
|
317 |
+
throw std::domain_error("Nonconformable matrices!");
|
318 |
+
return A * B;
|
319 |
+
},
|
320 |
+
py::arg("A"),
|
321 |
+
py::arg("B"));
|
322 |
+
|
323 |
+
// test_custom_operator_new
|
324 |
+
py::class_<CustomOperatorNew>(m, "CustomOperatorNew")
|
325 |
+
.def(py::init<>())
|
326 |
+
.def_readonly("a", &CustomOperatorNew::a)
|
327 |
+
.def_readonly("b", &CustomOperatorNew::b);
|
328 |
+
|
329 |
+
// test_eigen_ref_life_support
|
330 |
+
// In case of a failure (the caster's temp array does not live long enough), creating
|
331 |
+
// a new array (np.ones(10)) increases the chances that the temp array will be garbage
|
332 |
+
// collected and/or that its memory will be overridden with different values.
|
333 |
+
m.def("get_elem_direct", [](const Eigen::Ref<const Eigen::VectorXd> &v) {
|
334 |
+
py::module_::import("numpy").attr("ones")(10);
|
335 |
+
return v(5);
|
336 |
+
});
|
337 |
+
m.def("get_elem_indirect", [](std::vector<Eigen::Ref<const Eigen::VectorXd>> v) {
|
338 |
+
py::module_::import("numpy").attr("ones")(10);
|
339 |
+
return v[0](5);
|
340 |
+
});
|
341 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_eigen.py
ADDED
@@ -0,0 +1,770 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
from pybind11_tests import ConstructorStats
|
4 |
+
|
5 |
+
np = pytest.importorskip("numpy")
|
6 |
+
m = pytest.importorskip("pybind11_tests.eigen")
|
7 |
+
|
8 |
+
|
9 |
+
ref = np.array(
|
10 |
+
[
|
11 |
+
[0.0, 3, 0, 0, 0, 11],
|
12 |
+
[22, 0, 0, 0, 17, 11],
|
13 |
+
[7, 5, 0, 1, 0, 11],
|
14 |
+
[0, 0, 0, 0, 0, 11],
|
15 |
+
[0, 0, 14, 0, 8, 11],
|
16 |
+
]
|
17 |
+
)
|
18 |
+
|
19 |
+
|
20 |
+
def assert_equal_ref(mat):
|
21 |
+
np.testing.assert_array_equal(mat, ref)
|
22 |
+
|
23 |
+
|
24 |
+
def assert_sparse_equal_ref(sparse_mat):
|
25 |
+
assert_equal_ref(sparse_mat.toarray())
|
26 |
+
|
27 |
+
|
28 |
+
def test_fixed():
|
29 |
+
assert_equal_ref(m.fixed_c())
|
30 |
+
assert_equal_ref(m.fixed_r())
|
31 |
+
assert_equal_ref(m.fixed_copy_r(m.fixed_r()))
|
32 |
+
assert_equal_ref(m.fixed_copy_c(m.fixed_c()))
|
33 |
+
assert_equal_ref(m.fixed_copy_r(m.fixed_c()))
|
34 |
+
assert_equal_ref(m.fixed_copy_c(m.fixed_r()))
|
35 |
+
|
36 |
+
|
37 |
+
def test_dense():
|
38 |
+
assert_equal_ref(m.dense_r())
|
39 |
+
assert_equal_ref(m.dense_c())
|
40 |
+
assert_equal_ref(m.dense_copy_r(m.dense_r()))
|
41 |
+
assert_equal_ref(m.dense_copy_c(m.dense_c()))
|
42 |
+
assert_equal_ref(m.dense_copy_r(m.dense_c()))
|
43 |
+
assert_equal_ref(m.dense_copy_c(m.dense_r()))
|
44 |
+
|
45 |
+
|
46 |
+
def test_partially_fixed():
|
47 |
+
ref2 = np.array([[0.0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]])
|
48 |
+
np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2), ref2)
|
49 |
+
np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2), ref2)
|
50 |
+
np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, 1]), ref2[:, [1]])
|
51 |
+
np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2[0, :]), ref2[[0], :])
|
52 |
+
np.testing.assert_array_equal(
|
53 |
+
m.partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)]
|
54 |
+
)
|
55 |
+
np.testing.assert_array_equal(
|
56 |
+
m.partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]
|
57 |
+
)
|
58 |
+
|
59 |
+
np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2), ref2)
|
60 |
+
np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2), ref2)
|
61 |
+
np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, 1]), ref2[:, [1]])
|
62 |
+
np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2[0, :]), ref2[[0], :])
|
63 |
+
np.testing.assert_array_equal(
|
64 |
+
m.partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)]
|
65 |
+
)
|
66 |
+
np.testing.assert_array_equal(
|
67 |
+
m.partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]
|
68 |
+
)
|
69 |
+
|
70 |
+
# TypeError should be raise for a shape mismatch
|
71 |
+
functions = [
|
72 |
+
m.partial_copy_four_rm_r,
|
73 |
+
m.partial_copy_four_rm_c,
|
74 |
+
m.partial_copy_four_cm_r,
|
75 |
+
m.partial_copy_four_cm_c,
|
76 |
+
]
|
77 |
+
matrix_with_wrong_shape = [[1, 2], [3, 4]]
|
78 |
+
for f in functions:
|
79 |
+
with pytest.raises(TypeError) as excinfo:
|
80 |
+
f(matrix_with_wrong_shape)
|
81 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
82 |
+
|
83 |
+
|
84 |
+
def test_mutator_descriptors():
|
85 |
+
zr = np.arange(30, dtype="float32").reshape(5, 6) # row-major
|
86 |
+
zc = zr.reshape(6, 5).transpose() # column-major
|
87 |
+
|
88 |
+
m.fixed_mutator_r(zr)
|
89 |
+
m.fixed_mutator_c(zc)
|
90 |
+
m.fixed_mutator_a(zr)
|
91 |
+
m.fixed_mutator_a(zc)
|
92 |
+
with pytest.raises(TypeError) as excinfo:
|
93 |
+
m.fixed_mutator_r(zc)
|
94 |
+
assert (
|
95 |
+
"(arg0: numpy.ndarray[numpy.float32[5, 6],"
|
96 |
+
" flags.writeable, flags.c_contiguous]) -> None" in str(excinfo.value)
|
97 |
+
)
|
98 |
+
with pytest.raises(TypeError) as excinfo:
|
99 |
+
m.fixed_mutator_c(zr)
|
100 |
+
assert (
|
101 |
+
"(arg0: numpy.ndarray[numpy.float32[5, 6],"
|
102 |
+
" flags.writeable, flags.f_contiguous]) -> None" in str(excinfo.value)
|
103 |
+
)
|
104 |
+
with pytest.raises(TypeError) as excinfo:
|
105 |
+
m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype="float32"))
|
106 |
+
assert "(arg0: numpy.ndarray[numpy.float32[5, 6], flags.writeable]) -> None" in str(
|
107 |
+
excinfo.value
|
108 |
+
)
|
109 |
+
zr.flags.writeable = False
|
110 |
+
with pytest.raises(TypeError):
|
111 |
+
m.fixed_mutator_r(zr)
|
112 |
+
with pytest.raises(TypeError):
|
113 |
+
m.fixed_mutator_a(zr)
|
114 |
+
|
115 |
+
|
116 |
+
def test_cpp_casting():
|
117 |
+
assert m.cpp_copy(m.fixed_r()) == 22.0
|
118 |
+
assert m.cpp_copy(m.fixed_c()) == 22.0
|
119 |
+
z = np.array([[5.0, 6], [7, 8]])
|
120 |
+
assert m.cpp_copy(z) == 7.0
|
121 |
+
assert m.cpp_copy(m.get_cm_ref()) == 21.0
|
122 |
+
assert m.cpp_copy(m.get_rm_ref()) == 21.0
|
123 |
+
assert m.cpp_ref_c(m.get_cm_ref()) == 21.0
|
124 |
+
assert m.cpp_ref_r(m.get_rm_ref()) == 21.0
|
125 |
+
with pytest.raises(RuntimeError) as excinfo:
|
126 |
+
# Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles
|
127 |
+
m.cpp_ref_any(m.fixed_c())
|
128 |
+
assert "Unable to cast Python instance" in str(excinfo.value)
|
129 |
+
with pytest.raises(RuntimeError) as excinfo:
|
130 |
+
# Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles
|
131 |
+
m.cpp_ref_any(m.fixed_r())
|
132 |
+
assert "Unable to cast Python instance" in str(excinfo.value)
|
133 |
+
assert m.cpp_ref_any(m.ReturnTester.create()) == 1.0
|
134 |
+
|
135 |
+
assert m.cpp_ref_any(m.get_cm_ref()) == 21.0
|
136 |
+
assert m.cpp_ref_any(m.get_cm_ref()) == 21.0
|
137 |
+
|
138 |
+
|
139 |
+
def test_pass_readonly_array():
|
140 |
+
z = np.full((5, 6), 42.0)
|
141 |
+
z.flags.writeable = False
|
142 |
+
np.testing.assert_array_equal(z, m.fixed_copy_r(z))
|
143 |
+
np.testing.assert_array_equal(m.fixed_r_const(), m.fixed_r())
|
144 |
+
assert not m.fixed_r_const().flags.writeable
|
145 |
+
np.testing.assert_array_equal(m.fixed_copy_r(m.fixed_r_const()), m.fixed_r_const())
|
146 |
+
|
147 |
+
|
148 |
+
def test_nonunit_stride_from_python():
|
149 |
+
counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
|
150 |
+
second_row = counting_mat[1, :]
|
151 |
+
second_col = counting_mat[:, 1]
|
152 |
+
np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row)
|
153 |
+
np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row)
|
154 |
+
np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row)
|
155 |
+
np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col)
|
156 |
+
np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col)
|
157 |
+
np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col)
|
158 |
+
|
159 |
+
counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
|
160 |
+
slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
|
161 |
+
for ref_mat in slices:
|
162 |
+
np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)
|
163 |
+
np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)
|
164 |
+
|
165 |
+
# Mutator:
|
166 |
+
m.double_threer(second_row)
|
167 |
+
m.double_threec(second_col)
|
168 |
+
np.testing.assert_array_equal(counting_mat, [[0.0, 2, 2], [6, 16, 10], [6, 14, 8]])
|
169 |
+
|
170 |
+
|
171 |
+
def test_negative_stride_from_python(msg):
|
172 |
+
"""Eigen doesn't support (as of yet) negative strides. When a function takes an Eigen matrix by
|
173 |
+
copy or const reference, we can pass a numpy array that has negative strides. Otherwise, an
|
174 |
+
exception will be thrown as Eigen will not be able to map the numpy array."""
|
175 |
+
|
176 |
+
counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
|
177 |
+
counting_mat = counting_mat[::-1, ::-1]
|
178 |
+
second_row = counting_mat[1, :]
|
179 |
+
second_col = counting_mat[:, 1]
|
180 |
+
np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row)
|
181 |
+
np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row)
|
182 |
+
np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row)
|
183 |
+
np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col)
|
184 |
+
np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col)
|
185 |
+
np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col)
|
186 |
+
|
187 |
+
counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
|
188 |
+
counting_3d = counting_3d[::-1, ::-1, ::-1]
|
189 |
+
slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
|
190 |
+
for ref_mat in slices:
|
191 |
+
np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)
|
192 |
+
np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)
|
193 |
+
|
194 |
+
# Mutator:
|
195 |
+
with pytest.raises(TypeError) as excinfo:
|
196 |
+
m.double_threer(second_row)
|
197 |
+
assert (
|
198 |
+
msg(excinfo.value)
|
199 |
+
== """
|
200 |
+
double_threer(): incompatible function arguments. The following argument types are supported:
|
201 |
+
1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None
|
202 |
+
|
203 |
+
Invoked with: """ # noqa: E501 line too long
|
204 |
+
+ repr(np.array([5.0, 4.0, 3.0], dtype="float32"))
|
205 |
+
)
|
206 |
+
|
207 |
+
with pytest.raises(TypeError) as excinfo:
|
208 |
+
m.double_threec(second_col)
|
209 |
+
assert (
|
210 |
+
msg(excinfo.value)
|
211 |
+
== """
|
212 |
+
double_threec(): incompatible function arguments. The following argument types are supported:
|
213 |
+
1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None
|
214 |
+
|
215 |
+
Invoked with: """ # noqa: E501 line too long
|
216 |
+
+ repr(np.array([7.0, 4.0, 1.0], dtype="float32"))
|
217 |
+
)
|
218 |
+
|
219 |
+
|
220 |
+
def test_nonunit_stride_to_python():
|
221 |
+
assert np.all(m.diagonal(ref) == ref.diagonal())
|
222 |
+
assert np.all(m.diagonal_1(ref) == ref.diagonal(1))
|
223 |
+
for i in range(-5, 7):
|
224 |
+
assert np.all(
|
225 |
+
m.diagonal_n(ref, i) == ref.diagonal(i)
|
226 |
+
), "m.diagonal_n({})".format(i)
|
227 |
+
|
228 |
+
assert np.all(m.block(ref, 2, 1, 3, 3) == ref[2:5, 1:4])
|
229 |
+
assert np.all(m.block(ref, 1, 4, 4, 2) == ref[1:, 4:])
|
230 |
+
assert np.all(m.block(ref, 1, 4, 3, 2) == ref[1:4, 4:])
|
231 |
+
|
232 |
+
|
233 |
+
def test_eigen_ref_to_python():
|
234 |
+
chols = [m.cholesky1, m.cholesky2, m.cholesky3, m.cholesky4]
|
235 |
+
for i, chol in enumerate(chols, start=1):
|
236 |
+
mymat = chol(np.array([[1.0, 2, 4], [2, 13, 23], [4, 23, 77]]))
|
237 |
+
assert np.all(
|
238 |
+
mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])
|
239 |
+
), "cholesky{}".format(i)
|
240 |
+
|
241 |
+
|
242 |
+
def assign_both(a1, a2, r, c, v):
|
243 |
+
a1[r, c] = v
|
244 |
+
a2[r, c] = v
|
245 |
+
|
246 |
+
|
247 |
+
def array_copy_but_one(a, r, c, v):
|
248 |
+
z = np.array(a, copy=True)
|
249 |
+
z[r, c] = v
|
250 |
+
return z
|
251 |
+
|
252 |
+
|
253 |
+
def test_eigen_return_references():
|
254 |
+
"""Tests various ways of returning references and non-referencing copies"""
|
255 |
+
|
256 |
+
master = np.ones((10, 10))
|
257 |
+
a = m.ReturnTester()
|
258 |
+
a_get1 = a.get()
|
259 |
+
assert not a_get1.flags.owndata and a_get1.flags.writeable
|
260 |
+
assign_both(a_get1, master, 3, 3, 5)
|
261 |
+
a_get2 = a.get_ptr()
|
262 |
+
assert not a_get2.flags.owndata and a_get2.flags.writeable
|
263 |
+
assign_both(a_get1, master, 2, 3, 6)
|
264 |
+
|
265 |
+
a_view1 = a.view()
|
266 |
+
assert not a_view1.flags.owndata and not a_view1.flags.writeable
|
267 |
+
with pytest.raises(ValueError):
|
268 |
+
a_view1[2, 3] = 4
|
269 |
+
a_view2 = a.view_ptr()
|
270 |
+
assert not a_view2.flags.owndata and not a_view2.flags.writeable
|
271 |
+
with pytest.raises(ValueError):
|
272 |
+
a_view2[2, 3] = 4
|
273 |
+
|
274 |
+
a_copy1 = a.copy_get()
|
275 |
+
assert a_copy1.flags.owndata and a_copy1.flags.writeable
|
276 |
+
np.testing.assert_array_equal(a_copy1, master)
|
277 |
+
a_copy1[7, 7] = -44 # Shouldn't affect anything else
|
278 |
+
c1want = array_copy_but_one(master, 7, 7, -44)
|
279 |
+
a_copy2 = a.copy_view()
|
280 |
+
assert a_copy2.flags.owndata and a_copy2.flags.writeable
|
281 |
+
np.testing.assert_array_equal(a_copy2, master)
|
282 |
+
a_copy2[4, 4] = -22 # Shouldn't affect anything else
|
283 |
+
c2want = array_copy_but_one(master, 4, 4, -22)
|
284 |
+
|
285 |
+
a_ref1 = a.ref()
|
286 |
+
assert not a_ref1.flags.owndata and a_ref1.flags.writeable
|
287 |
+
assign_both(a_ref1, master, 1, 1, 15)
|
288 |
+
a_ref2 = a.ref_const()
|
289 |
+
assert not a_ref2.flags.owndata and not a_ref2.flags.writeable
|
290 |
+
with pytest.raises(ValueError):
|
291 |
+
a_ref2[5, 5] = 33
|
292 |
+
a_ref3 = a.ref_safe()
|
293 |
+
assert not a_ref3.flags.owndata and a_ref3.flags.writeable
|
294 |
+
assign_both(a_ref3, master, 0, 7, 99)
|
295 |
+
a_ref4 = a.ref_const_safe()
|
296 |
+
assert not a_ref4.flags.owndata and not a_ref4.flags.writeable
|
297 |
+
with pytest.raises(ValueError):
|
298 |
+
a_ref4[7, 0] = 987654321
|
299 |
+
|
300 |
+
a_copy3 = a.copy_ref()
|
301 |
+
assert a_copy3.flags.owndata and a_copy3.flags.writeable
|
302 |
+
np.testing.assert_array_equal(a_copy3, master)
|
303 |
+
a_copy3[8, 1] = 11
|
304 |
+
c3want = array_copy_but_one(master, 8, 1, 11)
|
305 |
+
a_copy4 = a.copy_ref_const()
|
306 |
+
assert a_copy4.flags.owndata and a_copy4.flags.writeable
|
307 |
+
np.testing.assert_array_equal(a_copy4, master)
|
308 |
+
a_copy4[8, 4] = 88
|
309 |
+
c4want = array_copy_but_one(master, 8, 4, 88)
|
310 |
+
|
311 |
+
a_block1 = a.block(3, 3, 2, 2)
|
312 |
+
assert not a_block1.flags.owndata and a_block1.flags.writeable
|
313 |
+
a_block1[0, 0] = 55
|
314 |
+
master[3, 3] = 55
|
315 |
+
a_block2 = a.block_safe(2, 2, 3, 2)
|
316 |
+
assert not a_block2.flags.owndata and a_block2.flags.writeable
|
317 |
+
a_block2[2, 1] = -123
|
318 |
+
master[4, 3] = -123
|
319 |
+
a_block3 = a.block_const(6, 7, 4, 3)
|
320 |
+
assert not a_block3.flags.owndata and not a_block3.flags.writeable
|
321 |
+
with pytest.raises(ValueError):
|
322 |
+
a_block3[2, 2] = -44444
|
323 |
+
|
324 |
+
a_copy5 = a.copy_block(2, 2, 2, 3)
|
325 |
+
assert a_copy5.flags.owndata and a_copy5.flags.writeable
|
326 |
+
np.testing.assert_array_equal(a_copy5, master[2:4, 2:5])
|
327 |
+
a_copy5[1, 1] = 777
|
328 |
+
c5want = array_copy_but_one(master[2:4, 2:5], 1, 1, 777)
|
329 |
+
|
330 |
+
a_corn1 = a.corners()
|
331 |
+
assert not a_corn1.flags.owndata and a_corn1.flags.writeable
|
332 |
+
a_corn1 *= 50
|
333 |
+
a_corn1[1, 1] = 999
|
334 |
+
master[0, 0] = 50
|
335 |
+
master[0, 9] = 50
|
336 |
+
master[9, 0] = 50
|
337 |
+
master[9, 9] = 999
|
338 |
+
a_corn2 = a.corners_const()
|
339 |
+
assert not a_corn2.flags.owndata and not a_corn2.flags.writeable
|
340 |
+
with pytest.raises(ValueError):
|
341 |
+
a_corn2[1, 0] = 51
|
342 |
+
|
343 |
+
# All of the changes made all the way along should be visible everywhere
|
344 |
+
# now (except for the copies, of course)
|
345 |
+
np.testing.assert_array_equal(a_get1, master)
|
346 |
+
np.testing.assert_array_equal(a_get2, master)
|
347 |
+
np.testing.assert_array_equal(a_view1, master)
|
348 |
+
np.testing.assert_array_equal(a_view2, master)
|
349 |
+
np.testing.assert_array_equal(a_ref1, master)
|
350 |
+
np.testing.assert_array_equal(a_ref2, master)
|
351 |
+
np.testing.assert_array_equal(a_ref3, master)
|
352 |
+
np.testing.assert_array_equal(a_ref4, master)
|
353 |
+
np.testing.assert_array_equal(a_block1, master[3:5, 3:5])
|
354 |
+
np.testing.assert_array_equal(a_block2, master[2:5, 2:4])
|
355 |
+
np.testing.assert_array_equal(a_block3, master[6:10, 7:10])
|
356 |
+
np.testing.assert_array_equal(
|
357 |
+
a_corn1, master[0 :: master.shape[0] - 1, 0 :: master.shape[1] - 1]
|
358 |
+
)
|
359 |
+
np.testing.assert_array_equal(
|
360 |
+
a_corn2, master[0 :: master.shape[0] - 1, 0 :: master.shape[1] - 1]
|
361 |
+
)
|
362 |
+
|
363 |
+
np.testing.assert_array_equal(a_copy1, c1want)
|
364 |
+
np.testing.assert_array_equal(a_copy2, c2want)
|
365 |
+
np.testing.assert_array_equal(a_copy3, c3want)
|
366 |
+
np.testing.assert_array_equal(a_copy4, c4want)
|
367 |
+
np.testing.assert_array_equal(a_copy5, c5want)
|
368 |
+
|
369 |
+
|
370 |
+
def assert_keeps_alive(cl, method, *args):
|
371 |
+
cstats = ConstructorStats.get(cl)
|
372 |
+
start_with = cstats.alive()
|
373 |
+
a = cl()
|
374 |
+
assert cstats.alive() == start_with + 1
|
375 |
+
z = method(a, *args)
|
376 |
+
assert cstats.alive() == start_with + 1
|
377 |
+
del a
|
378 |
+
# Here's the keep alive in action:
|
379 |
+
assert cstats.alive() == start_with + 1
|
380 |
+
del z
|
381 |
+
# Keep alive should have expired:
|
382 |
+
assert cstats.alive() == start_with
|
383 |
+
|
384 |
+
|
385 |
+
def test_eigen_keepalive():
|
386 |
+
a = m.ReturnTester()
|
387 |
+
cstats = ConstructorStats.get(m.ReturnTester)
|
388 |
+
assert cstats.alive() == 1
|
389 |
+
unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)]
|
390 |
+
copies = [
|
391 |
+
a.copy_get(),
|
392 |
+
a.copy_view(),
|
393 |
+
a.copy_ref(),
|
394 |
+
a.copy_ref_const(),
|
395 |
+
a.copy_block(4, 3, 2, 1),
|
396 |
+
]
|
397 |
+
del a
|
398 |
+
assert cstats.alive() == 0
|
399 |
+
del unsafe
|
400 |
+
del copies
|
401 |
+
|
402 |
+
for meth in [
|
403 |
+
m.ReturnTester.get,
|
404 |
+
m.ReturnTester.get_ptr,
|
405 |
+
m.ReturnTester.view,
|
406 |
+
m.ReturnTester.view_ptr,
|
407 |
+
m.ReturnTester.ref_safe,
|
408 |
+
m.ReturnTester.ref_const_safe,
|
409 |
+
m.ReturnTester.corners,
|
410 |
+
m.ReturnTester.corners_const,
|
411 |
+
]:
|
412 |
+
assert_keeps_alive(m.ReturnTester, meth)
|
413 |
+
|
414 |
+
for meth in [m.ReturnTester.block_safe, m.ReturnTester.block_const]:
|
415 |
+
assert_keeps_alive(m.ReturnTester, meth, 4, 3, 2, 1)
|
416 |
+
|
417 |
+
|
418 |
+
def test_eigen_ref_mutators():
|
419 |
+
"""Tests Eigen's ability to mutate numpy values"""
|
420 |
+
|
421 |
+
orig = np.array([[1.0, 2, 3], [4, 5, 6], [7, 8, 9]])
|
422 |
+
zr = np.array(orig)
|
423 |
+
zc = np.array(orig, order="F")
|
424 |
+
m.add_rm(zr, 1, 0, 100)
|
425 |
+
assert np.all(zr == np.array([[1.0, 2, 3], [104, 5, 6], [7, 8, 9]]))
|
426 |
+
m.add_cm(zc, 1, 0, 200)
|
427 |
+
assert np.all(zc == np.array([[1.0, 2, 3], [204, 5, 6], [7, 8, 9]]))
|
428 |
+
|
429 |
+
m.add_any(zr, 1, 0, 20)
|
430 |
+
assert np.all(zr == np.array([[1.0, 2, 3], [124, 5, 6], [7, 8, 9]]))
|
431 |
+
m.add_any(zc, 1, 0, 10)
|
432 |
+
assert np.all(zc == np.array([[1.0, 2, 3], [214, 5, 6], [7, 8, 9]]))
|
433 |
+
|
434 |
+
# Can't reference a col-major array with a row-major Ref, and vice versa:
|
435 |
+
with pytest.raises(TypeError):
|
436 |
+
m.add_rm(zc, 1, 0, 1)
|
437 |
+
with pytest.raises(TypeError):
|
438 |
+
m.add_cm(zr, 1, 0, 1)
|
439 |
+
|
440 |
+
# Overloads:
|
441 |
+
m.add1(zr, 1, 0, -100)
|
442 |
+
m.add2(zr, 1, 0, -20)
|
443 |
+
assert np.all(zr == orig)
|
444 |
+
m.add1(zc, 1, 0, -200)
|
445 |
+
m.add2(zc, 1, 0, -10)
|
446 |
+
assert np.all(zc == orig)
|
447 |
+
|
448 |
+
# a non-contiguous slice (this won't work on either the row- or
|
449 |
+
# column-contiguous refs, but should work for the any)
|
450 |
+
cornersr = zr[0::2, 0::2]
|
451 |
+
cornersc = zc[0::2, 0::2]
|
452 |
+
|
453 |
+
assert np.all(cornersr == np.array([[1.0, 3], [7, 9]]))
|
454 |
+
assert np.all(cornersc == np.array([[1.0, 3], [7, 9]]))
|
455 |
+
|
456 |
+
with pytest.raises(TypeError):
|
457 |
+
m.add_rm(cornersr, 0, 1, 25)
|
458 |
+
with pytest.raises(TypeError):
|
459 |
+
m.add_cm(cornersr, 0, 1, 25)
|
460 |
+
with pytest.raises(TypeError):
|
461 |
+
m.add_rm(cornersc, 0, 1, 25)
|
462 |
+
with pytest.raises(TypeError):
|
463 |
+
m.add_cm(cornersc, 0, 1, 25)
|
464 |
+
m.add_any(cornersr, 0, 1, 25)
|
465 |
+
m.add_any(cornersc, 0, 1, 44)
|
466 |
+
assert np.all(zr == np.array([[1.0, 2, 28], [4, 5, 6], [7, 8, 9]]))
|
467 |
+
assert np.all(zc == np.array([[1.0, 2, 47], [4, 5, 6], [7, 8, 9]]))
|
468 |
+
|
469 |
+
# You shouldn't be allowed to pass a non-writeable array to a mutating Eigen method:
|
470 |
+
zro = zr[0:4, 0:4]
|
471 |
+
zro.flags.writeable = False
|
472 |
+
with pytest.raises(TypeError):
|
473 |
+
m.add_rm(zro, 0, 0, 0)
|
474 |
+
with pytest.raises(TypeError):
|
475 |
+
m.add_any(zro, 0, 0, 0)
|
476 |
+
with pytest.raises(TypeError):
|
477 |
+
m.add1(zro, 0, 0, 0)
|
478 |
+
with pytest.raises(TypeError):
|
479 |
+
m.add2(zro, 0, 0, 0)
|
480 |
+
|
481 |
+
# integer array shouldn't be passable to a double-matrix-accepting mutating func:
|
482 |
+
zi = np.array([[1, 2], [3, 4]])
|
483 |
+
with pytest.raises(TypeError):
|
484 |
+
m.add_rm(zi)
|
485 |
+
|
486 |
+
|
487 |
+
def test_numpy_ref_mutators():
|
488 |
+
"""Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)"""
|
489 |
+
|
490 |
+
m.reset_refs() # In case another test already changed it
|
491 |
+
|
492 |
+
zc = m.get_cm_ref()
|
493 |
+
zcro = m.get_cm_const_ref()
|
494 |
+
zr = m.get_rm_ref()
|
495 |
+
zrro = m.get_rm_const_ref()
|
496 |
+
|
497 |
+
assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4
|
498 |
+
|
499 |
+
assert not zc.flags.owndata and zc.flags.writeable
|
500 |
+
assert not zr.flags.owndata and zr.flags.writeable
|
501 |
+
assert not zcro.flags.owndata and not zcro.flags.writeable
|
502 |
+
assert not zrro.flags.owndata and not zrro.flags.writeable
|
503 |
+
|
504 |
+
zc[1, 2] = 99
|
505 |
+
expect = np.array([[11.0, 12, 13], [21, 22, 99], [31, 32, 33]])
|
506 |
+
# We should have just changed zc, of course, but also zcro and the original eigen matrix
|
507 |
+
assert np.all(zc == expect)
|
508 |
+
assert np.all(zcro == expect)
|
509 |
+
assert np.all(m.get_cm_ref() == expect)
|
510 |
+
|
511 |
+
zr[1, 2] = 99
|
512 |
+
assert np.all(zr == expect)
|
513 |
+
assert np.all(zrro == expect)
|
514 |
+
assert np.all(m.get_rm_ref() == expect)
|
515 |
+
|
516 |
+
# Make sure the readonly ones are numpy-readonly:
|
517 |
+
with pytest.raises(ValueError):
|
518 |
+
zcro[1, 2] = 6
|
519 |
+
with pytest.raises(ValueError):
|
520 |
+
zrro[1, 2] = 6
|
521 |
+
|
522 |
+
# We should be able to explicitly copy like this (and since we're copying,
|
523 |
+
# the const should drop away)
|
524 |
+
y1 = np.array(m.get_cm_const_ref())
|
525 |
+
|
526 |
+
assert y1.flags.owndata and y1.flags.writeable
|
527 |
+
# We should get copies of the eigen data, which was modified above:
|
528 |
+
assert y1[1, 2] == 99
|
529 |
+
y1[1, 2] += 12
|
530 |
+
assert y1[1, 2] == 111
|
531 |
+
assert zc[1, 2] == 99 # Make sure we aren't referencing the original
|
532 |
+
|
533 |
+
|
534 |
+
def test_both_ref_mutators():
|
535 |
+
"""Tests a complex chain of nested eigen/numpy references"""
|
536 |
+
|
537 |
+
m.reset_refs() # In case another test already changed it
|
538 |
+
|
539 |
+
z = m.get_cm_ref() # numpy -> eigen
|
540 |
+
z[0, 2] -= 3
|
541 |
+
z2 = m.incr_matrix(z, 1) # numpy -> eigen -> numpy -> eigen
|
542 |
+
z2[1, 1] += 6
|
543 |
+
z3 = m.incr_matrix(z, 2) # (numpy -> eigen)^3
|
544 |
+
z3[2, 2] += -5
|
545 |
+
z4 = m.incr_matrix(z, 3) # (numpy -> eigen)^4
|
546 |
+
z4[1, 1] -= 1
|
547 |
+
z5 = m.incr_matrix(z, 4) # (numpy -> eigen)^5
|
548 |
+
z5[0, 0] = 0
|
549 |
+
assert np.all(z == z2)
|
550 |
+
assert np.all(z == z3)
|
551 |
+
assert np.all(z == z4)
|
552 |
+
assert np.all(z == z5)
|
553 |
+
expect = np.array([[0.0, 22, 20], [31, 37, 33], [41, 42, 38]])
|
554 |
+
assert np.all(z == expect)
|
555 |
+
|
556 |
+
y = np.array(range(100), dtype="float64").reshape(10, 10)
|
557 |
+
y2 = m.incr_matrix_any(y, 10) # np -> eigen -> np
|
558 |
+
y3 = m.incr_matrix_any(
|
559 |
+
y2[0::2, 0::2], -33
|
560 |
+
) # np -> eigen -> np slice -> np -> eigen -> np
|
561 |
+
y4 = m.even_rows(y3) # numpy -> eigen slice -> (... y3)
|
562 |
+
y5 = m.even_cols(y4) # numpy -> eigen slice -> (... y4)
|
563 |
+
y6 = m.incr_matrix_any(y5, 1000) # numpy -> eigen -> (... y5)
|
564 |
+
|
565 |
+
# Apply same mutations using just numpy:
|
566 |
+
yexpect = np.array(range(100), dtype="float64").reshape(10, 10)
|
567 |
+
yexpect += 10
|
568 |
+
yexpect[0::2, 0::2] -= 33
|
569 |
+
yexpect[0::4, 0::4] += 1000
|
570 |
+
assert np.all(y6 == yexpect[0::4, 0::4])
|
571 |
+
assert np.all(y5 == yexpect[0::4, 0::4])
|
572 |
+
assert np.all(y4 == yexpect[0::4, 0::2])
|
573 |
+
assert np.all(y3 == yexpect[0::2, 0::2])
|
574 |
+
assert np.all(y2 == yexpect)
|
575 |
+
assert np.all(y == yexpect)
|
576 |
+
|
577 |
+
|
578 |
+
def test_nocopy_wrapper():
|
579 |
+
# get_elem requires a column-contiguous matrix reference, but should be
|
580 |
+
# callable with other types of matrix (via copying):
|
581 |
+
int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order="F")
|
582 |
+
dbl_matrix_colmajor = np.array(
|
583 |
+
int_matrix_colmajor, dtype="double", order="F", copy=True
|
584 |
+
)
|
585 |
+
int_matrix_rowmajor = np.array(int_matrix_colmajor, order="C", copy=True)
|
586 |
+
dbl_matrix_rowmajor = np.array(
|
587 |
+
int_matrix_rowmajor, dtype="double", order="C", copy=True
|
588 |
+
)
|
589 |
+
|
590 |
+
# All should be callable via get_elem:
|
591 |
+
assert m.get_elem(int_matrix_colmajor) == 8
|
592 |
+
assert m.get_elem(dbl_matrix_colmajor) == 8
|
593 |
+
assert m.get_elem(int_matrix_rowmajor) == 8
|
594 |
+
assert m.get_elem(dbl_matrix_rowmajor) == 8
|
595 |
+
|
596 |
+
# All but the second should fail with m.get_elem_nocopy:
|
597 |
+
with pytest.raises(TypeError) as excinfo:
|
598 |
+
m.get_elem_nocopy(int_matrix_colmajor)
|
599 |
+
assert "get_elem_nocopy(): incompatible function arguments." in str(
|
600 |
+
excinfo.value
|
601 |
+
) and ", flags.f_contiguous" in str(excinfo.value)
|
602 |
+
assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8
|
603 |
+
with pytest.raises(TypeError) as excinfo:
|
604 |
+
m.get_elem_nocopy(int_matrix_rowmajor)
|
605 |
+
assert "get_elem_nocopy(): incompatible function arguments." in str(
|
606 |
+
excinfo.value
|
607 |
+
) and ", flags.f_contiguous" in str(excinfo.value)
|
608 |
+
with pytest.raises(TypeError) as excinfo:
|
609 |
+
m.get_elem_nocopy(dbl_matrix_rowmajor)
|
610 |
+
assert "get_elem_nocopy(): incompatible function arguments." in str(
|
611 |
+
excinfo.value
|
612 |
+
) and ", flags.f_contiguous" in str(excinfo.value)
|
613 |
+
|
614 |
+
# For the row-major test, we take a long matrix in row-major, so only the third is allowed:
|
615 |
+
with pytest.raises(TypeError) as excinfo:
|
616 |
+
m.get_elem_rm_nocopy(int_matrix_colmajor)
|
617 |
+
assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
|
618 |
+
excinfo.value
|
619 |
+
) and ", flags.c_contiguous" in str(excinfo.value)
|
620 |
+
with pytest.raises(TypeError) as excinfo:
|
621 |
+
m.get_elem_rm_nocopy(dbl_matrix_colmajor)
|
622 |
+
assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
|
623 |
+
excinfo.value
|
624 |
+
) and ", flags.c_contiguous" in str(excinfo.value)
|
625 |
+
assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8
|
626 |
+
with pytest.raises(TypeError) as excinfo:
|
627 |
+
m.get_elem_rm_nocopy(dbl_matrix_rowmajor)
|
628 |
+
assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
|
629 |
+
excinfo.value
|
630 |
+
) and ", flags.c_contiguous" in str(excinfo.value)
|
631 |
+
|
632 |
+
|
633 |
+
def test_eigen_ref_life_support():
|
634 |
+
"""Ensure the lifetime of temporary arrays created by the `Ref` caster
|
635 |
+
|
636 |
+
The `Ref` caster sometimes creates a copy which needs to stay alive. This needs to
|
637 |
+
happen both for directs casts (just the array) or indirectly (e.g. list of arrays).
|
638 |
+
"""
|
639 |
+
|
640 |
+
a = np.full(shape=10, fill_value=8, dtype=np.int8)
|
641 |
+
assert m.get_elem_direct(a) == 8
|
642 |
+
|
643 |
+
list_of_a = [a]
|
644 |
+
assert m.get_elem_indirect(list_of_a) == 8
|
645 |
+
|
646 |
+
|
647 |
+
def test_special_matrix_objects():
|
648 |
+
assert np.all(m.incr_diag(7) == np.diag([1.0, 2, 3, 4, 5, 6, 7]))
|
649 |
+
|
650 |
+
asymm = np.array([[1.0, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
|
651 |
+
symm_lower = np.array(asymm)
|
652 |
+
symm_upper = np.array(asymm)
|
653 |
+
for i in range(4):
|
654 |
+
for j in range(i + 1, 4):
|
655 |
+
symm_lower[i, j] = symm_lower[j, i]
|
656 |
+
symm_upper[j, i] = symm_upper[i, j]
|
657 |
+
|
658 |
+
assert np.all(m.symmetric_lower(asymm) == symm_lower)
|
659 |
+
assert np.all(m.symmetric_upper(asymm) == symm_upper)
|
660 |
+
|
661 |
+
|
662 |
+
def test_dense_signature(doc):
|
663 |
+
assert (
|
664 |
+
doc(m.double_col)
|
665 |
+
== """
|
666 |
+
double_col(arg0: numpy.ndarray[numpy.float32[m, 1]]) -> numpy.ndarray[numpy.float32[m, 1]]
|
667 |
+
"""
|
668 |
+
)
|
669 |
+
assert (
|
670 |
+
doc(m.double_row)
|
671 |
+
== """
|
672 |
+
double_row(arg0: numpy.ndarray[numpy.float32[1, n]]) -> numpy.ndarray[numpy.float32[1, n]]
|
673 |
+
"""
|
674 |
+
)
|
675 |
+
assert doc(m.double_complex) == (
|
676 |
+
"""
|
677 |
+
double_complex(arg0: numpy.ndarray[numpy.complex64[m, 1]])"""
|
678 |
+
""" -> numpy.ndarray[numpy.complex64[m, 1]]
|
679 |
+
"""
|
680 |
+
)
|
681 |
+
assert doc(m.double_mat_rm) == (
|
682 |
+
"""
|
683 |
+
double_mat_rm(arg0: numpy.ndarray[numpy.float32[m, n]])"""
|
684 |
+
""" -> numpy.ndarray[numpy.float32[m, n]]
|
685 |
+
"""
|
686 |
+
)
|
687 |
+
|
688 |
+
|
689 |
+
def test_named_arguments():
|
690 |
+
a = np.array([[1.0, 2], [3, 4], [5, 6]])
|
691 |
+
b = np.ones((2, 1))
|
692 |
+
|
693 |
+
assert np.all(m.matrix_multiply(a, b) == np.array([[3.0], [7], [11]]))
|
694 |
+
assert np.all(m.matrix_multiply(A=a, B=b) == np.array([[3.0], [7], [11]]))
|
695 |
+
assert np.all(m.matrix_multiply(B=b, A=a) == np.array([[3.0], [7], [11]]))
|
696 |
+
|
697 |
+
with pytest.raises(ValueError) as excinfo:
|
698 |
+
m.matrix_multiply(b, a)
|
699 |
+
assert str(excinfo.value) == "Nonconformable matrices!"
|
700 |
+
|
701 |
+
with pytest.raises(ValueError) as excinfo:
|
702 |
+
m.matrix_multiply(A=b, B=a)
|
703 |
+
assert str(excinfo.value) == "Nonconformable matrices!"
|
704 |
+
|
705 |
+
with pytest.raises(ValueError) as excinfo:
|
706 |
+
m.matrix_multiply(B=a, A=b)
|
707 |
+
assert str(excinfo.value) == "Nonconformable matrices!"
|
708 |
+
|
709 |
+
|
710 |
+
def test_sparse():
|
711 |
+
pytest.importorskip("scipy")
|
712 |
+
assert_sparse_equal_ref(m.sparse_r())
|
713 |
+
assert_sparse_equal_ref(m.sparse_c())
|
714 |
+
assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_r()))
|
715 |
+
assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_c()))
|
716 |
+
assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_c()))
|
717 |
+
assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_r()))
|
718 |
+
|
719 |
+
|
720 |
+
def test_sparse_signature(doc):
|
721 |
+
pytest.importorskip("scipy")
|
722 |
+
assert (
|
723 |
+
doc(m.sparse_copy_r)
|
724 |
+
== """
|
725 |
+
sparse_copy_r(arg0: scipy.sparse.csr_matrix[numpy.float32]) -> scipy.sparse.csr_matrix[numpy.float32]
|
726 |
+
""" # noqa: E501 line too long
|
727 |
+
)
|
728 |
+
assert (
|
729 |
+
doc(m.sparse_copy_c)
|
730 |
+
== """
|
731 |
+
sparse_copy_c(arg0: scipy.sparse.csc_matrix[numpy.float32]) -> scipy.sparse.csc_matrix[numpy.float32]
|
732 |
+
""" # noqa: E501 line too long
|
733 |
+
)
|
734 |
+
|
735 |
+
|
736 |
+
def test_issue738():
|
737 |
+
"""Ignore strides on a length-1 dimension (even if they would be incompatible length > 1)"""
|
738 |
+
assert np.all(m.iss738_f1(np.array([[1.0, 2, 3]])) == np.array([[1.0, 102, 203]]))
|
739 |
+
assert np.all(
|
740 |
+
m.iss738_f1(np.array([[1.0], [2], [3]])) == np.array([[1.0], [12], [23]])
|
741 |
+
)
|
742 |
+
|
743 |
+
assert np.all(m.iss738_f2(np.array([[1.0, 2, 3]])) == np.array([[1.0, 102, 203]]))
|
744 |
+
assert np.all(
|
745 |
+
m.iss738_f2(np.array([[1.0], [2], [3]])) == np.array([[1.0], [12], [23]])
|
746 |
+
)
|
747 |
+
|
748 |
+
|
749 |
+
def test_issue1105():
|
750 |
+
"""Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen
|
751 |
+
compile-time row vectors or column vector"""
|
752 |
+
assert m.iss1105_row(np.ones((1, 7)))
|
753 |
+
assert m.iss1105_col(np.ones((7, 1)))
|
754 |
+
|
755 |
+
# These should still fail (incompatible dimensions):
|
756 |
+
with pytest.raises(TypeError) as excinfo:
|
757 |
+
m.iss1105_row(np.ones((7, 1)))
|
758 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
759 |
+
with pytest.raises(TypeError) as excinfo:
|
760 |
+
m.iss1105_col(np.ones((1, 7)))
|
761 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
762 |
+
|
763 |
+
|
764 |
+
def test_custom_operator_new():
|
765 |
+
"""Using Eigen types as member variables requires a class-specific
|
766 |
+
operator new with proper alignment"""
|
767 |
+
|
768 |
+
o = m.CustomOperatorNew()
|
769 |
+
np.testing.assert_allclose(o.a, 0.0)
|
770 |
+
np.testing.assert_allclose(o.b.diagonal(), 1.0)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_embed/CMakeLists.txt
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
possibly_uninitialized(PYTHON_MODULE_EXTENSION Python_INTERPRETER_ID)
|
2 |
+
|
3 |
+
if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy")
|
4 |
+
message(STATUS "Skipping embed test on PyPy")
|
5 |
+
add_custom_target(cpptest) # Dummy target on PyPy. Embedding is not supported.
|
6 |
+
set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}")
|
7 |
+
return()
|
8 |
+
endif()
|
9 |
+
|
10 |
+
find_package(Catch 2.13.2)
|
11 |
+
|
12 |
+
if(CATCH_FOUND)
|
13 |
+
message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}")
|
14 |
+
else()
|
15 |
+
message(STATUS "Catch not detected. Interpreter tests will be skipped. Install Catch headers"
|
16 |
+
" manually or use `cmake -DDOWNLOAD_CATCH=ON` to fetch them automatically.")
|
17 |
+
return()
|
18 |
+
endif()
|
19 |
+
|
20 |
+
find_package(Threads REQUIRED)
|
21 |
+
|
22 |
+
add_executable(test_embed catch.cpp test_interpreter.cpp)
|
23 |
+
pybind11_enable_warnings(test_embed)
|
24 |
+
|
25 |
+
target_link_libraries(test_embed PRIVATE pybind11::embed Catch2::Catch2 Threads::Threads)
|
26 |
+
|
27 |
+
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
|
28 |
+
file(COPY test_interpreter.py DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
29 |
+
endif()
|
30 |
+
|
31 |
+
add_custom_target(
|
32 |
+
cpptest
|
33 |
+
COMMAND "$<TARGET_FILE:test_embed>"
|
34 |
+
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
35 |
+
|
36 |
+
pybind11_add_module(external_module THIN_LTO external_module.cpp)
|
37 |
+
set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
38 |
+
"${CMAKE_CURRENT_BINARY_DIR}")
|
39 |
+
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
40 |
+
string(TOUPPER ${config} config)
|
41 |
+
set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config}
|
42 |
+
"${CMAKE_CURRENT_BINARY_DIR}")
|
43 |
+
endforeach()
|
44 |
+
add_dependencies(cpptest external_module)
|
45 |
+
|
46 |
+
add_dependencies(check cpptest)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_embed/catch.cpp
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// The Catch implementation is compiled here. This is a standalone
|
2 |
+
// translation unit to avoid recompiling it for every test change.
|
3 |
+
|
4 |
+
#include <pybind11/embed.h>
|
5 |
+
|
6 |
+
#ifdef _MSC_VER
|
7 |
+
// Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to catch
|
8 |
+
// 2.0.1; this should be fixed in the next catch release after 2.0.1).
|
9 |
+
# pragma warning(disable: 4996)
|
10 |
+
#endif
|
11 |
+
|
12 |
+
#define CATCH_CONFIG_RUNNER
|
13 |
+
#include <catch.hpp>
|
14 |
+
|
15 |
+
namespace py = pybind11;
|
16 |
+
|
17 |
+
int main(int argc, char *argv[]) {
|
18 |
+
py::scoped_interpreter guard{};
|
19 |
+
auto result = Catch::Session().run(argc, argv);
|
20 |
+
|
21 |
+
return result < 0xff ? result : 0xff;
|
22 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_embed/external_module.cpp
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <pybind11/pybind11.h>
|
2 |
+
|
3 |
+
namespace py = pybind11;
|
4 |
+
|
5 |
+
/* Simple test module/test class to check that the referenced internals data of external pybind11
|
6 |
+
* modules aren't preserved over a finalize/initialize.
|
7 |
+
*/
|
8 |
+
|
9 |
+
PYBIND11_MODULE(external_module, m) {
|
10 |
+
class A {
|
11 |
+
public:
|
12 |
+
A(int value) : v{value} {};
|
13 |
+
int v;
|
14 |
+
};
|
15 |
+
|
16 |
+
py::class_<A>(m, "A")
|
17 |
+
.def(py::init<int>())
|
18 |
+
.def_readwrite("value", &A::v);
|
19 |
+
|
20 |
+
m.def("internals_at", []() {
|
21 |
+
return reinterpret_cast<uintptr_t>(&py::detail::get_internals());
|
22 |
+
});
|
23 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_embed/test_interpreter.cpp
ADDED
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <pybind11/embed.h>
|
2 |
+
|
3 |
+
#ifdef _MSC_VER
|
4 |
+
// Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to catch
|
5 |
+
// 2.0.1; this should be fixed in the next catch release after 2.0.1).
|
6 |
+
# pragma warning(disable: 4996)
|
7 |
+
#endif
|
8 |
+
|
9 |
+
#include <catch.hpp>
|
10 |
+
|
11 |
+
#include <fstream>
|
12 |
+
#include <functional>
|
13 |
+
#include <thread>
|
14 |
+
#include <utility>
|
15 |
+
|
16 |
+
namespace py = pybind11;
|
17 |
+
using namespace py::literals;
|
18 |
+
|
19 |
+
class Widget {
|
20 |
+
public:
|
21 |
+
Widget(std::string message) : message(std::move(message)) {}
|
22 |
+
virtual ~Widget() = default;
|
23 |
+
|
24 |
+
std::string the_message() const { return message; }
|
25 |
+
virtual int the_answer() const = 0;
|
26 |
+
|
27 |
+
private:
|
28 |
+
std::string message;
|
29 |
+
};
|
30 |
+
|
31 |
+
class PyWidget final : public Widget {
|
32 |
+
using Widget::Widget;
|
33 |
+
|
34 |
+
int the_answer() const override { PYBIND11_OVERRIDE_PURE(int, Widget, the_answer); }
|
35 |
+
};
|
36 |
+
|
37 |
+
PYBIND11_EMBEDDED_MODULE(widget_module, m) {
|
38 |
+
py::class_<Widget, PyWidget>(m, "Widget")
|
39 |
+
.def(py::init<std::string>())
|
40 |
+
.def_property_readonly("the_message", &Widget::the_message);
|
41 |
+
|
42 |
+
m.def("add", [](int i, int j) { return i + j; });
|
43 |
+
}
|
44 |
+
|
45 |
+
PYBIND11_EMBEDDED_MODULE(throw_exception, ) {
|
46 |
+
throw std::runtime_error("C++ Error");
|
47 |
+
}
|
48 |
+
|
49 |
+
PYBIND11_EMBEDDED_MODULE(throw_error_already_set, ) {
|
50 |
+
auto d = py::dict();
|
51 |
+
d["missing"].cast<py::object>();
|
52 |
+
}
|
53 |
+
|
54 |
+
TEST_CASE("Pass classes and data between modules defined in C++ and Python") {
|
55 |
+
auto module_ = py::module_::import("test_interpreter");
|
56 |
+
REQUIRE(py::hasattr(module_, "DerivedWidget"));
|
57 |
+
|
58 |
+
auto locals = py::dict("hello"_a="Hello, World!", "x"_a=5, **module_.attr("__dict__"));
|
59 |
+
py::exec(R"(
|
60 |
+
widget = DerivedWidget("{} - {}".format(hello, x))
|
61 |
+
message = widget.the_message
|
62 |
+
)", py::globals(), locals);
|
63 |
+
REQUIRE(locals["message"].cast<std::string>() == "Hello, World! - 5");
|
64 |
+
|
65 |
+
auto py_widget = module_.attr("DerivedWidget")("The question");
|
66 |
+
auto message = py_widget.attr("the_message");
|
67 |
+
REQUIRE(message.cast<std::string>() == "The question");
|
68 |
+
|
69 |
+
const auto &cpp_widget = py_widget.cast<const Widget &>();
|
70 |
+
REQUIRE(cpp_widget.the_answer() == 42);
|
71 |
+
}
|
72 |
+
|
73 |
+
TEST_CASE("Import error handling") {
|
74 |
+
REQUIRE_NOTHROW(py::module_::import("widget_module"));
|
75 |
+
REQUIRE_THROWS_WITH(py::module_::import("throw_exception"),
|
76 |
+
"ImportError: C++ Error");
|
77 |
+
REQUIRE_THROWS_WITH(py::module_::import("throw_error_already_set"),
|
78 |
+
Catch::Contains("ImportError: KeyError"));
|
79 |
+
}
|
80 |
+
|
81 |
+
TEST_CASE("There can be only one interpreter") {
|
82 |
+
static_assert(std::is_move_constructible<py::scoped_interpreter>::value, "");
|
83 |
+
static_assert(!std::is_move_assignable<py::scoped_interpreter>::value, "");
|
84 |
+
static_assert(!std::is_copy_constructible<py::scoped_interpreter>::value, "");
|
85 |
+
static_assert(!std::is_copy_assignable<py::scoped_interpreter>::value, "");
|
86 |
+
|
87 |
+
REQUIRE_THROWS_WITH(py::initialize_interpreter(), "The interpreter is already running");
|
88 |
+
REQUIRE_THROWS_WITH(py::scoped_interpreter(), "The interpreter is already running");
|
89 |
+
|
90 |
+
py::finalize_interpreter();
|
91 |
+
REQUIRE_NOTHROW(py::scoped_interpreter());
|
92 |
+
{
|
93 |
+
auto pyi1 = py::scoped_interpreter();
|
94 |
+
auto pyi2 = std::move(pyi1);
|
95 |
+
}
|
96 |
+
py::initialize_interpreter();
|
97 |
+
}
|
98 |
+
|
99 |
+
bool has_pybind11_internals_builtin() {
|
100 |
+
auto builtins = py::handle(PyEval_GetBuiltins());
|
101 |
+
return builtins.contains(PYBIND11_INTERNALS_ID);
|
102 |
+
};
|
103 |
+
|
104 |
+
bool has_pybind11_internals_static() {
|
105 |
+
auto **&ipp = py::detail::get_internals_pp();
|
106 |
+
return (ipp != nullptr) && (*ipp != nullptr);
|
107 |
+
}
|
108 |
+
|
109 |
+
TEST_CASE("Restart the interpreter") {
|
110 |
+
// Verify pre-restart state.
|
111 |
+
REQUIRE(py::module_::import("widget_module").attr("add")(1, 2).cast<int>() == 3);
|
112 |
+
REQUIRE(has_pybind11_internals_builtin());
|
113 |
+
REQUIRE(has_pybind11_internals_static());
|
114 |
+
REQUIRE(py::module_::import("external_module").attr("A")(123).attr("value").cast<int>() == 123);
|
115 |
+
|
116 |
+
// local and foreign module internals should point to the same internals:
|
117 |
+
REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp()) ==
|
118 |
+
py::module_::import("external_module").attr("internals_at")().cast<uintptr_t>());
|
119 |
+
|
120 |
+
// Restart the interpreter.
|
121 |
+
py::finalize_interpreter();
|
122 |
+
REQUIRE(Py_IsInitialized() == 0);
|
123 |
+
|
124 |
+
py::initialize_interpreter();
|
125 |
+
REQUIRE(Py_IsInitialized() == 1);
|
126 |
+
|
127 |
+
// Internals are deleted after a restart.
|
128 |
+
REQUIRE_FALSE(has_pybind11_internals_builtin());
|
129 |
+
REQUIRE_FALSE(has_pybind11_internals_static());
|
130 |
+
pybind11::detail::get_internals();
|
131 |
+
REQUIRE(has_pybind11_internals_builtin());
|
132 |
+
REQUIRE(has_pybind11_internals_static());
|
133 |
+
REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp()) ==
|
134 |
+
py::module_::import("external_module").attr("internals_at")().cast<uintptr_t>());
|
135 |
+
|
136 |
+
// Make sure that an interpreter with no get_internals() created until finalize still gets the
|
137 |
+
// internals destroyed
|
138 |
+
py::finalize_interpreter();
|
139 |
+
py::initialize_interpreter();
|
140 |
+
bool ran = false;
|
141 |
+
py::module_::import("__main__").attr("internals_destroy_test") =
|
142 |
+
py::capsule(&ran, [](void *ran) { py::detail::get_internals(); *static_cast<bool *>(ran) = true; });
|
143 |
+
REQUIRE_FALSE(has_pybind11_internals_builtin());
|
144 |
+
REQUIRE_FALSE(has_pybind11_internals_static());
|
145 |
+
REQUIRE_FALSE(ran);
|
146 |
+
py::finalize_interpreter();
|
147 |
+
REQUIRE(ran);
|
148 |
+
py::initialize_interpreter();
|
149 |
+
REQUIRE_FALSE(has_pybind11_internals_builtin());
|
150 |
+
REQUIRE_FALSE(has_pybind11_internals_static());
|
151 |
+
|
152 |
+
// C++ modules can be reloaded.
|
153 |
+
auto cpp_module = py::module_::import("widget_module");
|
154 |
+
REQUIRE(cpp_module.attr("add")(1, 2).cast<int>() == 3);
|
155 |
+
|
156 |
+
// C++ type information is reloaded and can be used in python modules.
|
157 |
+
auto py_module = py::module_::import("test_interpreter");
|
158 |
+
auto py_widget = py_module.attr("DerivedWidget")("Hello after restart");
|
159 |
+
REQUIRE(py_widget.attr("the_message").cast<std::string>() == "Hello after restart");
|
160 |
+
}
|
161 |
+
|
162 |
+
TEST_CASE("Subinterpreter") {
|
163 |
+
// Add tags to the modules in the main interpreter and test the basics.
|
164 |
+
py::module_::import("__main__").attr("main_tag") = "main interpreter";
|
165 |
+
{
|
166 |
+
auto m = py::module_::import("widget_module");
|
167 |
+
m.attr("extension_module_tag") = "added to module in main interpreter";
|
168 |
+
|
169 |
+
REQUIRE(m.attr("add")(1, 2).cast<int>() == 3);
|
170 |
+
}
|
171 |
+
REQUIRE(has_pybind11_internals_builtin());
|
172 |
+
REQUIRE(has_pybind11_internals_static());
|
173 |
+
|
174 |
+
/// Create and switch to a subinterpreter.
|
175 |
+
auto main_tstate = PyThreadState_Get();
|
176 |
+
auto sub_tstate = Py_NewInterpreter();
|
177 |
+
|
178 |
+
// Subinterpreters get their own copy of builtins. detail::get_internals() still
|
179 |
+
// works by returning from the static variable, i.e. all interpreters share a single
|
180 |
+
// global pybind11::internals;
|
181 |
+
REQUIRE_FALSE(has_pybind11_internals_builtin());
|
182 |
+
REQUIRE(has_pybind11_internals_static());
|
183 |
+
|
184 |
+
// Modules tags should be gone.
|
185 |
+
REQUIRE_FALSE(py::hasattr(py::module_::import("__main__"), "tag"));
|
186 |
+
{
|
187 |
+
auto m = py::module_::import("widget_module");
|
188 |
+
REQUIRE_FALSE(py::hasattr(m, "extension_module_tag"));
|
189 |
+
|
190 |
+
// Function bindings should still work.
|
191 |
+
REQUIRE(m.attr("add")(1, 2).cast<int>() == 3);
|
192 |
+
}
|
193 |
+
|
194 |
+
// Restore main interpreter.
|
195 |
+
Py_EndInterpreter(sub_tstate);
|
196 |
+
PyThreadState_Swap(main_tstate);
|
197 |
+
|
198 |
+
REQUIRE(py::hasattr(py::module_::import("__main__"), "main_tag"));
|
199 |
+
REQUIRE(py::hasattr(py::module_::import("widget_module"), "extension_module_tag"));
|
200 |
+
}
|
201 |
+
|
202 |
+
TEST_CASE("Execution frame") {
|
203 |
+
// When the interpreter is embedded, there is no execution frame, but `py::exec`
|
204 |
+
// should still function by using reasonable globals: `__main__.__dict__`.
|
205 |
+
py::exec("var = dict(number=42)");
|
206 |
+
REQUIRE(py::globals()["var"]["number"].cast<int>() == 42);
|
207 |
+
}
|
208 |
+
|
209 |
+
TEST_CASE("Threads") {
|
210 |
+
// Restart interpreter to ensure threads are not initialized
|
211 |
+
py::finalize_interpreter();
|
212 |
+
py::initialize_interpreter();
|
213 |
+
REQUIRE_FALSE(has_pybind11_internals_static());
|
214 |
+
|
215 |
+
constexpr auto num_threads = 10;
|
216 |
+
auto locals = py::dict("count"_a=0);
|
217 |
+
|
218 |
+
{
|
219 |
+
py::gil_scoped_release gil_release{};
|
220 |
+
REQUIRE(has_pybind11_internals_static());
|
221 |
+
|
222 |
+
auto threads = std::vector<std::thread>();
|
223 |
+
for (auto i = 0; i < num_threads; ++i) {
|
224 |
+
threads.emplace_back([&]() {
|
225 |
+
py::gil_scoped_acquire gil{};
|
226 |
+
locals["count"] = locals["count"].cast<int>() + 1;
|
227 |
+
});
|
228 |
+
}
|
229 |
+
|
230 |
+
for (auto &thread : threads) {
|
231 |
+
thread.join();
|
232 |
+
}
|
233 |
+
}
|
234 |
+
|
235 |
+
REQUIRE(locals["count"].cast<int>() == num_threads);
|
236 |
+
}
|
237 |
+
|
238 |
+
// Scope exit utility https://stackoverflow.com/a/36644501/7255855
|
239 |
+
struct scope_exit {
|
240 |
+
std::function<void()> f_;
|
241 |
+
explicit scope_exit(std::function<void()> f) noexcept : f_(std::move(f)) {}
|
242 |
+
~scope_exit() { if (f_) f_(); }
|
243 |
+
};
|
244 |
+
|
245 |
+
TEST_CASE("Reload module from file") {
|
246 |
+
// Disable generation of cached bytecode (.pyc files) for this test, otherwise
|
247 |
+
// Python might pick up an old version from the cache instead of the new versions
|
248 |
+
// of the .py files generated below
|
249 |
+
auto sys = py::module_::import("sys");
|
250 |
+
bool dont_write_bytecode = sys.attr("dont_write_bytecode").cast<bool>();
|
251 |
+
sys.attr("dont_write_bytecode") = true;
|
252 |
+
// Reset the value at scope exit
|
253 |
+
scope_exit reset_dont_write_bytecode([&]() {
|
254 |
+
sys.attr("dont_write_bytecode") = dont_write_bytecode;
|
255 |
+
});
|
256 |
+
|
257 |
+
std::string module_name = "test_module_reload";
|
258 |
+
std::string module_file = module_name + ".py";
|
259 |
+
|
260 |
+
// Create the module .py file
|
261 |
+
std::ofstream test_module(module_file);
|
262 |
+
test_module << "def test():\n";
|
263 |
+
test_module << " return 1\n";
|
264 |
+
test_module.close();
|
265 |
+
// Delete the file at scope exit
|
266 |
+
scope_exit delete_module_file([&]() {
|
267 |
+
std::remove(module_file.c_str());
|
268 |
+
});
|
269 |
+
|
270 |
+
// Import the module from file
|
271 |
+
auto module_ = py::module_::import(module_name.c_str());
|
272 |
+
int result = module_.attr("test")().cast<int>();
|
273 |
+
REQUIRE(result == 1);
|
274 |
+
|
275 |
+
// Update the module .py file with a small change
|
276 |
+
test_module.open(module_file);
|
277 |
+
test_module << "def test():\n";
|
278 |
+
test_module << " return 2\n";
|
279 |
+
test_module.close();
|
280 |
+
|
281 |
+
// Reload the module
|
282 |
+
module_.reload();
|
283 |
+
result = module_.attr("test")().cast<int>();
|
284 |
+
REQUIRE(result == 2);
|
285 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_embed/test_interpreter.py
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
from widget_module import Widget
|
3 |
+
|
4 |
+
|
5 |
+
class DerivedWidget(Widget):
|
6 |
+
def __init__(self, message):
|
7 |
+
super(DerivedWidget, self).__init__(message)
|
8 |
+
|
9 |
+
def the_answer(self):
|
10 |
+
return 42
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_enum.cpp
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_enums.cpp -- enumerations
|
3 |
+
|
4 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "pybind11_tests.h"
|
11 |
+
|
12 |
+
TEST_SUBMODULE(enums, m) {
|
13 |
+
// test_unscoped_enum
|
14 |
+
enum UnscopedEnum {
|
15 |
+
EOne = 1,
|
16 |
+
ETwo,
|
17 |
+
EThree
|
18 |
+
};
|
19 |
+
py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration")
|
20 |
+
.value("EOne", EOne, "Docstring for EOne")
|
21 |
+
.value("ETwo", ETwo, "Docstring for ETwo")
|
22 |
+
.value("EThree", EThree, "Docstring for EThree")
|
23 |
+
.export_values();
|
24 |
+
|
25 |
+
// test_scoped_enum
|
26 |
+
enum class ScopedEnum {
|
27 |
+
Two = 2,
|
28 |
+
Three
|
29 |
+
};
|
30 |
+
py::enum_<ScopedEnum>(m, "ScopedEnum", py::arithmetic())
|
31 |
+
.value("Two", ScopedEnum::Two)
|
32 |
+
.value("Three", ScopedEnum::Three);
|
33 |
+
|
34 |
+
m.def("test_scoped_enum", [](ScopedEnum z) {
|
35 |
+
return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three");
|
36 |
+
});
|
37 |
+
|
38 |
+
// test_binary_operators
|
39 |
+
enum Flags {
|
40 |
+
Read = 4,
|
41 |
+
Write = 2,
|
42 |
+
Execute = 1
|
43 |
+
};
|
44 |
+
py::enum_<Flags>(m, "Flags", py::arithmetic())
|
45 |
+
.value("Read", Flags::Read)
|
46 |
+
.value("Write", Flags::Write)
|
47 |
+
.value("Execute", Flags::Execute)
|
48 |
+
.export_values();
|
49 |
+
|
50 |
+
// test_implicit_conversion
|
51 |
+
class ClassWithUnscopedEnum {
|
52 |
+
public:
|
53 |
+
enum EMode {
|
54 |
+
EFirstMode = 1,
|
55 |
+
ESecondMode
|
56 |
+
};
|
57 |
+
|
58 |
+
static EMode test_function(EMode mode) {
|
59 |
+
return mode;
|
60 |
+
}
|
61 |
+
};
|
62 |
+
py::class_<ClassWithUnscopedEnum> exenum_class(m, "ClassWithUnscopedEnum");
|
63 |
+
exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function);
|
64 |
+
py::enum_<ClassWithUnscopedEnum::EMode>(exenum_class, "EMode")
|
65 |
+
.value("EFirstMode", ClassWithUnscopedEnum::EFirstMode)
|
66 |
+
.value("ESecondMode", ClassWithUnscopedEnum::ESecondMode)
|
67 |
+
.export_values();
|
68 |
+
|
69 |
+
// test_enum_to_int
|
70 |
+
m.def("test_enum_to_int", [](int) { });
|
71 |
+
m.def("test_enum_to_uint", [](uint32_t) { });
|
72 |
+
m.def("test_enum_to_long_long", [](long long) { });
|
73 |
+
|
74 |
+
// test_duplicate_enum_name
|
75 |
+
enum SimpleEnum
|
76 |
+
{
|
77 |
+
ONE, TWO, THREE
|
78 |
+
};
|
79 |
+
|
80 |
+
m.def("register_bad_enum", [m]() {
|
81 |
+
py::enum_<SimpleEnum>(m, "SimpleEnum")
|
82 |
+
.value("ONE", SimpleEnum::ONE) //NOTE: all value function calls are called with the same first parameter value
|
83 |
+
.value("ONE", SimpleEnum::TWO)
|
84 |
+
.value("ONE", SimpleEnum::THREE)
|
85 |
+
.export_values();
|
86 |
+
});
|
87 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_enum.py
ADDED
@@ -0,0 +1,236 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
from pybind11_tests import enums as m
|
4 |
+
|
5 |
+
|
6 |
+
def test_unscoped_enum():
|
7 |
+
assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne"
|
8 |
+
assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
|
9 |
+
assert str(m.EOne) == "UnscopedEnum.EOne"
|
10 |
+
assert repr(m.UnscopedEnum.EOne) == "<UnscopedEnum.EOne: 1>"
|
11 |
+
assert repr(m.UnscopedEnum.ETwo) == "<UnscopedEnum.ETwo: 2>"
|
12 |
+
assert repr(m.EOne) == "<UnscopedEnum.EOne: 1>"
|
13 |
+
|
14 |
+
# name property
|
15 |
+
assert m.UnscopedEnum.EOne.name == "EOne"
|
16 |
+
assert m.UnscopedEnum.EOne.value == 1
|
17 |
+
assert m.UnscopedEnum.ETwo.name == "ETwo"
|
18 |
+
assert m.UnscopedEnum.ETwo.value == 2
|
19 |
+
assert m.EOne is m.UnscopedEnum.EOne
|
20 |
+
# name, value readonly
|
21 |
+
with pytest.raises(AttributeError):
|
22 |
+
m.UnscopedEnum.EOne.name = ""
|
23 |
+
with pytest.raises(AttributeError):
|
24 |
+
m.UnscopedEnum.EOne.value = 10
|
25 |
+
# name, value returns a copy
|
26 |
+
# TODO: Neither the name nor value tests actually check against aliasing.
|
27 |
+
# Use a mutable type that has reference semantics.
|
28 |
+
nonaliased_name = m.UnscopedEnum.EOne.name
|
29 |
+
nonaliased_name = "bar" # noqa: F841
|
30 |
+
assert m.UnscopedEnum.EOne.name == "EOne"
|
31 |
+
nonaliased_value = m.UnscopedEnum.EOne.value
|
32 |
+
nonaliased_value = 10 # noqa: F841
|
33 |
+
assert m.UnscopedEnum.EOne.value == 1
|
34 |
+
|
35 |
+
# __members__ property
|
36 |
+
assert m.UnscopedEnum.__members__ == {
|
37 |
+
"EOne": m.UnscopedEnum.EOne,
|
38 |
+
"ETwo": m.UnscopedEnum.ETwo,
|
39 |
+
"EThree": m.UnscopedEnum.EThree,
|
40 |
+
}
|
41 |
+
# __members__ readonly
|
42 |
+
with pytest.raises(AttributeError):
|
43 |
+
m.UnscopedEnum.__members__ = {}
|
44 |
+
# __members__ returns a copy
|
45 |
+
nonaliased_members = m.UnscopedEnum.__members__
|
46 |
+
nonaliased_members["bar"] = "baz"
|
47 |
+
assert m.UnscopedEnum.__members__ == {
|
48 |
+
"EOne": m.UnscopedEnum.EOne,
|
49 |
+
"ETwo": m.UnscopedEnum.ETwo,
|
50 |
+
"EThree": m.UnscopedEnum.EThree,
|
51 |
+
}
|
52 |
+
|
53 |
+
for docstring_line in """An unscoped enumeration
|
54 |
+
|
55 |
+
Members:
|
56 |
+
|
57 |
+
EOne : Docstring for EOne
|
58 |
+
|
59 |
+
ETwo : Docstring for ETwo
|
60 |
+
|
61 |
+
EThree : Docstring for EThree""".split(
|
62 |
+
"\n"
|
63 |
+
):
|
64 |
+
assert docstring_line in m.UnscopedEnum.__doc__
|
65 |
+
|
66 |
+
# Unscoped enums will accept ==/!= int comparisons
|
67 |
+
y = m.UnscopedEnum.ETwo
|
68 |
+
assert y == 2
|
69 |
+
assert 2 == y
|
70 |
+
assert y != 3
|
71 |
+
assert 3 != y
|
72 |
+
# Compare with None
|
73 |
+
assert y != None # noqa: E711
|
74 |
+
assert not (y == None) # noqa: E711
|
75 |
+
# Compare with an object
|
76 |
+
assert y != object()
|
77 |
+
assert not (y == object())
|
78 |
+
# Compare with string
|
79 |
+
assert y != "2"
|
80 |
+
assert "2" != y
|
81 |
+
assert not ("2" == y)
|
82 |
+
assert not (y == "2")
|
83 |
+
|
84 |
+
with pytest.raises(TypeError):
|
85 |
+
y < object() # noqa: B015
|
86 |
+
|
87 |
+
with pytest.raises(TypeError):
|
88 |
+
y <= object() # noqa: B015
|
89 |
+
|
90 |
+
with pytest.raises(TypeError):
|
91 |
+
y > object() # noqa: B015
|
92 |
+
|
93 |
+
with pytest.raises(TypeError):
|
94 |
+
y >= object() # noqa: B015
|
95 |
+
|
96 |
+
with pytest.raises(TypeError):
|
97 |
+
y | object() # noqa: B015
|
98 |
+
|
99 |
+
with pytest.raises(TypeError):
|
100 |
+
y & object() # noqa: B015
|
101 |
+
|
102 |
+
with pytest.raises(TypeError):
|
103 |
+
y ^ object() # noqa: B015
|
104 |
+
|
105 |
+
assert int(m.UnscopedEnum.ETwo) == 2
|
106 |
+
assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo"
|
107 |
+
|
108 |
+
# order
|
109 |
+
assert m.UnscopedEnum.EOne < m.UnscopedEnum.ETwo
|
110 |
+
assert m.UnscopedEnum.EOne < 2
|
111 |
+
assert m.UnscopedEnum.ETwo > m.UnscopedEnum.EOne
|
112 |
+
assert m.UnscopedEnum.ETwo > 1
|
113 |
+
assert m.UnscopedEnum.ETwo <= 2
|
114 |
+
assert m.UnscopedEnum.ETwo >= 2
|
115 |
+
assert m.UnscopedEnum.EOne <= m.UnscopedEnum.ETwo
|
116 |
+
assert m.UnscopedEnum.EOne <= 2
|
117 |
+
assert m.UnscopedEnum.ETwo >= m.UnscopedEnum.EOne
|
118 |
+
assert m.UnscopedEnum.ETwo >= 1
|
119 |
+
assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne)
|
120 |
+
assert not (2 < m.UnscopedEnum.EOne)
|
121 |
+
|
122 |
+
# arithmetic
|
123 |
+
assert m.UnscopedEnum.EOne & m.UnscopedEnum.EThree == m.UnscopedEnum.EOne
|
124 |
+
assert m.UnscopedEnum.EOne | m.UnscopedEnum.ETwo == m.UnscopedEnum.EThree
|
125 |
+
assert m.UnscopedEnum.EOne ^ m.UnscopedEnum.EThree == m.UnscopedEnum.ETwo
|
126 |
+
|
127 |
+
|
128 |
+
def test_scoped_enum():
|
129 |
+
assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three"
|
130 |
+
z = m.ScopedEnum.Two
|
131 |
+
assert m.test_scoped_enum(z) == "ScopedEnum::Two"
|
132 |
+
|
133 |
+
# Scoped enums will *NOT* accept ==/!= int comparisons (Will always return False)
|
134 |
+
assert not z == 3
|
135 |
+
assert not 3 == z
|
136 |
+
assert z != 3
|
137 |
+
assert 3 != z
|
138 |
+
# Compare with None
|
139 |
+
assert z != None # noqa: E711
|
140 |
+
assert not (z == None) # noqa: E711
|
141 |
+
# Compare with an object
|
142 |
+
assert z != object()
|
143 |
+
assert not (z == object())
|
144 |
+
# Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions)
|
145 |
+
with pytest.raises(TypeError):
|
146 |
+
z > 3 # noqa: B015
|
147 |
+
with pytest.raises(TypeError):
|
148 |
+
z < 3 # noqa: B015
|
149 |
+
with pytest.raises(TypeError):
|
150 |
+
z >= 3 # noqa: B015
|
151 |
+
with pytest.raises(TypeError):
|
152 |
+
z <= 3 # noqa: B015
|
153 |
+
|
154 |
+
# order
|
155 |
+
assert m.ScopedEnum.Two < m.ScopedEnum.Three
|
156 |
+
assert m.ScopedEnum.Three > m.ScopedEnum.Two
|
157 |
+
assert m.ScopedEnum.Two <= m.ScopedEnum.Three
|
158 |
+
assert m.ScopedEnum.Two <= m.ScopedEnum.Two
|
159 |
+
assert m.ScopedEnum.Two >= m.ScopedEnum.Two
|
160 |
+
assert m.ScopedEnum.Three >= m.ScopedEnum.Two
|
161 |
+
|
162 |
+
|
163 |
+
def test_implicit_conversion():
|
164 |
+
assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"
|
165 |
+
assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
|
166 |
+
assert repr(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "<EMode.EFirstMode: 1>"
|
167 |
+
assert repr(m.ClassWithUnscopedEnum.EFirstMode) == "<EMode.EFirstMode: 1>"
|
168 |
+
|
169 |
+
f = m.ClassWithUnscopedEnum.test_function
|
170 |
+
first = m.ClassWithUnscopedEnum.EFirstMode
|
171 |
+
second = m.ClassWithUnscopedEnum.ESecondMode
|
172 |
+
|
173 |
+
assert f(first) == 1
|
174 |
+
|
175 |
+
assert f(first) == f(first)
|
176 |
+
assert not f(first) != f(first)
|
177 |
+
|
178 |
+
assert f(first) != f(second)
|
179 |
+
assert not f(first) == f(second)
|
180 |
+
|
181 |
+
assert f(first) == int(f(first))
|
182 |
+
assert not f(first) != int(f(first))
|
183 |
+
|
184 |
+
assert f(first) != int(f(second))
|
185 |
+
assert not f(first) == int(f(second))
|
186 |
+
|
187 |
+
# noinspection PyDictCreation
|
188 |
+
x = {f(first): 1, f(second): 2}
|
189 |
+
x[f(first)] = 3
|
190 |
+
x[f(second)] = 4
|
191 |
+
# Hashing test
|
192 |
+
assert repr(x) == "{<EMode.EFirstMode: 1>: 3, <EMode.ESecondMode: 2>: 4}"
|
193 |
+
|
194 |
+
|
195 |
+
def test_binary_operators():
|
196 |
+
assert int(m.Flags.Read) == 4
|
197 |
+
assert int(m.Flags.Write) == 2
|
198 |
+
assert int(m.Flags.Execute) == 1
|
199 |
+
assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7
|
200 |
+
assert int(m.Flags.Read | m.Flags.Write) == 6
|
201 |
+
assert int(m.Flags.Read | m.Flags.Execute) == 5
|
202 |
+
assert int(m.Flags.Write | m.Flags.Execute) == 3
|
203 |
+
assert int(m.Flags.Write | 1) == 3
|
204 |
+
assert ~m.Flags.Write == -3
|
205 |
+
|
206 |
+
state = m.Flags.Read | m.Flags.Write
|
207 |
+
assert (state & m.Flags.Read) != 0
|
208 |
+
assert (state & m.Flags.Write) != 0
|
209 |
+
assert (state & m.Flags.Execute) == 0
|
210 |
+
assert (state & 1) == 0
|
211 |
+
|
212 |
+
state2 = ~state
|
213 |
+
assert state2 == -7
|
214 |
+
assert int(state ^ state2) == -1
|
215 |
+
|
216 |
+
|
217 |
+
def test_enum_to_int():
|
218 |
+
m.test_enum_to_int(m.Flags.Read)
|
219 |
+
m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode)
|
220 |
+
m.test_enum_to_uint(m.Flags.Read)
|
221 |
+
m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode)
|
222 |
+
m.test_enum_to_long_long(m.Flags.Read)
|
223 |
+
m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode)
|
224 |
+
|
225 |
+
|
226 |
+
def test_duplicate_enum_name():
|
227 |
+
with pytest.raises(ValueError) as excinfo:
|
228 |
+
m.register_bad_enum()
|
229 |
+
assert str(excinfo.value) == 'SimpleEnum: element "ONE" already exists!'
|
230 |
+
|
231 |
+
|
232 |
+
def test_docstring_signatures():
|
233 |
+
for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
|
234 |
+
for attr in enum_type.__dict__.values():
|
235 |
+
# Issue #2623/PR #2637: Add argument names to enum_ methods
|
236 |
+
assert "arg0" not in (attr.__doc__ or "")
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_eval.cpp
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_eval.cpp -- Usage of eval() and eval_file()
|
3 |
+
|
4 |
+
Copyright (c) 2016 Klemens D. Morgenstern
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
|
11 |
+
#include <pybind11/eval.h>
|
12 |
+
|
13 |
+
#include "pybind11_tests.h"
|
14 |
+
#include <utility>
|
15 |
+
|
16 |
+
TEST_SUBMODULE(eval_, m) {
|
17 |
+
// test_evals
|
18 |
+
|
19 |
+
auto global = py::dict(py::module_::import("__main__").attr("__dict__"));
|
20 |
+
|
21 |
+
m.def("test_eval_statements", [global]() {
|
22 |
+
auto local = py::dict();
|
23 |
+
local["call_test"] = py::cpp_function([&]() -> int {
|
24 |
+
return 42;
|
25 |
+
});
|
26 |
+
|
27 |
+
// Regular string literal
|
28 |
+
py::exec(
|
29 |
+
"message = 'Hello World!'\n"
|
30 |
+
"x = call_test()",
|
31 |
+
global, local
|
32 |
+
);
|
33 |
+
|
34 |
+
// Multi-line raw string literal
|
35 |
+
py::exec(R"(
|
36 |
+
if x == 42:
|
37 |
+
print(message)
|
38 |
+
else:
|
39 |
+
raise RuntimeError
|
40 |
+
)", global, local
|
41 |
+
);
|
42 |
+
auto x = local["x"].cast<int>();
|
43 |
+
|
44 |
+
return x == 42;
|
45 |
+
});
|
46 |
+
|
47 |
+
m.def("test_eval", [global]() {
|
48 |
+
auto local = py::dict();
|
49 |
+
local["x"] = py::int_(42);
|
50 |
+
auto x = py::eval("x", global, local);
|
51 |
+
return x.cast<int>() == 42;
|
52 |
+
});
|
53 |
+
|
54 |
+
m.def("test_eval_single_statement", []() {
|
55 |
+
auto local = py::dict();
|
56 |
+
local["call_test"] = py::cpp_function([&]() -> int {
|
57 |
+
return 42;
|
58 |
+
});
|
59 |
+
|
60 |
+
auto result = py::eval<py::eval_single_statement>("x = call_test()", py::dict(), local);
|
61 |
+
auto x = local["x"].cast<int>();
|
62 |
+
return result.is_none() && x == 42;
|
63 |
+
});
|
64 |
+
|
65 |
+
m.def("test_eval_file", [global](py::str filename) {
|
66 |
+
auto local = py::dict();
|
67 |
+
local["y"] = py::int_(43);
|
68 |
+
|
69 |
+
int val_out = 0;
|
70 |
+
local["call_test2"] = py::cpp_function([&](int value) { val_out = value; });
|
71 |
+
|
72 |
+
auto result = py::eval_file(std::move(filename), global, local);
|
73 |
+
return val_out == 43 && result.is_none();
|
74 |
+
});
|
75 |
+
|
76 |
+
m.def("test_eval_failure", []() {
|
77 |
+
try {
|
78 |
+
py::eval("nonsense code ...");
|
79 |
+
} catch (py::error_already_set &) {
|
80 |
+
return true;
|
81 |
+
}
|
82 |
+
return false;
|
83 |
+
});
|
84 |
+
|
85 |
+
m.def("test_eval_file_failure", []() {
|
86 |
+
try {
|
87 |
+
py::eval_file("non-existing file");
|
88 |
+
} catch (std::exception &) {
|
89 |
+
return true;
|
90 |
+
}
|
91 |
+
return false;
|
92 |
+
});
|
93 |
+
|
94 |
+
// test_eval_empty_globals
|
95 |
+
m.def("eval_empty_globals", [](py::object global) {
|
96 |
+
if (global.is_none())
|
97 |
+
global = py::dict();
|
98 |
+
auto int_class = py::eval("isinstance(42, int)", global);
|
99 |
+
return global;
|
100 |
+
});
|
101 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_eval.py
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import os
|
3 |
+
|
4 |
+
import pytest
|
5 |
+
|
6 |
+
import env # noqa: F401
|
7 |
+
|
8 |
+
from pybind11_tests import eval_ as m
|
9 |
+
|
10 |
+
|
11 |
+
def test_evals(capture):
|
12 |
+
with capture:
|
13 |
+
assert m.test_eval_statements()
|
14 |
+
assert capture == "Hello World!"
|
15 |
+
|
16 |
+
assert m.test_eval()
|
17 |
+
assert m.test_eval_single_statement()
|
18 |
+
|
19 |
+
assert m.test_eval_failure()
|
20 |
+
|
21 |
+
|
22 |
+
@pytest.mark.xfail("env.PYPY and not env.PY2", raises=RuntimeError)
|
23 |
+
def test_eval_file():
|
24 |
+
filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
|
25 |
+
assert m.test_eval_file(filename)
|
26 |
+
|
27 |
+
assert m.test_eval_file_failure()
|
28 |
+
|
29 |
+
|
30 |
+
def test_eval_empty_globals():
|
31 |
+
assert "__builtins__" in m.eval_empty_globals(None)
|
32 |
+
|
33 |
+
g = {}
|
34 |
+
assert "__builtins__" in m.eval_empty_globals(g)
|
35 |
+
assert "__builtins__" in g
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_eval_call.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
# This file is called from 'test_eval.py'
|
3 |
+
|
4 |
+
if "call_test2" in locals():
|
5 |
+
call_test2(y) # noqa: F821 undefined name
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_exceptions.cpp
ADDED
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_custom-exceptions.cpp -- exception translation
|
3 |
+
|
4 |
+
Copyright (c) 2016 Pim Schellart <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "test_exceptions.h"
|
11 |
+
|
12 |
+
#include "pybind11_tests.h"
|
13 |
+
#include <utility>
|
14 |
+
|
15 |
+
// A type that should be raised as an exception in Python
|
16 |
+
class MyException : public std::exception {
|
17 |
+
public:
|
18 |
+
explicit MyException(const char * m) : message{m} {}
|
19 |
+
const char * what() const noexcept override {return message.c_str();}
|
20 |
+
private:
|
21 |
+
std::string message = "";
|
22 |
+
};
|
23 |
+
|
24 |
+
// A type that should be translated to a standard Python exception
|
25 |
+
class MyException2 : public std::exception {
|
26 |
+
public:
|
27 |
+
explicit MyException2(const char * m) : message{m} {}
|
28 |
+
const char * what() const noexcept override {return message.c_str();}
|
29 |
+
private:
|
30 |
+
std::string message = "";
|
31 |
+
};
|
32 |
+
|
33 |
+
// A type that is not derived from std::exception (and is thus unknown)
|
34 |
+
class MyException3 {
|
35 |
+
public:
|
36 |
+
explicit MyException3(const char * m) : message{m} {}
|
37 |
+
virtual const char * what() const noexcept {return message.c_str();}
|
38 |
+
// Rule of 5 BEGIN: to preempt compiler warnings.
|
39 |
+
MyException3(const MyException3&) = default;
|
40 |
+
MyException3(MyException3&&) = default;
|
41 |
+
MyException3& operator=(const MyException3&) = default;
|
42 |
+
MyException3& operator=(MyException3&&) = default;
|
43 |
+
virtual ~MyException3() = default;
|
44 |
+
// Rule of 5 END.
|
45 |
+
private:
|
46 |
+
std::string message = "";
|
47 |
+
};
|
48 |
+
|
49 |
+
// A type that should be translated to MyException
|
50 |
+
// and delegated to its exception translator
|
51 |
+
class MyException4 : public std::exception {
|
52 |
+
public:
|
53 |
+
explicit MyException4(const char * m) : message{m} {}
|
54 |
+
const char * what() const noexcept override {return message.c_str();}
|
55 |
+
private:
|
56 |
+
std::string message = "";
|
57 |
+
};
|
58 |
+
|
59 |
+
|
60 |
+
// Like the above, but declared via the helper function
|
61 |
+
class MyException5 : public std::logic_error {
|
62 |
+
public:
|
63 |
+
explicit MyException5(const std::string &what) : std::logic_error(what) {}
|
64 |
+
};
|
65 |
+
|
66 |
+
// Inherits from MyException5
|
67 |
+
class MyException5_1 : public MyException5 {
|
68 |
+
using MyException5::MyException5;
|
69 |
+
};
|
70 |
+
|
71 |
+
struct PythonCallInDestructor {
|
72 |
+
PythonCallInDestructor(const py::dict &d) : d(d) {}
|
73 |
+
~PythonCallInDestructor() { d["good"] = true; }
|
74 |
+
|
75 |
+
py::dict d;
|
76 |
+
};
|
77 |
+
|
78 |
+
|
79 |
+
|
80 |
+
struct PythonAlreadySetInDestructor {
|
81 |
+
PythonAlreadySetInDestructor(const py::str &s) : s(s) {}
|
82 |
+
~PythonAlreadySetInDestructor() {
|
83 |
+
py::dict foo;
|
84 |
+
try {
|
85 |
+
// Assign to a py::object to force read access of nonexistent dict entry
|
86 |
+
py::object o = foo["bar"];
|
87 |
+
}
|
88 |
+
catch (py::error_already_set& ex) {
|
89 |
+
ex.discard_as_unraisable(s);
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
py::str s;
|
94 |
+
};
|
95 |
+
|
96 |
+
|
97 |
+
TEST_SUBMODULE(exceptions, m) {
|
98 |
+
m.def("throw_std_exception", []() {
|
99 |
+
throw std::runtime_error("This exception was intentionally thrown.");
|
100 |
+
});
|
101 |
+
|
102 |
+
// make a new custom exception and use it as a translation target
|
103 |
+
static py::exception<MyException> ex(m, "MyException");
|
104 |
+
py::register_exception_translator([](std::exception_ptr p) {
|
105 |
+
try {
|
106 |
+
if (p) std::rethrow_exception(p);
|
107 |
+
} catch (const MyException &e) {
|
108 |
+
// Set MyException as the active python error
|
109 |
+
ex(e.what());
|
110 |
+
}
|
111 |
+
});
|
112 |
+
|
113 |
+
// register new translator for MyException2
|
114 |
+
// no need to store anything here because this type will
|
115 |
+
// never by visible from Python
|
116 |
+
py::register_exception_translator([](std::exception_ptr p) {
|
117 |
+
try {
|
118 |
+
if (p) std::rethrow_exception(p);
|
119 |
+
} catch (const MyException2 &e) {
|
120 |
+
// Translate this exception to a standard RuntimeError
|
121 |
+
PyErr_SetString(PyExc_RuntimeError, e.what());
|
122 |
+
}
|
123 |
+
});
|
124 |
+
|
125 |
+
// register new translator for MyException4
|
126 |
+
// which will catch it and delegate to the previously registered
|
127 |
+
// translator for MyException by throwing a new exception
|
128 |
+
py::register_exception_translator([](std::exception_ptr p) {
|
129 |
+
try {
|
130 |
+
if (p) std::rethrow_exception(p);
|
131 |
+
} catch (const MyException4 &e) {
|
132 |
+
throw MyException(e.what());
|
133 |
+
}
|
134 |
+
});
|
135 |
+
|
136 |
+
// A simple exception translation:
|
137 |
+
auto ex5 = py::register_exception<MyException5>(m, "MyException5");
|
138 |
+
// A slightly more complicated one that declares MyException5_1 as a subclass of MyException5
|
139 |
+
py::register_exception<MyException5_1>(m, "MyException5_1", ex5.ptr());
|
140 |
+
|
141 |
+
m.def("throws1", []() { throw MyException("this error should go to a custom type"); });
|
142 |
+
m.def("throws2", []() { throw MyException2("this error should go to a standard Python exception"); });
|
143 |
+
m.def("throws3", []() { throw MyException3("this error cannot be translated"); });
|
144 |
+
m.def("throws4", []() { throw MyException4("this error is rethrown"); });
|
145 |
+
m.def("throws5", []() { throw MyException5("this is a helper-defined translated exception"); });
|
146 |
+
m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); });
|
147 |
+
m.def("throws_logic_error", []() { throw std::logic_error("this error should fall through to the standard handler"); });
|
148 |
+
m.def("throws_overflow_error", []() {throw std::overflow_error(""); });
|
149 |
+
m.def("exception_matches", []() {
|
150 |
+
py::dict foo;
|
151 |
+
try {
|
152 |
+
// Assign to a py::object to force read access of nonexistent dict entry
|
153 |
+
py::object o = foo["bar"];
|
154 |
+
}
|
155 |
+
catch (py::error_already_set& ex) {
|
156 |
+
if (!ex.matches(PyExc_KeyError)) throw;
|
157 |
+
return true;
|
158 |
+
}
|
159 |
+
return false;
|
160 |
+
});
|
161 |
+
m.def("exception_matches_base", []() {
|
162 |
+
py::dict foo;
|
163 |
+
try {
|
164 |
+
// Assign to a py::object to force read access of nonexistent dict entry
|
165 |
+
py::object o = foo["bar"];
|
166 |
+
}
|
167 |
+
catch (py::error_already_set &ex) {
|
168 |
+
if (!ex.matches(PyExc_Exception)) throw;
|
169 |
+
return true;
|
170 |
+
}
|
171 |
+
return false;
|
172 |
+
});
|
173 |
+
m.def("modulenotfound_exception_matches_base", []() {
|
174 |
+
try {
|
175 |
+
// On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError
|
176 |
+
py::module_::import("nonexistent");
|
177 |
+
}
|
178 |
+
catch (py::error_already_set &ex) {
|
179 |
+
if (!ex.matches(PyExc_ImportError)) throw;
|
180 |
+
return true;
|
181 |
+
}
|
182 |
+
return false;
|
183 |
+
});
|
184 |
+
|
185 |
+
m.def("throw_already_set", [](bool err) {
|
186 |
+
if (err)
|
187 |
+
PyErr_SetString(PyExc_ValueError, "foo");
|
188 |
+
try {
|
189 |
+
throw py::error_already_set();
|
190 |
+
} catch (const std::runtime_error& e) {
|
191 |
+
if ((err && e.what() != std::string("ValueError: foo")) ||
|
192 |
+
(!err && e.what() != std::string("Unknown internal error occurred")))
|
193 |
+
{
|
194 |
+
PyErr_Clear();
|
195 |
+
throw std::runtime_error("error message mismatch");
|
196 |
+
}
|
197 |
+
}
|
198 |
+
PyErr_Clear();
|
199 |
+
if (err)
|
200 |
+
PyErr_SetString(PyExc_ValueError, "foo");
|
201 |
+
throw py::error_already_set();
|
202 |
+
});
|
203 |
+
|
204 |
+
m.def("python_call_in_destructor", [](const py::dict &d) {
|
205 |
+
bool retval = false;
|
206 |
+
try {
|
207 |
+
PythonCallInDestructor set_dict_in_destructor(d);
|
208 |
+
PyErr_SetString(PyExc_ValueError, "foo");
|
209 |
+
throw py::error_already_set();
|
210 |
+
} catch (const py::error_already_set&) {
|
211 |
+
retval = true;
|
212 |
+
}
|
213 |
+
return retval;
|
214 |
+
});
|
215 |
+
|
216 |
+
m.def("python_alreadyset_in_destructor", [](const py::str &s) {
|
217 |
+
PythonAlreadySetInDestructor alreadyset_in_destructor(s);
|
218 |
+
return true;
|
219 |
+
});
|
220 |
+
|
221 |
+
// test_nested_throws
|
222 |
+
m.def("try_catch",
|
223 |
+
[m](const py::object &exc_type, const py::function &f, const py::args &args) {
|
224 |
+
try {
|
225 |
+
f(*args);
|
226 |
+
} catch (py::error_already_set &ex) {
|
227 |
+
if (ex.matches(exc_type))
|
228 |
+
py::print(ex.what());
|
229 |
+
else
|
230 |
+
throw;
|
231 |
+
}
|
232 |
+
});
|
233 |
+
|
234 |
+
// Test repr that cannot be displayed
|
235 |
+
m.def("simple_bool_passthrough", [](bool x) {return x;});
|
236 |
+
|
237 |
+
m.def("throw_should_be_translated_to_key_error", []() { throw shared_exception(); });
|
238 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_exceptions.h
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
#include "pybind11_tests.h"
|
3 |
+
#include <stdexcept>
|
4 |
+
|
5 |
+
// shared exceptions for cross_module_tests
|
6 |
+
|
7 |
+
class PYBIND11_EXPORT_EXCEPTION shared_exception : public pybind11::builtin_exception {
|
8 |
+
public:
|
9 |
+
using builtin_exception::builtin_exception;
|
10 |
+
explicit shared_exception() : shared_exception("") {}
|
11 |
+
void set_error() const override { PyErr_SetString(PyExc_RuntimeError, what()); }
|
12 |
+
};
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_exceptions.py
ADDED
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import sys
|
3 |
+
|
4 |
+
import pytest
|
5 |
+
|
6 |
+
import env # noqa: F401
|
7 |
+
|
8 |
+
from pybind11_tests import exceptions as m
|
9 |
+
import pybind11_cross_module_tests as cm
|
10 |
+
|
11 |
+
|
12 |
+
def test_std_exception(msg):
|
13 |
+
with pytest.raises(RuntimeError) as excinfo:
|
14 |
+
m.throw_std_exception()
|
15 |
+
assert msg(excinfo.value) == "This exception was intentionally thrown."
|
16 |
+
|
17 |
+
|
18 |
+
def test_error_already_set(msg):
|
19 |
+
with pytest.raises(RuntimeError) as excinfo:
|
20 |
+
m.throw_already_set(False)
|
21 |
+
assert msg(excinfo.value) == "Unknown internal error occurred"
|
22 |
+
|
23 |
+
with pytest.raises(ValueError) as excinfo:
|
24 |
+
m.throw_already_set(True)
|
25 |
+
assert msg(excinfo.value) == "foo"
|
26 |
+
|
27 |
+
|
28 |
+
def test_cross_module_exceptions():
|
29 |
+
with pytest.raises(RuntimeError) as excinfo:
|
30 |
+
cm.raise_runtime_error()
|
31 |
+
assert str(excinfo.value) == "My runtime error"
|
32 |
+
|
33 |
+
with pytest.raises(ValueError) as excinfo:
|
34 |
+
cm.raise_value_error()
|
35 |
+
assert str(excinfo.value) == "My value error"
|
36 |
+
|
37 |
+
with pytest.raises(ValueError) as excinfo:
|
38 |
+
cm.throw_pybind_value_error()
|
39 |
+
assert str(excinfo.value) == "pybind11 value error"
|
40 |
+
|
41 |
+
with pytest.raises(TypeError) as excinfo:
|
42 |
+
cm.throw_pybind_type_error()
|
43 |
+
assert str(excinfo.value) == "pybind11 type error"
|
44 |
+
|
45 |
+
with pytest.raises(StopIteration) as excinfo:
|
46 |
+
cm.throw_stop_iteration()
|
47 |
+
|
48 |
+
|
49 |
+
# TODO: FIXME
|
50 |
+
@pytest.mark.xfail(
|
51 |
+
"env.PYPY and env.MACOS",
|
52 |
+
raises=RuntimeError,
|
53 |
+
reason="Expected failure with PyPy and libc++ (Issue #2847 & PR #2999)",
|
54 |
+
)
|
55 |
+
def test_cross_module_exception_translator():
|
56 |
+
with pytest.raises(KeyError):
|
57 |
+
# translator registered in cross_module_tests
|
58 |
+
m.throw_should_be_translated_to_key_error()
|
59 |
+
|
60 |
+
|
61 |
+
def test_python_call_in_catch():
|
62 |
+
d = {}
|
63 |
+
assert m.python_call_in_destructor(d) is True
|
64 |
+
assert d["good"] is True
|
65 |
+
|
66 |
+
|
67 |
+
def ignore_pytest_unraisable_warning(f):
|
68 |
+
unraisable = "PytestUnraisableExceptionWarning"
|
69 |
+
if hasattr(pytest, unraisable): # Python >= 3.8 and pytest >= 6
|
70 |
+
dec = pytest.mark.filterwarnings("ignore::pytest.{}".format(unraisable))
|
71 |
+
return dec(f)
|
72 |
+
else:
|
73 |
+
return f
|
74 |
+
|
75 |
+
|
76 |
+
@ignore_pytest_unraisable_warning
|
77 |
+
def test_python_alreadyset_in_destructor(monkeypatch, capsys):
|
78 |
+
hooked = False
|
79 |
+
triggered = [False] # mutable, so Python 2.7 closure can modify it
|
80 |
+
|
81 |
+
if hasattr(sys, "unraisablehook"): # Python 3.8+
|
82 |
+
hooked = True
|
83 |
+
# Don't take `sys.unraisablehook`, as that's overwritten by pytest
|
84 |
+
default_hook = sys.__unraisablehook__
|
85 |
+
|
86 |
+
def hook(unraisable_hook_args):
|
87 |
+
exc_type, exc_value, exc_tb, err_msg, obj = unraisable_hook_args
|
88 |
+
if obj == "already_set demo":
|
89 |
+
triggered[0] = True
|
90 |
+
default_hook(unraisable_hook_args)
|
91 |
+
return
|
92 |
+
|
93 |
+
# Use monkeypatch so pytest can apply and remove the patch as appropriate
|
94 |
+
monkeypatch.setattr(sys, "unraisablehook", hook)
|
95 |
+
|
96 |
+
assert m.python_alreadyset_in_destructor("already_set demo") is True
|
97 |
+
if hooked:
|
98 |
+
assert triggered[0] is True
|
99 |
+
|
100 |
+
_, captured_stderr = capsys.readouterr()
|
101 |
+
# Error message is different in Python 2 and 3, check for words that appear in both
|
102 |
+
assert "ignored" in captured_stderr and "already_set demo" in captured_stderr
|
103 |
+
|
104 |
+
|
105 |
+
def test_exception_matches():
|
106 |
+
assert m.exception_matches()
|
107 |
+
assert m.exception_matches_base()
|
108 |
+
assert m.modulenotfound_exception_matches_base()
|
109 |
+
|
110 |
+
|
111 |
+
def test_custom(msg):
|
112 |
+
# Can we catch a MyException?
|
113 |
+
with pytest.raises(m.MyException) as excinfo:
|
114 |
+
m.throws1()
|
115 |
+
assert msg(excinfo.value) == "this error should go to a custom type"
|
116 |
+
|
117 |
+
# Can we translate to standard Python exceptions?
|
118 |
+
with pytest.raises(RuntimeError) as excinfo:
|
119 |
+
m.throws2()
|
120 |
+
assert msg(excinfo.value) == "this error should go to a standard Python exception"
|
121 |
+
|
122 |
+
# Can we handle unknown exceptions?
|
123 |
+
with pytest.raises(RuntimeError) as excinfo:
|
124 |
+
m.throws3()
|
125 |
+
assert msg(excinfo.value) == "Caught an unknown exception!"
|
126 |
+
|
127 |
+
# Can we delegate to another handler by rethrowing?
|
128 |
+
with pytest.raises(m.MyException) as excinfo:
|
129 |
+
m.throws4()
|
130 |
+
assert msg(excinfo.value) == "this error is rethrown"
|
131 |
+
|
132 |
+
# Can we fall-through to the default handler?
|
133 |
+
with pytest.raises(RuntimeError) as excinfo:
|
134 |
+
m.throws_logic_error()
|
135 |
+
assert (
|
136 |
+
msg(excinfo.value) == "this error should fall through to the standard handler"
|
137 |
+
)
|
138 |
+
|
139 |
+
# OverFlow error translation.
|
140 |
+
with pytest.raises(OverflowError) as excinfo:
|
141 |
+
m.throws_overflow_error()
|
142 |
+
|
143 |
+
# Can we handle a helper-declared exception?
|
144 |
+
with pytest.raises(m.MyException5) as excinfo:
|
145 |
+
m.throws5()
|
146 |
+
assert msg(excinfo.value) == "this is a helper-defined translated exception"
|
147 |
+
|
148 |
+
# Exception subclassing:
|
149 |
+
with pytest.raises(m.MyException5) as excinfo:
|
150 |
+
m.throws5_1()
|
151 |
+
assert msg(excinfo.value) == "MyException5 subclass"
|
152 |
+
assert isinstance(excinfo.value, m.MyException5_1)
|
153 |
+
|
154 |
+
with pytest.raises(m.MyException5_1) as excinfo:
|
155 |
+
m.throws5_1()
|
156 |
+
assert msg(excinfo.value) == "MyException5 subclass"
|
157 |
+
|
158 |
+
with pytest.raises(m.MyException5) as excinfo:
|
159 |
+
try:
|
160 |
+
m.throws5()
|
161 |
+
except m.MyException5_1:
|
162 |
+
raise RuntimeError("Exception error: caught child from parent")
|
163 |
+
assert msg(excinfo.value) == "this is a helper-defined translated exception"
|
164 |
+
|
165 |
+
|
166 |
+
def test_nested_throws(capture):
|
167 |
+
"""Tests nested (e.g. C++ -> Python -> C++) exception handling"""
|
168 |
+
|
169 |
+
def throw_myex():
|
170 |
+
raise m.MyException("nested error")
|
171 |
+
|
172 |
+
def throw_myex5():
|
173 |
+
raise m.MyException5("nested error 5")
|
174 |
+
|
175 |
+
# In the comments below, the exception is caught in the first step, thrown in the last step
|
176 |
+
|
177 |
+
# C++ -> Python
|
178 |
+
with capture:
|
179 |
+
m.try_catch(m.MyException5, throw_myex5)
|
180 |
+
assert str(capture).startswith("MyException5: nested error 5")
|
181 |
+
|
182 |
+
# Python -> C++ -> Python
|
183 |
+
with pytest.raises(m.MyException) as excinfo:
|
184 |
+
m.try_catch(m.MyException5, throw_myex)
|
185 |
+
assert str(excinfo.value) == "nested error"
|
186 |
+
|
187 |
+
def pycatch(exctype, f, *args):
|
188 |
+
try:
|
189 |
+
f(*args)
|
190 |
+
except m.MyException as e:
|
191 |
+
print(e)
|
192 |
+
|
193 |
+
# C++ -> Python -> C++ -> Python
|
194 |
+
with capture:
|
195 |
+
m.try_catch(
|
196 |
+
m.MyException5,
|
197 |
+
pycatch,
|
198 |
+
m.MyException,
|
199 |
+
m.try_catch,
|
200 |
+
m.MyException,
|
201 |
+
throw_myex5,
|
202 |
+
)
|
203 |
+
assert str(capture).startswith("MyException5: nested error 5")
|
204 |
+
|
205 |
+
# C++ -> Python -> C++
|
206 |
+
with capture:
|
207 |
+
m.try_catch(m.MyException, pycatch, m.MyException5, m.throws4)
|
208 |
+
assert capture == "this error is rethrown"
|
209 |
+
|
210 |
+
# Python -> C++ -> Python -> C++
|
211 |
+
with pytest.raises(m.MyException5) as excinfo:
|
212 |
+
m.try_catch(m.MyException, pycatch, m.MyException, m.throws5)
|
213 |
+
assert str(excinfo.value) == "this is a helper-defined translated exception"
|
214 |
+
|
215 |
+
|
216 |
+
# This can often happen if you wrap a pybind11 class in a Python wrapper
|
217 |
+
def test_invalid_repr():
|
218 |
+
class MyRepr(object):
|
219 |
+
def __repr__(self):
|
220 |
+
raise AttributeError("Example error")
|
221 |
+
|
222 |
+
with pytest.raises(TypeError):
|
223 |
+
m.simple_bool_passthrough(MyRepr())
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_factory_constructors.cpp
ADDED
@@ -0,0 +1,382 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_factory_constructors.cpp -- tests construction from a factory function
|
3 |
+
via py::init_factory()
|
4 |
+
|
5 |
+
Copyright (c) 2017 Jason Rhinelander <[email protected]>
|
6 |
+
|
7 |
+
All rights reserved. Use of this source code is governed by a
|
8 |
+
BSD-style license that can be found in the LICENSE file.
|
9 |
+
*/
|
10 |
+
|
11 |
+
#include "constructor_stats.h"
|
12 |
+
#include "pybind11_tests.h"
|
13 |
+
#include <cmath>
|
14 |
+
#include <new>
|
15 |
+
#include <utility>
|
16 |
+
|
17 |
+
// Classes for testing python construction via C++ factory function:
|
18 |
+
// Not publicly constructible, copyable, or movable:
|
19 |
+
class TestFactory1 {
|
20 |
+
friend class TestFactoryHelper;
|
21 |
+
TestFactory1() : value("(empty)") { print_default_created(this); }
|
22 |
+
TestFactory1(int v) : value(std::to_string(v)) { print_created(this, value); }
|
23 |
+
TestFactory1(std::string v) : value(std::move(v)) { print_created(this, value); }
|
24 |
+
public:
|
25 |
+
std::string value;
|
26 |
+
TestFactory1(TestFactory1 &&) = delete;
|
27 |
+
TestFactory1(const TestFactory1 &) = delete;
|
28 |
+
TestFactory1 &operator=(TestFactory1 &&) = delete;
|
29 |
+
TestFactory1 &operator=(const TestFactory1 &) = delete;
|
30 |
+
~TestFactory1() { print_destroyed(this); }
|
31 |
+
};
|
32 |
+
// Non-public construction, but moveable:
|
33 |
+
class TestFactory2 {
|
34 |
+
friend class TestFactoryHelper;
|
35 |
+
TestFactory2() : value("(empty2)") { print_default_created(this); }
|
36 |
+
TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); }
|
37 |
+
TestFactory2(std::string v) : value(std::move(v)) { print_created(this, value); }
|
38 |
+
public:
|
39 |
+
TestFactory2(TestFactory2 &&m) noexcept {
|
40 |
+
value = std::move(m.value);
|
41 |
+
print_move_created(this);
|
42 |
+
}
|
43 |
+
TestFactory2 &operator=(TestFactory2 &&m) noexcept {
|
44 |
+
value = std::move(m.value);
|
45 |
+
print_move_assigned(this);
|
46 |
+
return *this;
|
47 |
+
}
|
48 |
+
std::string value;
|
49 |
+
~TestFactory2() { print_destroyed(this); }
|
50 |
+
};
|
51 |
+
// Mixed direct/factory construction:
|
52 |
+
class TestFactory3 {
|
53 |
+
protected:
|
54 |
+
friend class TestFactoryHelper;
|
55 |
+
TestFactory3() : value("(empty3)") { print_default_created(this); }
|
56 |
+
TestFactory3(int v) : value(std::to_string(v)) { print_created(this, value); }
|
57 |
+
public:
|
58 |
+
TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); }
|
59 |
+
TestFactory3(TestFactory3 &&m) noexcept {
|
60 |
+
value = std::move(m.value);
|
61 |
+
print_move_created(this);
|
62 |
+
}
|
63 |
+
TestFactory3 &operator=(TestFactory3 &&m) noexcept {
|
64 |
+
value = std::move(m.value);
|
65 |
+
print_move_assigned(this);
|
66 |
+
return *this;
|
67 |
+
}
|
68 |
+
std::string value;
|
69 |
+
virtual ~TestFactory3() { print_destroyed(this); }
|
70 |
+
};
|
71 |
+
// Inheritance test
|
72 |
+
class TestFactory4 : public TestFactory3 {
|
73 |
+
public:
|
74 |
+
TestFactory4() : TestFactory3() { print_default_created(this); }
|
75 |
+
TestFactory4(int v) : TestFactory3(v) { print_created(this, v); }
|
76 |
+
~TestFactory4() override { print_destroyed(this); }
|
77 |
+
};
|
78 |
+
// Another class for an invalid downcast test
|
79 |
+
class TestFactory5 : public TestFactory3 {
|
80 |
+
public:
|
81 |
+
TestFactory5(int i) : TestFactory3(i) { print_created(this, i); }
|
82 |
+
~TestFactory5() override { print_destroyed(this); }
|
83 |
+
};
|
84 |
+
|
85 |
+
class TestFactory6 {
|
86 |
+
protected:
|
87 |
+
int value;
|
88 |
+
bool alias = false;
|
89 |
+
public:
|
90 |
+
TestFactory6(int i) : value{i} { print_created(this, i); }
|
91 |
+
TestFactory6(TestFactory6 &&f) noexcept {
|
92 |
+
print_move_created(this);
|
93 |
+
value = f.value;
|
94 |
+
alias = f.alias;
|
95 |
+
}
|
96 |
+
TestFactory6(const TestFactory6 &f) { print_copy_created(this); value = f.value; alias = f.alias; }
|
97 |
+
virtual ~TestFactory6() { print_destroyed(this); }
|
98 |
+
virtual int get() { return value; }
|
99 |
+
bool has_alias() const { return alias; }
|
100 |
+
};
|
101 |
+
class PyTF6 : public TestFactory6 {
|
102 |
+
public:
|
103 |
+
// Special constructor that allows the factory to construct a PyTF6 from a TestFactory6 only
|
104 |
+
// when an alias is needed:
|
105 |
+
PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) { alias = true; print_created(this, "move", value); }
|
106 |
+
PyTF6(int i) : TestFactory6(i) { alias = true; print_created(this, i); }
|
107 |
+
PyTF6(PyTF6 &&f) noexcept : TestFactory6(std::move(f)) { print_move_created(this); }
|
108 |
+
PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); }
|
109 |
+
PyTF6(std::string s) : TestFactory6((int) s.size()) { alias = true; print_created(this, s); }
|
110 |
+
~PyTF6() override { print_destroyed(this); }
|
111 |
+
int get() override { PYBIND11_OVERRIDE(int, TestFactory6, get, /*no args*/); }
|
112 |
+
};
|
113 |
+
|
114 |
+
class TestFactory7 {
|
115 |
+
protected:
|
116 |
+
int value;
|
117 |
+
bool alias = false;
|
118 |
+
public:
|
119 |
+
TestFactory7(int i) : value{i} { print_created(this, i); }
|
120 |
+
TestFactory7(TestFactory7 &&f) noexcept {
|
121 |
+
print_move_created(this);
|
122 |
+
value = f.value;
|
123 |
+
alias = f.alias;
|
124 |
+
}
|
125 |
+
TestFactory7(const TestFactory7 &f) { print_copy_created(this); value = f.value; alias = f.alias; }
|
126 |
+
virtual ~TestFactory7() { print_destroyed(this); }
|
127 |
+
virtual int get() { return value; }
|
128 |
+
bool has_alias() const { return alias; }
|
129 |
+
};
|
130 |
+
class PyTF7 : public TestFactory7 {
|
131 |
+
public:
|
132 |
+
PyTF7(int i) : TestFactory7(i) { alias = true; print_created(this, i); }
|
133 |
+
PyTF7(PyTF7 &&f) noexcept : TestFactory7(std::move(f)) { print_move_created(this); }
|
134 |
+
PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); }
|
135 |
+
~PyTF7() override { print_destroyed(this); }
|
136 |
+
int get() override { PYBIND11_OVERRIDE(int, TestFactory7, get, /*no args*/); }
|
137 |
+
};
|
138 |
+
|
139 |
+
|
140 |
+
class TestFactoryHelper {
|
141 |
+
public:
|
142 |
+
// Non-movable, non-copyable type:
|
143 |
+
// Return via pointer:
|
144 |
+
static TestFactory1 *construct1() { return new TestFactory1(); }
|
145 |
+
// Holder:
|
146 |
+
static std::unique_ptr<TestFactory1> construct1(int a) { return std::unique_ptr<TestFactory1>(new TestFactory1(a)); }
|
147 |
+
// pointer again
|
148 |
+
static TestFactory1 *construct1_string(std::string a) {
|
149 |
+
return new TestFactory1(std::move(a));
|
150 |
+
}
|
151 |
+
|
152 |
+
// Moveable type:
|
153 |
+
// pointer:
|
154 |
+
static TestFactory2 *construct2() { return new TestFactory2(); }
|
155 |
+
// holder:
|
156 |
+
static std::unique_ptr<TestFactory2> construct2(int a) { return std::unique_ptr<TestFactory2>(new TestFactory2(a)); }
|
157 |
+
// by value moving:
|
158 |
+
static TestFactory2 construct2(std::string a) { return TestFactory2(std::move(a)); }
|
159 |
+
|
160 |
+
// shared_ptr holder type:
|
161 |
+
// pointer:
|
162 |
+
static TestFactory3 *construct3() { return new TestFactory3(); }
|
163 |
+
// holder:
|
164 |
+
static std::shared_ptr<TestFactory3> construct3(int a) { return std::shared_ptr<TestFactory3>(new TestFactory3(a)); }
|
165 |
+
};
|
166 |
+
|
167 |
+
TEST_SUBMODULE(factory_constructors, m) {
|
168 |
+
|
169 |
+
// Define various trivial types to allow simpler overload resolution:
|
170 |
+
py::module_ m_tag = m.def_submodule("tag");
|
171 |
+
#define MAKE_TAG_TYPE(Name) \
|
172 |
+
struct Name##_tag {}; \
|
173 |
+
py::class_<Name##_tag>(m_tag, #Name "_tag").def(py::init<>()); \
|
174 |
+
m_tag.attr(#Name) = py::cast(Name##_tag{})
|
175 |
+
MAKE_TAG_TYPE(pointer);
|
176 |
+
MAKE_TAG_TYPE(unique_ptr);
|
177 |
+
MAKE_TAG_TYPE(move);
|
178 |
+
MAKE_TAG_TYPE(shared_ptr);
|
179 |
+
MAKE_TAG_TYPE(derived);
|
180 |
+
MAKE_TAG_TYPE(TF4);
|
181 |
+
MAKE_TAG_TYPE(TF5);
|
182 |
+
MAKE_TAG_TYPE(null_ptr);
|
183 |
+
MAKE_TAG_TYPE(null_unique_ptr);
|
184 |
+
MAKE_TAG_TYPE(null_shared_ptr);
|
185 |
+
MAKE_TAG_TYPE(base);
|
186 |
+
MAKE_TAG_TYPE(invalid_base);
|
187 |
+
MAKE_TAG_TYPE(alias);
|
188 |
+
MAKE_TAG_TYPE(unaliasable);
|
189 |
+
MAKE_TAG_TYPE(mixed);
|
190 |
+
|
191 |
+
// test_init_factory_basic, test_bad_type
|
192 |
+
py::class_<TestFactory1>(m, "TestFactory1")
|
193 |
+
.def(py::init([](unique_ptr_tag, int v) { return TestFactoryHelper::construct1(v); }))
|
194 |
+
.def(py::init(&TestFactoryHelper::construct1_string)) // raw function pointer
|
195 |
+
.def(py::init([](pointer_tag) { return TestFactoryHelper::construct1(); }))
|
196 |
+
.def(py::init([](py::handle, int v, py::handle) { return TestFactoryHelper::construct1(v); }))
|
197 |
+
.def_readwrite("value", &TestFactory1::value)
|
198 |
+
;
|
199 |
+
py::class_<TestFactory2>(m, "TestFactory2")
|
200 |
+
.def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); }))
|
201 |
+
.def(py::init([](unique_ptr_tag, std::string v) {
|
202 |
+
return TestFactoryHelper::construct2(std::move(v));
|
203 |
+
}))
|
204 |
+
.def(py::init([](move_tag) { return TestFactoryHelper::construct2(); }))
|
205 |
+
.def_readwrite("value", &TestFactory2::value);
|
206 |
+
|
207 |
+
// Stateful & reused:
|
208 |
+
int c = 1;
|
209 |
+
auto c4a = [c](pointer_tag, TF4_tag, int a) { (void) c; return new TestFactory4(a);};
|
210 |
+
|
211 |
+
// test_init_factory_basic, test_init_factory_casting
|
212 |
+
py::class_<TestFactory3, std::shared_ptr<TestFactory3>> pyTestFactory3(m, "TestFactory3");
|
213 |
+
pyTestFactory3
|
214 |
+
.def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); }))
|
215 |
+
.def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); }));
|
216 |
+
ignoreOldStyleInitWarnings([&pyTestFactory3]() {
|
217 |
+
pyTestFactory3.def("__init__", [](TestFactory3 &self, std::string v) {
|
218 |
+
new (&self) TestFactory3(std::move(v));
|
219 |
+
}); // placement-new ctor
|
220 |
+
});
|
221 |
+
pyTestFactory3
|
222 |
+
// factories returning a derived type:
|
223 |
+
.def(py::init(c4a)) // derived ptr
|
224 |
+
.def(py::init([](pointer_tag, TF5_tag, int a) { return new TestFactory5(a); }))
|
225 |
+
// derived shared ptr:
|
226 |
+
.def(py::init([](shared_ptr_tag, TF4_tag, int a) { return std::make_shared<TestFactory4>(a); }))
|
227 |
+
.def(py::init([](shared_ptr_tag, TF5_tag, int a) { return std::make_shared<TestFactory5>(a); }))
|
228 |
+
|
229 |
+
// Returns nullptr:
|
230 |
+
.def(py::init([](null_ptr_tag) { return (TestFactory3 *) nullptr; }))
|
231 |
+
.def(py::init([](null_unique_ptr_tag) { return std::unique_ptr<TestFactory3>(); }))
|
232 |
+
.def(py::init([](null_shared_ptr_tag) { return std::shared_ptr<TestFactory3>(); }))
|
233 |
+
|
234 |
+
.def_readwrite("value", &TestFactory3::value)
|
235 |
+
;
|
236 |
+
|
237 |
+
// test_init_factory_casting
|
238 |
+
py::class_<TestFactory4, TestFactory3, std::shared_ptr<TestFactory4>>(m, "TestFactory4")
|
239 |
+
.def(py::init(c4a)) // pointer
|
240 |
+
;
|
241 |
+
|
242 |
+
// Doesn't need to be registered, but registering makes getting ConstructorStats easier:
|
243 |
+
py::class_<TestFactory5, TestFactory3, std::shared_ptr<TestFactory5>>(m, "TestFactory5");
|
244 |
+
|
245 |
+
// test_init_factory_alias
|
246 |
+
// Alias testing
|
247 |
+
py::class_<TestFactory6, PyTF6>(m, "TestFactory6")
|
248 |
+
.def(py::init([](base_tag, int i) { return TestFactory6(i); }))
|
249 |
+
.def(py::init([](alias_tag, int i) { return PyTF6(i); }))
|
250 |
+
.def(py::init([](alias_tag, std::string s) { return PyTF6(std::move(s)); }))
|
251 |
+
.def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); }))
|
252 |
+
.def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); }))
|
253 |
+
.def(py::init(
|
254 |
+
[](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); }))
|
255 |
+
|
256 |
+
.def("get", &TestFactory6::get)
|
257 |
+
.def("has_alias", &TestFactory6::has_alias)
|
258 |
+
|
259 |
+
.def_static(
|
260 |
+
"get_cstats", &ConstructorStats::get<TestFactory6>, py::return_value_policy::reference)
|
261 |
+
.def_static(
|
262 |
+
"get_alias_cstats", &ConstructorStats::get<PyTF6>, py::return_value_policy::reference);
|
263 |
+
|
264 |
+
// test_init_factory_dual
|
265 |
+
// Separate alias constructor testing
|
266 |
+
py::class_<TestFactory7, PyTF7, std::shared_ptr<TestFactory7>>(m, "TestFactory7")
|
267 |
+
.def(py::init([](int i) { return TestFactory7(i); }, [](int i) { return PyTF7(i); }))
|
268 |
+
.def(py::init([](pointer_tag, int i) { return new TestFactory7(i); },
|
269 |
+
[](pointer_tag, int i) { return new PyTF7(i); }))
|
270 |
+
.def(py::init([](mixed_tag, int i) { return new TestFactory7(i); },
|
271 |
+
[](mixed_tag, int i) { return PyTF7(i); }))
|
272 |
+
.def(py::init([](mixed_tag, const std::string &s) { return TestFactory7((int) s.size()); },
|
273 |
+
[](mixed_tag, const std::string &s) { return new PyTF7((int) s.size()); }))
|
274 |
+
.def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory7(i); },
|
275 |
+
[](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); }))
|
276 |
+
.def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF7(i); },
|
277 |
+
[](alias_tag, pointer_tag, int i) { return new PyTF7(10 * i); }))
|
278 |
+
.def(py::init(
|
279 |
+
[](shared_ptr_tag, base_tag, int i) { return std::make_shared<TestFactory7>(i); },
|
280 |
+
[](shared_ptr_tag, base_tag, int i) {
|
281 |
+
auto *p = new PyTF7(i);
|
282 |
+
return std::shared_ptr<TestFactory7>(p);
|
283 |
+
}))
|
284 |
+
.def(py::init([](shared_ptr_tag,
|
285 |
+
invalid_base_tag,
|
286 |
+
int i) { return std::make_shared<TestFactory7>(i); },
|
287 |
+
[](shared_ptr_tag, invalid_base_tag, int i) {
|
288 |
+
return std::make_shared<TestFactory7>(i);
|
289 |
+
})) // <-- invalid alias factory
|
290 |
+
|
291 |
+
.def("get", &TestFactory7::get)
|
292 |
+
.def("has_alias", &TestFactory7::has_alias)
|
293 |
+
|
294 |
+
.def_static(
|
295 |
+
"get_cstats", &ConstructorStats::get<TestFactory7>, py::return_value_policy::reference)
|
296 |
+
.def_static(
|
297 |
+
"get_alias_cstats", &ConstructorStats::get<PyTF7>, py::return_value_policy::reference);
|
298 |
+
|
299 |
+
// test_placement_new_alternative
|
300 |
+
// Class with a custom new operator but *without* a placement new operator (issue #948)
|
301 |
+
class NoPlacementNew {
|
302 |
+
public:
|
303 |
+
NoPlacementNew(int i) : i(i) { }
|
304 |
+
static void *operator new(std::size_t s) {
|
305 |
+
auto *p = ::operator new(s);
|
306 |
+
py::print("operator new called, returning", reinterpret_cast<uintptr_t>(p));
|
307 |
+
return p;
|
308 |
+
}
|
309 |
+
static void operator delete(void *p) {
|
310 |
+
py::print("operator delete called on", reinterpret_cast<uintptr_t>(p));
|
311 |
+
::operator delete(p);
|
312 |
+
}
|
313 |
+
int i;
|
314 |
+
};
|
315 |
+
// As of 2.2, `py::init<args>` no longer requires placement new
|
316 |
+
py::class_<NoPlacementNew>(m, "NoPlacementNew")
|
317 |
+
.def(py::init<int>())
|
318 |
+
.def(py::init([]() { return new NoPlacementNew(100); }))
|
319 |
+
.def_readwrite("i", &NoPlacementNew::i)
|
320 |
+
;
|
321 |
+
|
322 |
+
|
323 |
+
// test_reallocations
|
324 |
+
// Class that has verbose operator_new/operator_delete calls
|
325 |
+
struct NoisyAlloc {
|
326 |
+
NoisyAlloc(const NoisyAlloc &) = default;
|
327 |
+
NoisyAlloc(int i) { py::print(py::str("NoisyAlloc(int {})").format(i)); }
|
328 |
+
NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); }
|
329 |
+
~NoisyAlloc() { py::print("~NoisyAlloc()"); }
|
330 |
+
|
331 |
+
static void *operator new(size_t s) { py::print("noisy new"); return ::operator new(s); }
|
332 |
+
static void *operator new(size_t, void *p) { py::print("noisy placement new"); return p; }
|
333 |
+
static void operator delete(void *p, size_t) { py::print("noisy delete"); ::operator delete(p); }
|
334 |
+
static void operator delete(void *, void *) { py::print("noisy placement delete"); }
|
335 |
+
#if defined(_MSC_VER) && _MSC_VER < 1910
|
336 |
+
// MSVC 2015 bug: the above "noisy delete" isn't invoked (fixed in MSVC 2017)
|
337 |
+
static void operator delete(void *p) { py::print("noisy delete"); ::operator delete(p); }
|
338 |
+
#endif
|
339 |
+
};
|
340 |
+
|
341 |
+
|
342 |
+
py::class_<NoisyAlloc> pyNoisyAlloc(m, "NoisyAlloc");
|
343 |
+
// Since these overloads have the same number of arguments, the dispatcher will try each of
|
344 |
+
// them until the arguments convert. Thus we can get a pre-allocation here when passing a
|
345 |
+
// single non-integer:
|
346 |
+
ignoreOldStyleInitWarnings([&pyNoisyAlloc]() {
|
347 |
+
pyNoisyAlloc.def("__init__", [](NoisyAlloc *a, int i) { new (a) NoisyAlloc(i); }); // Regular constructor, runs first, requires preallocation
|
348 |
+
});
|
349 |
+
|
350 |
+
pyNoisyAlloc.def(py::init([](double d) { return new NoisyAlloc(d); }));
|
351 |
+
|
352 |
+
// The two-argument version: first the factory pointer overload.
|
353 |
+
pyNoisyAlloc.def(py::init([](int i, int) { return new NoisyAlloc(i); }));
|
354 |
+
// Return-by-value:
|
355 |
+
pyNoisyAlloc.def(py::init([](double d, int) { return NoisyAlloc(d); }));
|
356 |
+
// Old-style placement new init; requires preallocation
|
357 |
+
ignoreOldStyleInitWarnings([&pyNoisyAlloc]() {
|
358 |
+
pyNoisyAlloc.def("__init__", [](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); });
|
359 |
+
});
|
360 |
+
// Requires deallocation of previous overload preallocated value:
|
361 |
+
pyNoisyAlloc.def(py::init([](int i, double) { return new NoisyAlloc(i); }));
|
362 |
+
// Regular again: requires yet another preallocation
|
363 |
+
ignoreOldStyleInitWarnings([&pyNoisyAlloc]() {
|
364 |
+
pyNoisyAlloc.def(
|
365 |
+
"__init__", [](NoisyAlloc &a, int i, const std::string &) { new (&a) NoisyAlloc(i); });
|
366 |
+
});
|
367 |
+
|
368 |
+
// static_assert testing (the following def's should all fail with appropriate compilation errors):
|
369 |
+
#if 0
|
370 |
+
struct BadF1Base {};
|
371 |
+
struct BadF1 : BadF1Base {};
|
372 |
+
struct PyBadF1 : BadF1 {};
|
373 |
+
py::class_<BadF1, PyBadF1, std::shared_ptr<BadF1>> bf1(m, "BadF1");
|
374 |
+
// wrapped factory function must return a compatible pointer, holder, or value
|
375 |
+
bf1.def(py::init([]() { return 3; }));
|
376 |
+
// incompatible factory function pointer return type
|
377 |
+
bf1.def(py::init([]() { static int three = 3; return &three; }));
|
378 |
+
// incompatible factory function std::shared_ptr<T> return type: cannot convert shared_ptr<T> to holder
|
379 |
+
// (non-polymorphic base)
|
380 |
+
bf1.def(py::init([]() { return std::shared_ptr<BadF1Base>(new BadF1()); }));
|
381 |
+
#endif
|
382 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_factory_constructors.py
ADDED
@@ -0,0 +1,520 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
import re
|
4 |
+
|
5 |
+
import env # noqa: F401
|
6 |
+
|
7 |
+
from pybind11_tests import factory_constructors as m
|
8 |
+
from pybind11_tests.factory_constructors import tag
|
9 |
+
from pybind11_tests import ConstructorStats
|
10 |
+
|
11 |
+
|
12 |
+
def test_init_factory_basic():
|
13 |
+
"""Tests py::init_factory() wrapper around various ways of returning the object"""
|
14 |
+
|
15 |
+
cstats = [
|
16 |
+
ConstructorStats.get(c)
|
17 |
+
for c in [m.TestFactory1, m.TestFactory2, m.TestFactory3]
|
18 |
+
]
|
19 |
+
cstats[0].alive() # force gc
|
20 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
21 |
+
|
22 |
+
x1 = m.TestFactory1(tag.unique_ptr, 3)
|
23 |
+
assert x1.value == "3"
|
24 |
+
y1 = m.TestFactory1(tag.pointer)
|
25 |
+
assert y1.value == "(empty)"
|
26 |
+
z1 = m.TestFactory1("hi!")
|
27 |
+
assert z1.value == "hi!"
|
28 |
+
|
29 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 3
|
30 |
+
|
31 |
+
x2 = m.TestFactory2(tag.move)
|
32 |
+
assert x2.value == "(empty2)"
|
33 |
+
y2 = m.TestFactory2(tag.pointer, 7)
|
34 |
+
assert y2.value == "7"
|
35 |
+
z2 = m.TestFactory2(tag.unique_ptr, "hi again")
|
36 |
+
assert z2.value == "hi again"
|
37 |
+
|
38 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 6
|
39 |
+
|
40 |
+
x3 = m.TestFactory3(tag.shared_ptr)
|
41 |
+
assert x3.value == "(empty3)"
|
42 |
+
y3 = m.TestFactory3(tag.pointer, 42)
|
43 |
+
assert y3.value == "42"
|
44 |
+
z3 = m.TestFactory3("bye")
|
45 |
+
assert z3.value == "bye"
|
46 |
+
|
47 |
+
for null_ptr_kind in [tag.null_ptr, tag.null_unique_ptr, tag.null_shared_ptr]:
|
48 |
+
with pytest.raises(TypeError) as excinfo:
|
49 |
+
m.TestFactory3(null_ptr_kind)
|
50 |
+
assert (
|
51 |
+
str(excinfo.value) == "pybind11::init(): factory function returned nullptr"
|
52 |
+
)
|
53 |
+
|
54 |
+
assert [i.alive() for i in cstats] == [3, 3, 3]
|
55 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 9
|
56 |
+
|
57 |
+
del x1, y2, y3, z3
|
58 |
+
assert [i.alive() for i in cstats] == [2, 2, 1]
|
59 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 5
|
60 |
+
del x2, x3, y1, z1, z2
|
61 |
+
assert [i.alive() for i in cstats] == [0, 0, 0]
|
62 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
63 |
+
|
64 |
+
assert [i.values() for i in cstats] == [
|
65 |
+
["3", "hi!"],
|
66 |
+
["7", "hi again"],
|
67 |
+
["42", "bye"],
|
68 |
+
]
|
69 |
+
assert [i.default_constructions for i in cstats] == [1, 1, 1]
|
70 |
+
|
71 |
+
|
72 |
+
def test_init_factory_signature(msg):
|
73 |
+
with pytest.raises(TypeError) as excinfo:
|
74 |
+
m.TestFactory1("invalid", "constructor", "arguments")
|
75 |
+
assert (
|
76 |
+
msg(excinfo.value)
|
77 |
+
== """
|
78 |
+
__init__(): incompatible constructor arguments. The following argument types are supported:
|
79 |
+
1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int)
|
80 |
+
2. m.factory_constructors.TestFactory1(arg0: str)
|
81 |
+
3. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.pointer_tag)
|
82 |
+
4. m.factory_constructors.TestFactory1(arg0: handle, arg1: int, arg2: handle)
|
83 |
+
|
84 |
+
Invoked with: 'invalid', 'constructor', 'arguments'
|
85 |
+
""" # noqa: E501 line too long
|
86 |
+
)
|
87 |
+
|
88 |
+
assert (
|
89 |
+
msg(m.TestFactory1.__init__.__doc__)
|
90 |
+
== """
|
91 |
+
__init__(*args, **kwargs)
|
92 |
+
Overloaded function.
|
93 |
+
|
94 |
+
1. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) -> None
|
95 |
+
|
96 |
+
2. __init__(self: m.factory_constructors.TestFactory1, arg0: str) -> None
|
97 |
+
|
98 |
+
3. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.pointer_tag) -> None
|
99 |
+
|
100 |
+
4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None
|
101 |
+
""" # noqa: E501 line too long
|
102 |
+
)
|
103 |
+
|
104 |
+
|
105 |
+
def test_init_factory_casting():
|
106 |
+
"""Tests py::init_factory() wrapper with various upcasting and downcasting returns"""
|
107 |
+
|
108 |
+
cstats = [
|
109 |
+
ConstructorStats.get(c)
|
110 |
+
for c in [m.TestFactory3, m.TestFactory4, m.TestFactory5]
|
111 |
+
]
|
112 |
+
cstats[0].alive() # force gc
|
113 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
114 |
+
|
115 |
+
# Construction from derived references:
|
116 |
+
a = m.TestFactory3(tag.pointer, tag.TF4, 4)
|
117 |
+
assert a.value == "4"
|
118 |
+
b = m.TestFactory3(tag.shared_ptr, tag.TF4, 5)
|
119 |
+
assert b.value == "5"
|
120 |
+
c = m.TestFactory3(tag.pointer, tag.TF5, 6)
|
121 |
+
assert c.value == "6"
|
122 |
+
d = m.TestFactory3(tag.shared_ptr, tag.TF5, 7)
|
123 |
+
assert d.value == "7"
|
124 |
+
|
125 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 4
|
126 |
+
|
127 |
+
# Shared a lambda with TF3:
|
128 |
+
e = m.TestFactory4(tag.pointer, tag.TF4, 8)
|
129 |
+
assert e.value == "8"
|
130 |
+
|
131 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 5
|
132 |
+
assert [i.alive() for i in cstats] == [5, 3, 2]
|
133 |
+
|
134 |
+
del a
|
135 |
+
assert [i.alive() for i in cstats] == [4, 2, 2]
|
136 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 4
|
137 |
+
|
138 |
+
del b, c, e
|
139 |
+
assert [i.alive() for i in cstats] == [1, 0, 1]
|
140 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 1
|
141 |
+
|
142 |
+
del d
|
143 |
+
assert [i.alive() for i in cstats] == [0, 0, 0]
|
144 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
145 |
+
|
146 |
+
assert [i.values() for i in cstats] == [
|
147 |
+
["4", "5", "6", "7", "8"],
|
148 |
+
["4", "5", "8"],
|
149 |
+
["6", "7"],
|
150 |
+
]
|
151 |
+
|
152 |
+
|
153 |
+
def test_init_factory_alias():
|
154 |
+
"""Tests py::init_factory() wrapper with value conversions and alias types"""
|
155 |
+
|
156 |
+
cstats = [m.TestFactory6.get_cstats(), m.TestFactory6.get_alias_cstats()]
|
157 |
+
cstats[0].alive() # force gc
|
158 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
159 |
+
|
160 |
+
a = m.TestFactory6(tag.base, 1)
|
161 |
+
assert a.get() == 1
|
162 |
+
assert not a.has_alias()
|
163 |
+
b = m.TestFactory6(tag.alias, "hi there")
|
164 |
+
assert b.get() == 8
|
165 |
+
assert b.has_alias()
|
166 |
+
c = m.TestFactory6(tag.alias, 3)
|
167 |
+
assert c.get() == 3
|
168 |
+
assert c.has_alias()
|
169 |
+
d = m.TestFactory6(tag.alias, tag.pointer, 4)
|
170 |
+
assert d.get() == 4
|
171 |
+
assert d.has_alias()
|
172 |
+
e = m.TestFactory6(tag.base, tag.pointer, 5)
|
173 |
+
assert e.get() == 5
|
174 |
+
assert not e.has_alias()
|
175 |
+
f = m.TestFactory6(tag.base, tag.alias, tag.pointer, 6)
|
176 |
+
assert f.get() == 6
|
177 |
+
assert f.has_alias()
|
178 |
+
|
179 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 6
|
180 |
+
assert [i.alive() for i in cstats] == [6, 4]
|
181 |
+
|
182 |
+
del a, b, e
|
183 |
+
assert [i.alive() for i in cstats] == [3, 3]
|
184 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 3
|
185 |
+
del f, c, d
|
186 |
+
assert [i.alive() for i in cstats] == [0, 0]
|
187 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
188 |
+
|
189 |
+
class MyTest(m.TestFactory6):
|
190 |
+
def __init__(self, *args):
|
191 |
+
m.TestFactory6.__init__(self, *args)
|
192 |
+
|
193 |
+
def get(self):
|
194 |
+
return -5 + m.TestFactory6.get(self)
|
195 |
+
|
196 |
+
# Return Class by value, moved into new alias:
|
197 |
+
z = MyTest(tag.base, 123)
|
198 |
+
assert z.get() == 118
|
199 |
+
assert z.has_alias()
|
200 |
+
|
201 |
+
# Return alias by value, moved into new alias:
|
202 |
+
y = MyTest(tag.alias, "why hello!")
|
203 |
+
assert y.get() == 5
|
204 |
+
assert y.has_alias()
|
205 |
+
|
206 |
+
# Return Class by pointer, moved into new alias then original destroyed:
|
207 |
+
x = MyTest(tag.base, tag.pointer, 47)
|
208 |
+
assert x.get() == 42
|
209 |
+
assert x.has_alias()
|
210 |
+
|
211 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 3
|
212 |
+
assert [i.alive() for i in cstats] == [3, 3]
|
213 |
+
del x, y, z
|
214 |
+
assert [i.alive() for i in cstats] == [0, 0]
|
215 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
216 |
+
|
217 |
+
assert [i.values() for i in cstats] == [
|
218 |
+
["1", "8", "3", "4", "5", "6", "123", "10", "47"],
|
219 |
+
["hi there", "3", "4", "6", "move", "123", "why hello!", "move", "47"],
|
220 |
+
]
|
221 |
+
|
222 |
+
|
223 |
+
def test_init_factory_dual():
|
224 |
+
"""Tests init factory functions with dual main/alias factory functions"""
|
225 |
+
from pybind11_tests.factory_constructors import TestFactory7
|
226 |
+
|
227 |
+
cstats = [TestFactory7.get_cstats(), TestFactory7.get_alias_cstats()]
|
228 |
+
cstats[0].alive() # force gc
|
229 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
230 |
+
|
231 |
+
class PythFactory7(TestFactory7):
|
232 |
+
def get(self):
|
233 |
+
return 100 + TestFactory7.get(self)
|
234 |
+
|
235 |
+
a1 = TestFactory7(1)
|
236 |
+
a2 = PythFactory7(2)
|
237 |
+
assert a1.get() == 1
|
238 |
+
assert a2.get() == 102
|
239 |
+
assert not a1.has_alias()
|
240 |
+
assert a2.has_alias()
|
241 |
+
|
242 |
+
b1 = TestFactory7(tag.pointer, 3)
|
243 |
+
b2 = PythFactory7(tag.pointer, 4)
|
244 |
+
assert b1.get() == 3
|
245 |
+
assert b2.get() == 104
|
246 |
+
assert not b1.has_alias()
|
247 |
+
assert b2.has_alias()
|
248 |
+
|
249 |
+
c1 = TestFactory7(tag.mixed, 5)
|
250 |
+
c2 = PythFactory7(tag.mixed, 6)
|
251 |
+
assert c1.get() == 5
|
252 |
+
assert c2.get() == 106
|
253 |
+
assert not c1.has_alias()
|
254 |
+
assert c2.has_alias()
|
255 |
+
|
256 |
+
d1 = TestFactory7(tag.base, tag.pointer, 7)
|
257 |
+
d2 = PythFactory7(tag.base, tag.pointer, 8)
|
258 |
+
assert d1.get() == 7
|
259 |
+
assert d2.get() == 108
|
260 |
+
assert not d1.has_alias()
|
261 |
+
assert d2.has_alias()
|
262 |
+
|
263 |
+
# Both return an alias; the second multiplies the value by 10:
|
264 |
+
e1 = TestFactory7(tag.alias, tag.pointer, 9)
|
265 |
+
e2 = PythFactory7(tag.alias, tag.pointer, 10)
|
266 |
+
assert e1.get() == 9
|
267 |
+
assert e2.get() == 200
|
268 |
+
assert e1.has_alias()
|
269 |
+
assert e2.has_alias()
|
270 |
+
|
271 |
+
f1 = TestFactory7(tag.shared_ptr, tag.base, 11)
|
272 |
+
f2 = PythFactory7(tag.shared_ptr, tag.base, 12)
|
273 |
+
assert f1.get() == 11
|
274 |
+
assert f2.get() == 112
|
275 |
+
assert not f1.has_alias()
|
276 |
+
assert f2.has_alias()
|
277 |
+
|
278 |
+
g1 = TestFactory7(tag.shared_ptr, tag.invalid_base, 13)
|
279 |
+
assert g1.get() == 13
|
280 |
+
assert not g1.has_alias()
|
281 |
+
with pytest.raises(TypeError) as excinfo:
|
282 |
+
PythFactory7(tag.shared_ptr, tag.invalid_base, 14)
|
283 |
+
assert (
|
284 |
+
str(excinfo.value)
|
285 |
+
== "pybind11::init(): construction failed: returned holder-wrapped instance is not an "
|
286 |
+
"alias instance"
|
287 |
+
)
|
288 |
+
|
289 |
+
assert [i.alive() for i in cstats] == [13, 7]
|
290 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 13
|
291 |
+
|
292 |
+
del a1, a2, b1, d1, e1, e2
|
293 |
+
assert [i.alive() for i in cstats] == [7, 4]
|
294 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 7
|
295 |
+
del b2, c1, c2, d2, f1, f2, g1
|
296 |
+
assert [i.alive() for i in cstats] == [0, 0]
|
297 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
298 |
+
|
299 |
+
assert [i.values() for i in cstats] == [
|
300 |
+
["1", "2", "3", "4", "5", "6", "7", "8", "9", "100", "11", "12", "13", "14"],
|
301 |
+
["2", "4", "6", "8", "9", "100", "12"],
|
302 |
+
]
|
303 |
+
|
304 |
+
|
305 |
+
def test_no_placement_new(capture):
|
306 |
+
"""Prior to 2.2, `py::init<...>` relied on the type supporting placement
|
307 |
+
new; this tests a class without placement new support."""
|
308 |
+
with capture:
|
309 |
+
a = m.NoPlacementNew(123)
|
310 |
+
|
311 |
+
found = re.search(r"^operator new called, returning (\d+)\n$", str(capture))
|
312 |
+
assert found
|
313 |
+
assert a.i == 123
|
314 |
+
with capture:
|
315 |
+
del a
|
316 |
+
pytest.gc_collect()
|
317 |
+
assert capture == "operator delete called on " + found.group(1)
|
318 |
+
|
319 |
+
with capture:
|
320 |
+
b = m.NoPlacementNew()
|
321 |
+
|
322 |
+
found = re.search(r"^operator new called, returning (\d+)\n$", str(capture))
|
323 |
+
assert found
|
324 |
+
assert b.i == 100
|
325 |
+
with capture:
|
326 |
+
del b
|
327 |
+
pytest.gc_collect()
|
328 |
+
assert capture == "operator delete called on " + found.group(1)
|
329 |
+
|
330 |
+
|
331 |
+
def test_multiple_inheritance():
|
332 |
+
class MITest(m.TestFactory1, m.TestFactory2):
|
333 |
+
def __init__(self):
|
334 |
+
m.TestFactory1.__init__(self, tag.unique_ptr, 33)
|
335 |
+
m.TestFactory2.__init__(self, tag.move)
|
336 |
+
|
337 |
+
a = MITest()
|
338 |
+
assert m.TestFactory1.value.fget(a) == "33"
|
339 |
+
assert m.TestFactory2.value.fget(a) == "(empty2)"
|
340 |
+
|
341 |
+
|
342 |
+
def create_and_destroy(*args):
|
343 |
+
a = m.NoisyAlloc(*args)
|
344 |
+
print("---")
|
345 |
+
del a
|
346 |
+
pytest.gc_collect()
|
347 |
+
|
348 |
+
|
349 |
+
def strip_comments(s):
|
350 |
+
return re.sub(r"\s+#.*", "", s)
|
351 |
+
|
352 |
+
|
353 |
+
def test_reallocation_a(capture, msg):
|
354 |
+
"""When the constructor is overloaded, previous overloads can require a preallocated value.
|
355 |
+
This test makes sure that such preallocated values only happen when they might be necessary,
|
356 |
+
and that they are deallocated properly."""
|
357 |
+
|
358 |
+
pytest.gc_collect()
|
359 |
+
|
360 |
+
with capture:
|
361 |
+
create_and_destroy(1)
|
362 |
+
assert (
|
363 |
+
msg(capture)
|
364 |
+
== """
|
365 |
+
noisy new
|
366 |
+
noisy placement new
|
367 |
+
NoisyAlloc(int 1)
|
368 |
+
---
|
369 |
+
~NoisyAlloc()
|
370 |
+
noisy delete
|
371 |
+
"""
|
372 |
+
)
|
373 |
+
|
374 |
+
|
375 |
+
def test_reallocation_b(capture, msg):
|
376 |
+
with capture:
|
377 |
+
create_and_destroy(1.5)
|
378 |
+
assert msg(capture) == strip_comments(
|
379 |
+
"""
|
380 |
+
noisy new # allocation required to attempt first overload
|
381 |
+
noisy delete # have to dealloc before considering factory init overload
|
382 |
+
noisy new # pointer factory calling "new", part 1: allocation
|
383 |
+
NoisyAlloc(double 1.5) # ... part two, invoking constructor
|
384 |
+
---
|
385 |
+
~NoisyAlloc() # Destructor
|
386 |
+
noisy delete # operator delete
|
387 |
+
"""
|
388 |
+
)
|
389 |
+
|
390 |
+
|
391 |
+
def test_reallocation_c(capture, msg):
|
392 |
+
with capture:
|
393 |
+
create_and_destroy(2, 3)
|
394 |
+
assert msg(capture) == strip_comments(
|
395 |
+
"""
|
396 |
+
noisy new # pointer factory calling "new", allocation
|
397 |
+
NoisyAlloc(int 2) # constructor
|
398 |
+
---
|
399 |
+
~NoisyAlloc() # Destructor
|
400 |
+
noisy delete # operator delete
|
401 |
+
"""
|
402 |
+
)
|
403 |
+
|
404 |
+
|
405 |
+
def test_reallocation_d(capture, msg):
|
406 |
+
with capture:
|
407 |
+
create_and_destroy(2.5, 3)
|
408 |
+
assert msg(capture) == strip_comments(
|
409 |
+
"""
|
410 |
+
NoisyAlloc(double 2.5) # construction (local func variable: operator_new not called)
|
411 |
+
noisy new # return-by-value "new" part 1: allocation
|
412 |
+
~NoisyAlloc() # moved-away local func variable destruction
|
413 |
+
---
|
414 |
+
~NoisyAlloc() # Destructor
|
415 |
+
noisy delete # operator delete
|
416 |
+
"""
|
417 |
+
)
|
418 |
+
|
419 |
+
|
420 |
+
def test_reallocation_e(capture, msg):
|
421 |
+
with capture:
|
422 |
+
create_and_destroy(3.5, 4.5)
|
423 |
+
assert msg(capture) == strip_comments(
|
424 |
+
"""
|
425 |
+
noisy new # preallocation needed before invoking placement-new overload
|
426 |
+
noisy placement new # Placement new
|
427 |
+
NoisyAlloc(double 3.5) # construction
|
428 |
+
---
|
429 |
+
~NoisyAlloc() # Destructor
|
430 |
+
noisy delete # operator delete
|
431 |
+
"""
|
432 |
+
)
|
433 |
+
|
434 |
+
|
435 |
+
def test_reallocation_f(capture, msg):
|
436 |
+
with capture:
|
437 |
+
create_and_destroy(4, 0.5)
|
438 |
+
assert msg(capture) == strip_comments(
|
439 |
+
"""
|
440 |
+
noisy new # preallocation needed before invoking placement-new overload
|
441 |
+
noisy delete # deallocation of preallocated storage
|
442 |
+
noisy new # Factory pointer allocation
|
443 |
+
NoisyAlloc(int 4) # factory pointer construction
|
444 |
+
---
|
445 |
+
~NoisyAlloc() # Destructor
|
446 |
+
noisy delete # operator delete
|
447 |
+
"""
|
448 |
+
)
|
449 |
+
|
450 |
+
|
451 |
+
def test_reallocation_g(capture, msg):
|
452 |
+
with capture:
|
453 |
+
create_and_destroy(5, "hi")
|
454 |
+
assert msg(capture) == strip_comments(
|
455 |
+
"""
|
456 |
+
noisy new # preallocation needed before invoking first placement new
|
457 |
+
noisy delete # delete before considering new-style constructor
|
458 |
+
noisy new # preallocation for second placement new
|
459 |
+
noisy placement new # Placement new in the second placement new overload
|
460 |
+
NoisyAlloc(int 5) # construction
|
461 |
+
---
|
462 |
+
~NoisyAlloc() # Destructor
|
463 |
+
noisy delete # operator delete
|
464 |
+
"""
|
465 |
+
)
|
466 |
+
|
467 |
+
|
468 |
+
@pytest.mark.skipif("env.PY2")
|
469 |
+
def test_invalid_self():
|
470 |
+
"""Tests invocation of the pybind-registered base class with an invalid `self` argument. You
|
471 |
+
can only actually do this on Python 3: Python 2 raises an exception itself if you try."""
|
472 |
+
|
473 |
+
class NotPybindDerived(object):
|
474 |
+
pass
|
475 |
+
|
476 |
+
# Attempts to initialize with an invalid type passed as `self`:
|
477 |
+
class BrokenTF1(m.TestFactory1):
|
478 |
+
def __init__(self, bad):
|
479 |
+
if bad == 1:
|
480 |
+
a = m.TestFactory2(tag.pointer, 1)
|
481 |
+
m.TestFactory1.__init__(a, tag.pointer)
|
482 |
+
elif bad == 2:
|
483 |
+
a = NotPybindDerived()
|
484 |
+
m.TestFactory1.__init__(a, tag.pointer)
|
485 |
+
|
486 |
+
# Same as above, but for a class with an alias:
|
487 |
+
class BrokenTF6(m.TestFactory6):
|
488 |
+
def __init__(self, bad):
|
489 |
+
if bad == 0:
|
490 |
+
m.TestFactory6.__init__()
|
491 |
+
elif bad == 1:
|
492 |
+
a = m.TestFactory2(tag.pointer, 1)
|
493 |
+
m.TestFactory6.__init__(a, tag.base, 1)
|
494 |
+
elif bad == 2:
|
495 |
+
a = m.TestFactory2(tag.pointer, 1)
|
496 |
+
m.TestFactory6.__init__(a, tag.alias, 1)
|
497 |
+
elif bad == 3:
|
498 |
+
m.TestFactory6.__init__(
|
499 |
+
NotPybindDerived.__new__(NotPybindDerived), tag.base, 1
|
500 |
+
)
|
501 |
+
elif bad == 4:
|
502 |
+
m.TestFactory6.__init__(
|
503 |
+
NotPybindDerived.__new__(NotPybindDerived), tag.alias, 1
|
504 |
+
)
|
505 |
+
|
506 |
+
for arg in (1, 2):
|
507 |
+
with pytest.raises(TypeError) as excinfo:
|
508 |
+
BrokenTF1(arg)
|
509 |
+
assert (
|
510 |
+
str(excinfo.value)
|
511 |
+
== "__init__(self, ...) called with invalid or missing `self` argument"
|
512 |
+
)
|
513 |
+
|
514 |
+
for arg in (0, 1, 2, 3, 4):
|
515 |
+
with pytest.raises(TypeError) as excinfo:
|
516 |
+
BrokenTF6(arg)
|
517 |
+
assert (
|
518 |
+
str(excinfo.value)
|
519 |
+
== "__init__(self, ...) called with invalid or missing `self` argument"
|
520 |
+
)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_gil_scoped.cpp
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_gil_scoped.cpp -- acquire and release gil
|
3 |
+
|
4 |
+
Copyright (c) 2017 Borja Zarco (Google LLC) <[email protected]>
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#include "pybind11_tests.h"
|
11 |
+
#include <pybind11/functional.h>
|
12 |
+
|
13 |
+
|
14 |
+
class VirtClass {
|
15 |
+
public:
|
16 |
+
virtual ~VirtClass() = default;
|
17 |
+
VirtClass() = default;
|
18 |
+
VirtClass(const VirtClass&) = delete;
|
19 |
+
virtual void virtual_func() {}
|
20 |
+
virtual void pure_virtual_func() = 0;
|
21 |
+
};
|
22 |
+
|
23 |
+
class PyVirtClass : public VirtClass {
|
24 |
+
void virtual_func() override {
|
25 |
+
PYBIND11_OVERRIDE(void, VirtClass, virtual_func,);
|
26 |
+
}
|
27 |
+
void pure_virtual_func() override {
|
28 |
+
PYBIND11_OVERRIDE_PURE(void, VirtClass, pure_virtual_func,);
|
29 |
+
}
|
30 |
+
};
|
31 |
+
|
32 |
+
TEST_SUBMODULE(gil_scoped, m) {
|
33 |
+
py::class_<VirtClass, PyVirtClass>(m, "VirtClass")
|
34 |
+
.def(py::init<>())
|
35 |
+
.def("virtual_func", &VirtClass::virtual_func)
|
36 |
+
.def("pure_virtual_func", &VirtClass::pure_virtual_func);
|
37 |
+
|
38 |
+
m.def("test_callback_py_obj", [](py::object &func) { func(); });
|
39 |
+
m.def("test_callback_std_func", [](const std::function<void()> &func) { func(); });
|
40 |
+
m.def("test_callback_virtual_func", [](VirtClass &virt) { virt.virtual_func(); });
|
41 |
+
m.def("test_callback_pure_virtual_func", [](VirtClass &virt) { virt.pure_virtual_func(); });
|
42 |
+
m.def("test_cross_module_gil", []() {
|
43 |
+
auto cm = py::module_::import("cross_module_gil_utils");
|
44 |
+
auto gil_acquire
|
45 |
+
= reinterpret_cast<void (*)()>(PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr()));
|
46 |
+
py::gil_scoped_release gil_release;
|
47 |
+
gil_acquire();
|
48 |
+
});
|
49 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_gil_scoped.py
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import multiprocessing
|
3 |
+
import threading
|
4 |
+
|
5 |
+
from pybind11_tests import gil_scoped as m
|
6 |
+
|
7 |
+
|
8 |
+
def _run_in_process(target, *args, **kwargs):
|
9 |
+
"""Runs target in process and returns its exitcode after 10s (None if still alive)."""
|
10 |
+
process = multiprocessing.Process(target=target, args=args, kwargs=kwargs)
|
11 |
+
process.daemon = True
|
12 |
+
try:
|
13 |
+
process.start()
|
14 |
+
# Do not need to wait much, 10s should be more than enough.
|
15 |
+
process.join(timeout=10)
|
16 |
+
return process.exitcode
|
17 |
+
finally:
|
18 |
+
if process.is_alive():
|
19 |
+
process.terminate()
|
20 |
+
|
21 |
+
|
22 |
+
def _python_to_cpp_to_python():
|
23 |
+
"""Calls different C++ functions that come back to Python."""
|
24 |
+
|
25 |
+
class ExtendedVirtClass(m.VirtClass):
|
26 |
+
def virtual_func(self):
|
27 |
+
pass
|
28 |
+
|
29 |
+
def pure_virtual_func(self):
|
30 |
+
pass
|
31 |
+
|
32 |
+
extended = ExtendedVirtClass()
|
33 |
+
m.test_callback_py_obj(lambda: None)
|
34 |
+
m.test_callback_std_func(lambda: None)
|
35 |
+
m.test_callback_virtual_func(extended)
|
36 |
+
m.test_callback_pure_virtual_func(extended)
|
37 |
+
|
38 |
+
|
39 |
+
def _python_to_cpp_to_python_from_threads(num_threads, parallel=False):
|
40 |
+
"""Calls different C++ functions that come back to Python, from Python threads."""
|
41 |
+
threads = []
|
42 |
+
for _ in range(num_threads):
|
43 |
+
thread = threading.Thread(target=_python_to_cpp_to_python)
|
44 |
+
thread.daemon = True
|
45 |
+
thread.start()
|
46 |
+
if parallel:
|
47 |
+
threads.append(thread)
|
48 |
+
else:
|
49 |
+
thread.join()
|
50 |
+
for thread in threads:
|
51 |
+
thread.join()
|
52 |
+
|
53 |
+
|
54 |
+
# TODO: FIXME, sometimes returns -11 (segfault) instead of 0 on macOS Python 3.9
|
55 |
+
def test_python_to_cpp_to_python_from_thread():
|
56 |
+
"""Makes sure there is no GIL deadlock when running in a thread.
|
57 |
+
|
58 |
+
It runs in a separate process to be able to stop and assert if it deadlocks.
|
59 |
+
"""
|
60 |
+
assert _run_in_process(_python_to_cpp_to_python_from_threads, 1) == 0
|
61 |
+
|
62 |
+
|
63 |
+
# TODO: FIXME on macOS Python 3.9
|
64 |
+
def test_python_to_cpp_to_python_from_thread_multiple_parallel():
|
65 |
+
"""Makes sure there is no GIL deadlock when running in a thread multiple times in parallel.
|
66 |
+
|
67 |
+
It runs in a separate process to be able to stop and assert if it deadlocks.
|
68 |
+
"""
|
69 |
+
assert _run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=True) == 0
|
70 |
+
|
71 |
+
|
72 |
+
# TODO: FIXME on macOS Python 3.9
|
73 |
+
def test_python_to_cpp_to_python_from_thread_multiple_sequential():
|
74 |
+
"""Makes sure there is no GIL deadlock when running in a thread multiple times sequentially.
|
75 |
+
|
76 |
+
It runs in a separate process to be able to stop and assert if it deadlocks.
|
77 |
+
"""
|
78 |
+
assert (
|
79 |
+
_run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=False) == 0
|
80 |
+
)
|
81 |
+
|
82 |
+
|
83 |
+
# TODO: FIXME on macOS Python 3.9
|
84 |
+
def test_python_to_cpp_to_python_from_process():
|
85 |
+
"""Makes sure there is no GIL deadlock when using processes.
|
86 |
+
|
87 |
+
This test is for completion, but it was never an issue.
|
88 |
+
"""
|
89 |
+
assert _run_in_process(_python_to_cpp_to_python) == 0
|
90 |
+
|
91 |
+
|
92 |
+
def test_cross_module_gil():
|
93 |
+
"""Makes sure that the GIL can be acquired by another module from a GIL-released state."""
|
94 |
+
m.test_cross_module_gil() # Should not raise a SIGSEGV
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_iostream.cpp
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_iostream.cpp -- Usage of scoped_output_redirect
|
3 |
+
|
4 |
+
Copyright (c) 2017 Henry F. Schreiner
|
5 |
+
|
6 |
+
All rights reserved. Use of this source code is governed by a
|
7 |
+
BSD-style license that can be found in the LICENSE file.
|
8 |
+
*/
|
9 |
+
|
10 |
+
#if defined(_MSC_VER) && _MSC_VER < 1910 // VS 2015's MSVC
|
11 |
+
# pragma warning(disable: 4702) // unreachable code in system header (xatomic.h(382))
|
12 |
+
#endif
|
13 |
+
|
14 |
+
#include <pybind11/iostream.h>
|
15 |
+
#include "pybind11_tests.h"
|
16 |
+
#include <atomic>
|
17 |
+
#include <iostream>
|
18 |
+
#include <mutex>
|
19 |
+
#include <string>
|
20 |
+
#include <thread>
|
21 |
+
|
22 |
+
void noisy_function(const std::string &msg, bool flush) {
|
23 |
+
|
24 |
+
std::cout << msg;
|
25 |
+
if (flush)
|
26 |
+
std::cout << std::flush;
|
27 |
+
}
|
28 |
+
|
29 |
+
void noisy_funct_dual(const std::string &msg, const std::string &emsg) {
|
30 |
+
std::cout << msg;
|
31 |
+
std::cerr << emsg;
|
32 |
+
}
|
33 |
+
|
34 |
+
// object to manage C++ thread
|
35 |
+
// simply repeatedly write to std::cerr until stopped
|
36 |
+
// redirect is called at some point to test the safety of scoped_estream_redirect
|
37 |
+
struct TestThread {
|
38 |
+
TestThread() : stop_{false} {
|
39 |
+
auto thread_f = [this] {
|
40 |
+
static std::mutex cout_mutex;
|
41 |
+
while (!stop_) {
|
42 |
+
{
|
43 |
+
// #HelpAppreciated: Work on iostream.h thread safety.
|
44 |
+
// Without this lock, the clang ThreadSanitizer (tsan) reliably reports a
|
45 |
+
// data race, and this test is predictably flakey on Windows.
|
46 |
+
// For more background see the discussion under
|
47 |
+
// https://github.com/pybind/pybind11/pull/2982 and
|
48 |
+
// https://github.com/pybind/pybind11/pull/2995.
|
49 |
+
const std::lock_guard<std::mutex> lock(cout_mutex);
|
50 |
+
std::cout << "x" << std::flush;
|
51 |
+
}
|
52 |
+
std::this_thread::sleep_for(std::chrono::microseconds(50));
|
53 |
+
} };
|
54 |
+
t_ = new std::thread(std::move(thread_f));
|
55 |
+
}
|
56 |
+
|
57 |
+
~TestThread() {
|
58 |
+
delete t_;
|
59 |
+
}
|
60 |
+
|
61 |
+
void stop() { stop_ = true; }
|
62 |
+
|
63 |
+
void join() const {
|
64 |
+
py::gil_scoped_release gil_lock;
|
65 |
+
t_->join();
|
66 |
+
}
|
67 |
+
|
68 |
+
void sleep() {
|
69 |
+
py::gil_scoped_release gil_lock;
|
70 |
+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
71 |
+
}
|
72 |
+
|
73 |
+
std::thread *t_{nullptr};
|
74 |
+
std::atomic<bool> stop_;
|
75 |
+
};
|
76 |
+
|
77 |
+
|
78 |
+
TEST_SUBMODULE(iostream, m) {
|
79 |
+
|
80 |
+
add_ostream_redirect(m);
|
81 |
+
|
82 |
+
// test_evals
|
83 |
+
|
84 |
+
m.def("captured_output_default", [](const std::string &msg) {
|
85 |
+
py::scoped_ostream_redirect redir;
|
86 |
+
std::cout << msg << std::flush;
|
87 |
+
});
|
88 |
+
|
89 |
+
m.def("captured_output", [](const std::string &msg) {
|
90 |
+
py::scoped_ostream_redirect redir(std::cout, py::module_::import("sys").attr("stdout"));
|
91 |
+
std::cout << msg << std::flush;
|
92 |
+
});
|
93 |
+
|
94 |
+
m.def("guard_output", &noisy_function,
|
95 |
+
py::call_guard<py::scoped_ostream_redirect>(),
|
96 |
+
py::arg("msg"), py::arg("flush")=true);
|
97 |
+
|
98 |
+
m.def("captured_err", [](const std::string &msg) {
|
99 |
+
py::scoped_ostream_redirect redir(std::cerr, py::module_::import("sys").attr("stderr"));
|
100 |
+
std::cerr << msg << std::flush;
|
101 |
+
});
|
102 |
+
|
103 |
+
m.def("noisy_function", &noisy_function, py::arg("msg"), py::arg("flush") = true);
|
104 |
+
|
105 |
+
m.def("dual_guard", &noisy_funct_dual,
|
106 |
+
py::call_guard<py::scoped_ostream_redirect, py::scoped_estream_redirect>(),
|
107 |
+
py::arg("msg"), py::arg("emsg"));
|
108 |
+
|
109 |
+
m.def("raw_output", [](const std::string &msg) { std::cout << msg << std::flush; });
|
110 |
+
|
111 |
+
m.def("raw_err", [](const std::string &msg) { std::cerr << msg << std::flush; });
|
112 |
+
|
113 |
+
m.def("captured_dual", [](const std::string &msg, const std::string &emsg) {
|
114 |
+
py::scoped_ostream_redirect redirout(std::cout, py::module_::import("sys").attr("stdout"));
|
115 |
+
py::scoped_ostream_redirect redirerr(std::cerr, py::module_::import("sys").attr("stderr"));
|
116 |
+
std::cout << msg << std::flush;
|
117 |
+
std::cerr << emsg << std::flush;
|
118 |
+
});
|
119 |
+
|
120 |
+
py::class_<TestThread>(m, "TestThread")
|
121 |
+
.def(py::init<>())
|
122 |
+
.def("stop", &TestThread::stop)
|
123 |
+
.def("join", &TestThread::join)
|
124 |
+
.def("sleep", &TestThread::sleep);
|
125 |
+
}
|