Spaces:
Sleeping
Sleeping
29b338ff1ad9cc2ef38afc45e9956c994e3bd3762d2bc7adef8c3d297096e021
Browse files- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_iostream.py +331 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_kwargs_and_defaults.cpp +153 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_kwargs_and_defaults.py +285 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_local_bindings.cpp +107 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_local_bindings.py +258 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_methods_and_attributes.cpp +412 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_methods_and_attributes.py +518 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_modules.cpp +102 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_modules.py +90 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_multiple_inheritance.cpp +230 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_multiple_inheritance.py +361 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_numpy_array.cpp +462 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_numpy_array.py +554 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_numpy_dtypes.cpp +522 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_numpy_dtypes.py +434 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_numpy_vectorize.cpp +103 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_numpy_vectorize.py +266 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_opaque_types.cpp +73 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_opaque_types.py +58 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_operator_overloading.cpp +235 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_operator_overloading.py +145 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_pickling.cpp +189 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_pickling.py +83 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_pytypes.cpp +437 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_pytypes.py +591 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_sequences_and_iterators.cpp +374 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_sequences_and_iterators.py +195 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_smart_ptr.cpp +451 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_smart_ptr.py +318 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_stl.cpp +341 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_stl.py +292 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_stl_binders.cpp +131 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_stl_binders.py +291 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_tagbased_polymorphic.cpp +142 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_tagbased_polymorphic.py +29 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_union.cpp +22 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_union.py +9 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_virtual_functions.cpp +509 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_virtual_functions.py +408 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/valgrind-numpy-scipy.supp +140 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/valgrind-python.supp +117 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/FindCatch.cmake +70 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/FindEigen3.cmake +86 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/FindPythonLibsNew.cmake +257 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/check-style.sh +44 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/cmake_uninstall.cmake.in +23 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/libsize.py +38 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/make_changelog.py +66 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/pybind11Common.cmake +402 -0
- third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/pybind11Config.cmake.in +233 -0
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_iostream.py
ADDED
@@ -0,0 +1,331 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
from pybind11_tests import iostream as m
|
3 |
+
import sys
|
4 |
+
|
5 |
+
from contextlib import contextmanager
|
6 |
+
|
7 |
+
try:
|
8 |
+
# Python 3
|
9 |
+
from io import StringIO
|
10 |
+
except ImportError:
|
11 |
+
# Python 2
|
12 |
+
try:
|
13 |
+
from cStringIO import StringIO
|
14 |
+
except ImportError:
|
15 |
+
from StringIO import StringIO
|
16 |
+
|
17 |
+
try:
|
18 |
+
# Python 3.4
|
19 |
+
from contextlib import redirect_stdout
|
20 |
+
except ImportError:
|
21 |
+
|
22 |
+
@contextmanager
|
23 |
+
def redirect_stdout(target):
|
24 |
+
original = sys.stdout
|
25 |
+
sys.stdout = target
|
26 |
+
yield
|
27 |
+
sys.stdout = original
|
28 |
+
|
29 |
+
|
30 |
+
try:
|
31 |
+
# Python 3.5
|
32 |
+
from contextlib import redirect_stderr
|
33 |
+
except ImportError:
|
34 |
+
|
35 |
+
@contextmanager
|
36 |
+
def redirect_stderr(target):
|
37 |
+
original = sys.stderr
|
38 |
+
sys.stderr = target
|
39 |
+
yield
|
40 |
+
sys.stderr = original
|
41 |
+
|
42 |
+
|
43 |
+
def test_captured(capsys):
|
44 |
+
msg = "I've been redirected to Python, I hope!"
|
45 |
+
m.captured_output(msg)
|
46 |
+
stdout, stderr = capsys.readouterr()
|
47 |
+
assert stdout == msg
|
48 |
+
assert stderr == ""
|
49 |
+
|
50 |
+
m.captured_output_default(msg)
|
51 |
+
stdout, stderr = capsys.readouterr()
|
52 |
+
assert stdout == msg
|
53 |
+
assert stderr == ""
|
54 |
+
|
55 |
+
m.captured_err(msg)
|
56 |
+
stdout, stderr = capsys.readouterr()
|
57 |
+
assert stdout == ""
|
58 |
+
assert stderr == msg
|
59 |
+
|
60 |
+
|
61 |
+
def test_captured_large_string(capsys):
|
62 |
+
# Make this bigger than the buffer used on the C++ side: 1024 chars
|
63 |
+
msg = "I've been redirected to Python, I hope!"
|
64 |
+
msg = msg * (1024 // len(msg) + 1)
|
65 |
+
|
66 |
+
m.captured_output_default(msg)
|
67 |
+
stdout, stderr = capsys.readouterr()
|
68 |
+
assert stdout == msg
|
69 |
+
assert stderr == ""
|
70 |
+
|
71 |
+
|
72 |
+
def test_captured_utf8_2byte_offset0(capsys):
|
73 |
+
msg = "\u07FF"
|
74 |
+
msg = "" + msg * (1024 // len(msg) + 1)
|
75 |
+
|
76 |
+
m.captured_output_default(msg)
|
77 |
+
stdout, stderr = capsys.readouterr()
|
78 |
+
assert stdout == msg
|
79 |
+
assert stderr == ""
|
80 |
+
|
81 |
+
|
82 |
+
def test_captured_utf8_2byte_offset1(capsys):
|
83 |
+
msg = "\u07FF"
|
84 |
+
msg = "1" + msg * (1024 // len(msg) + 1)
|
85 |
+
|
86 |
+
m.captured_output_default(msg)
|
87 |
+
stdout, stderr = capsys.readouterr()
|
88 |
+
assert stdout == msg
|
89 |
+
assert stderr == ""
|
90 |
+
|
91 |
+
|
92 |
+
def test_captured_utf8_3byte_offset0(capsys):
|
93 |
+
msg = "\uFFFF"
|
94 |
+
msg = "" + msg * (1024 // len(msg) + 1)
|
95 |
+
|
96 |
+
m.captured_output_default(msg)
|
97 |
+
stdout, stderr = capsys.readouterr()
|
98 |
+
assert stdout == msg
|
99 |
+
assert stderr == ""
|
100 |
+
|
101 |
+
|
102 |
+
def test_captured_utf8_3byte_offset1(capsys):
|
103 |
+
msg = "\uFFFF"
|
104 |
+
msg = "1" + msg * (1024 // len(msg) + 1)
|
105 |
+
|
106 |
+
m.captured_output_default(msg)
|
107 |
+
stdout, stderr = capsys.readouterr()
|
108 |
+
assert stdout == msg
|
109 |
+
assert stderr == ""
|
110 |
+
|
111 |
+
|
112 |
+
def test_captured_utf8_3byte_offset2(capsys):
|
113 |
+
msg = "\uFFFF"
|
114 |
+
msg = "12" + msg * (1024 // len(msg) + 1)
|
115 |
+
|
116 |
+
m.captured_output_default(msg)
|
117 |
+
stdout, stderr = capsys.readouterr()
|
118 |
+
assert stdout == msg
|
119 |
+
assert stderr == ""
|
120 |
+
|
121 |
+
|
122 |
+
def test_captured_utf8_4byte_offset0(capsys):
|
123 |
+
msg = "\U0010FFFF"
|
124 |
+
msg = "" + msg * (1024 // len(msg) + 1)
|
125 |
+
|
126 |
+
m.captured_output_default(msg)
|
127 |
+
stdout, stderr = capsys.readouterr()
|
128 |
+
assert stdout == msg
|
129 |
+
assert stderr == ""
|
130 |
+
|
131 |
+
|
132 |
+
def test_captured_utf8_4byte_offset1(capsys):
|
133 |
+
msg = "\U0010FFFF"
|
134 |
+
msg = "1" + msg * (1024 // len(msg) + 1)
|
135 |
+
|
136 |
+
m.captured_output_default(msg)
|
137 |
+
stdout, stderr = capsys.readouterr()
|
138 |
+
assert stdout == msg
|
139 |
+
assert stderr == ""
|
140 |
+
|
141 |
+
|
142 |
+
def test_captured_utf8_4byte_offset2(capsys):
|
143 |
+
msg = "\U0010FFFF"
|
144 |
+
msg = "12" + msg * (1024 // len(msg) + 1)
|
145 |
+
|
146 |
+
m.captured_output_default(msg)
|
147 |
+
stdout, stderr = capsys.readouterr()
|
148 |
+
assert stdout == msg
|
149 |
+
assert stderr == ""
|
150 |
+
|
151 |
+
|
152 |
+
def test_captured_utf8_4byte_offset3(capsys):
|
153 |
+
msg = "\U0010FFFF"
|
154 |
+
msg = "123" + msg * (1024 // len(msg) + 1)
|
155 |
+
|
156 |
+
m.captured_output_default(msg)
|
157 |
+
stdout, stderr = capsys.readouterr()
|
158 |
+
assert stdout == msg
|
159 |
+
assert stderr == ""
|
160 |
+
|
161 |
+
|
162 |
+
def test_guard_capture(capsys):
|
163 |
+
msg = "I've been redirected to Python, I hope!"
|
164 |
+
m.guard_output(msg)
|
165 |
+
stdout, stderr = capsys.readouterr()
|
166 |
+
assert stdout == msg
|
167 |
+
assert stderr == ""
|
168 |
+
|
169 |
+
|
170 |
+
def test_series_captured(capture):
|
171 |
+
with capture:
|
172 |
+
m.captured_output("a")
|
173 |
+
m.captured_output("b")
|
174 |
+
assert capture == "ab"
|
175 |
+
|
176 |
+
|
177 |
+
def test_flush(capfd):
|
178 |
+
msg = "(not flushed)"
|
179 |
+
msg2 = "(flushed)"
|
180 |
+
|
181 |
+
with m.ostream_redirect():
|
182 |
+
m.noisy_function(msg, flush=False)
|
183 |
+
stdout, stderr = capfd.readouterr()
|
184 |
+
assert stdout == ""
|
185 |
+
|
186 |
+
m.noisy_function(msg2, flush=True)
|
187 |
+
stdout, stderr = capfd.readouterr()
|
188 |
+
assert stdout == msg + msg2
|
189 |
+
|
190 |
+
m.noisy_function(msg, flush=False)
|
191 |
+
|
192 |
+
stdout, stderr = capfd.readouterr()
|
193 |
+
assert stdout == msg
|
194 |
+
|
195 |
+
|
196 |
+
def test_not_captured(capfd):
|
197 |
+
msg = "Something that should not show up in log"
|
198 |
+
stream = StringIO()
|
199 |
+
with redirect_stdout(stream):
|
200 |
+
m.raw_output(msg)
|
201 |
+
stdout, stderr = capfd.readouterr()
|
202 |
+
assert stdout == msg
|
203 |
+
assert stderr == ""
|
204 |
+
assert stream.getvalue() == ""
|
205 |
+
|
206 |
+
stream = StringIO()
|
207 |
+
with redirect_stdout(stream):
|
208 |
+
m.captured_output(msg)
|
209 |
+
stdout, stderr = capfd.readouterr()
|
210 |
+
assert stdout == ""
|
211 |
+
assert stderr == ""
|
212 |
+
assert stream.getvalue() == msg
|
213 |
+
|
214 |
+
|
215 |
+
def test_err(capfd):
|
216 |
+
msg = "Something that should not show up in log"
|
217 |
+
stream = StringIO()
|
218 |
+
with redirect_stderr(stream):
|
219 |
+
m.raw_err(msg)
|
220 |
+
stdout, stderr = capfd.readouterr()
|
221 |
+
assert stdout == ""
|
222 |
+
assert stderr == msg
|
223 |
+
assert stream.getvalue() == ""
|
224 |
+
|
225 |
+
stream = StringIO()
|
226 |
+
with redirect_stderr(stream):
|
227 |
+
m.captured_err(msg)
|
228 |
+
stdout, stderr = capfd.readouterr()
|
229 |
+
assert stdout == ""
|
230 |
+
assert stderr == ""
|
231 |
+
assert stream.getvalue() == msg
|
232 |
+
|
233 |
+
|
234 |
+
def test_multi_captured(capfd):
|
235 |
+
stream = StringIO()
|
236 |
+
with redirect_stdout(stream):
|
237 |
+
m.captured_output("a")
|
238 |
+
m.raw_output("b")
|
239 |
+
m.captured_output("c")
|
240 |
+
m.raw_output("d")
|
241 |
+
stdout, stderr = capfd.readouterr()
|
242 |
+
assert stdout == "bd"
|
243 |
+
assert stream.getvalue() == "ac"
|
244 |
+
|
245 |
+
|
246 |
+
def test_dual(capsys):
|
247 |
+
m.captured_dual("a", "b")
|
248 |
+
stdout, stderr = capsys.readouterr()
|
249 |
+
assert stdout == "a"
|
250 |
+
assert stderr == "b"
|
251 |
+
|
252 |
+
|
253 |
+
def test_redirect(capfd):
|
254 |
+
msg = "Should not be in log!"
|
255 |
+
stream = StringIO()
|
256 |
+
with redirect_stdout(stream):
|
257 |
+
m.raw_output(msg)
|
258 |
+
stdout, stderr = capfd.readouterr()
|
259 |
+
assert stdout == msg
|
260 |
+
assert stream.getvalue() == ""
|
261 |
+
|
262 |
+
stream = StringIO()
|
263 |
+
with redirect_stdout(stream):
|
264 |
+
with m.ostream_redirect():
|
265 |
+
m.raw_output(msg)
|
266 |
+
stdout, stderr = capfd.readouterr()
|
267 |
+
assert stdout == ""
|
268 |
+
assert stream.getvalue() == msg
|
269 |
+
|
270 |
+
stream = StringIO()
|
271 |
+
with redirect_stdout(stream):
|
272 |
+
m.raw_output(msg)
|
273 |
+
stdout, stderr = capfd.readouterr()
|
274 |
+
assert stdout == msg
|
275 |
+
assert stream.getvalue() == ""
|
276 |
+
|
277 |
+
|
278 |
+
def test_redirect_err(capfd):
|
279 |
+
msg = "StdOut"
|
280 |
+
msg2 = "StdErr"
|
281 |
+
|
282 |
+
stream = StringIO()
|
283 |
+
with redirect_stderr(stream):
|
284 |
+
with m.ostream_redirect(stdout=False):
|
285 |
+
m.raw_output(msg)
|
286 |
+
m.raw_err(msg2)
|
287 |
+
stdout, stderr = capfd.readouterr()
|
288 |
+
assert stdout == msg
|
289 |
+
assert stderr == ""
|
290 |
+
assert stream.getvalue() == msg2
|
291 |
+
|
292 |
+
|
293 |
+
def test_redirect_both(capfd):
|
294 |
+
msg = "StdOut"
|
295 |
+
msg2 = "StdErr"
|
296 |
+
|
297 |
+
stream = StringIO()
|
298 |
+
stream2 = StringIO()
|
299 |
+
with redirect_stdout(stream):
|
300 |
+
with redirect_stderr(stream2):
|
301 |
+
with m.ostream_redirect():
|
302 |
+
m.raw_output(msg)
|
303 |
+
m.raw_err(msg2)
|
304 |
+
stdout, stderr = capfd.readouterr()
|
305 |
+
assert stdout == ""
|
306 |
+
assert stderr == ""
|
307 |
+
assert stream.getvalue() == msg
|
308 |
+
assert stream2.getvalue() == msg2
|
309 |
+
|
310 |
+
|
311 |
+
def test_threading():
|
312 |
+
with m.ostream_redirect(stdout=True, stderr=False):
|
313 |
+
# start some threads
|
314 |
+
threads = []
|
315 |
+
|
316 |
+
# start some threads
|
317 |
+
for _j in range(20):
|
318 |
+
threads.append(m.TestThread())
|
319 |
+
|
320 |
+
# give the threads some time to fail
|
321 |
+
threads[0].sleep()
|
322 |
+
|
323 |
+
# stop all the threads
|
324 |
+
for t in threads:
|
325 |
+
t.stop()
|
326 |
+
|
327 |
+
for t in threads:
|
328 |
+
t.join()
|
329 |
+
|
330 |
+
# if a thread segfaults, we don't get here
|
331 |
+
assert True
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_kwargs_and_defaults.cpp
ADDED
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_kwargs_and_defaults.cpp -- keyword arguments and default values
|
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 |
+
#include <utility>
|
15 |
+
|
16 |
+
TEST_SUBMODULE(kwargs_and_defaults, m) {
|
17 |
+
auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); };
|
18 |
+
|
19 |
+
// test_named_arguments
|
20 |
+
m.def("kw_func0", kw_func);
|
21 |
+
m.def("kw_func1", kw_func, py::arg("x"), py::arg("y"));
|
22 |
+
m.def("kw_func2", kw_func, py::arg("x") = 100, py::arg("y") = 200);
|
23 |
+
m.def("kw_func3", [](const char *) { }, py::arg("data") = std::string("Hello world!"));
|
24 |
+
|
25 |
+
/* A fancier default argument */
|
26 |
+
std::vector<int> list{{13, 17}};
|
27 |
+
m.def("kw_func4", [](const std::vector<int> &entries) {
|
28 |
+
std::string ret = "{";
|
29 |
+
for (int i : entries)
|
30 |
+
ret += std::to_string(i) + " ";
|
31 |
+
ret.back() = '}';
|
32 |
+
return ret;
|
33 |
+
}, py::arg("myList") = list);
|
34 |
+
|
35 |
+
m.def("kw_func_udl", kw_func, "x"_a, "y"_a=300);
|
36 |
+
m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a=0);
|
37 |
+
|
38 |
+
// test_args_and_kwargs
|
39 |
+
m.def("args_function", [](py::args args) -> py::tuple {
|
40 |
+
return std::move(args);
|
41 |
+
});
|
42 |
+
m.def("args_kwargs_function", [](const py::args &args, const py::kwargs &kwargs) {
|
43 |
+
return py::make_tuple(args, kwargs);
|
44 |
+
});
|
45 |
+
|
46 |
+
// test_mixed_args_and_kwargs
|
47 |
+
m.def("mixed_plus_args",
|
48 |
+
[](int i, double j, const py::args &args) { return py::make_tuple(i, j, args); });
|
49 |
+
m.def("mixed_plus_kwargs",
|
50 |
+
[](int i, double j, const py::kwargs &kwargs) { return py::make_tuple(i, j, kwargs); });
|
51 |
+
auto mixed_plus_both = [](int i, double j, const py::args &args, const py::kwargs &kwargs) {
|
52 |
+
return py::make_tuple(i, j, args, kwargs);
|
53 |
+
};
|
54 |
+
m.def("mixed_plus_args_kwargs", mixed_plus_both);
|
55 |
+
|
56 |
+
m.def("mixed_plus_args_kwargs_defaults", mixed_plus_both,
|
57 |
+
py::arg("i") = 1, py::arg("j") = 3.14159);
|
58 |
+
|
59 |
+
// test_args_refcount
|
60 |
+
// PyPy needs a garbage collection to get the reference count values to match CPython's behaviour
|
61 |
+
#ifdef PYPY_VERSION
|
62 |
+
#define GC_IF_NEEDED ConstructorStats::gc()
|
63 |
+
#else
|
64 |
+
#define GC_IF_NEEDED
|
65 |
+
#endif
|
66 |
+
m.def("arg_refcount_h", [](py::handle h) { GC_IF_NEEDED; return h.ref_count(); });
|
67 |
+
m.def("arg_refcount_h", [](py::handle h, py::handle, py::handle) { GC_IF_NEEDED; return h.ref_count(); });
|
68 |
+
m.def("arg_refcount_o", [](const py::object &o) {
|
69 |
+
GC_IF_NEEDED;
|
70 |
+
return o.ref_count();
|
71 |
+
});
|
72 |
+
m.def("args_refcount", [](py::args a) {
|
73 |
+
GC_IF_NEEDED;
|
74 |
+
py::tuple t(a.size());
|
75 |
+
for (size_t i = 0; i < a.size(); i++)
|
76 |
+
// Use raw Python API here to avoid an extra, intermediate incref on the tuple item:
|
77 |
+
t[i] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast<py::ssize_t>(i)));
|
78 |
+
return t;
|
79 |
+
});
|
80 |
+
m.def("mixed_args_refcount", [](const py::object &o, py::args a) {
|
81 |
+
GC_IF_NEEDED;
|
82 |
+
py::tuple t(a.size() + 1);
|
83 |
+
t[0] = o.ref_count();
|
84 |
+
for (size_t i = 0; i < a.size(); i++)
|
85 |
+
// Use raw Python API here to avoid an extra, intermediate incref on the tuple item:
|
86 |
+
t[i + 1] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast<py::ssize_t>(i)));
|
87 |
+
return t;
|
88 |
+
});
|
89 |
+
|
90 |
+
// pybind11 won't allow these to be bound: args and kwargs, if present, must be at the end.
|
91 |
+
// Uncomment these to test that the static_assert is indeed working:
|
92 |
+
// m.def("bad_args1", [](py::args, int) {});
|
93 |
+
// m.def("bad_args2", [](py::kwargs, int) {});
|
94 |
+
// m.def("bad_args3", [](py::kwargs, py::args) {});
|
95 |
+
// m.def("bad_args4", [](py::args, int, py::kwargs) {});
|
96 |
+
// m.def("bad_args5", [](py::args, py::kwargs, int) {});
|
97 |
+
// m.def("bad_args6", [](py::args, py::args) {});
|
98 |
+
// m.def("bad_args7", [](py::kwargs, py::kwargs) {});
|
99 |
+
|
100 |
+
// test_keyword_only_args
|
101 |
+
m.def("kw_only_all", [](int i, int j) { return py::make_tuple(i, j); },
|
102 |
+
py::kw_only(), py::arg("i"), py::arg("j"));
|
103 |
+
m.def("kw_only_some", [](int i, int j, int k) { return py::make_tuple(i, j, k); },
|
104 |
+
py::arg(), py::kw_only(), py::arg("j"), py::arg("k"));
|
105 |
+
m.def("kw_only_with_defaults", [](int i, int j, int k, int z) { return py::make_tuple(i, j, k, z); },
|
106 |
+
py::arg() = 3, "j"_a = 4, py::kw_only(), "k"_a = 5, "z"_a);
|
107 |
+
m.def("kw_only_mixed", [](int i, int j) { return py::make_tuple(i, j); },
|
108 |
+
"i"_a, py::kw_only(), "j"_a);
|
109 |
+
m.def(
|
110 |
+
"kw_only_plus_more",
|
111 |
+
[](int i, int j, int k, const py::kwargs &kwargs) {
|
112 |
+
return py::make_tuple(i, j, k, kwargs);
|
113 |
+
},
|
114 |
+
py::arg() /* positional */,
|
115 |
+
py::arg("j") = -1 /* both */,
|
116 |
+
py::kw_only(),
|
117 |
+
py::arg("k") /* kw-only */);
|
118 |
+
|
119 |
+
m.def("register_invalid_kw_only", [](py::module_ m) {
|
120 |
+
m.def("bad_kw_only", [](int i, int j) { return py::make_tuple(i, j); },
|
121 |
+
py::kw_only(), py::arg() /* invalid unnamed argument */, "j"_a);
|
122 |
+
});
|
123 |
+
|
124 |
+
// test_positional_only_args
|
125 |
+
m.def("pos_only_all", [](int i, int j) { return py::make_tuple(i, j); },
|
126 |
+
py::arg("i"), py::arg("j"), py::pos_only());
|
127 |
+
m.def("pos_only_mix", [](int i, int j) { return py::make_tuple(i, j); },
|
128 |
+
py::arg("i"), py::pos_only(), py::arg("j"));
|
129 |
+
m.def("pos_kw_only_mix", [](int i, int j, int k) { return py::make_tuple(i, j, k); },
|
130 |
+
py::arg("i"), py::pos_only(), py::arg("j"), py::kw_only(), py::arg("k"));
|
131 |
+
m.def("pos_only_def_mix", [](int i, int j, int k) { return py::make_tuple(i, j, k); },
|
132 |
+
py::arg("i"), py::arg("j") = 2, py::pos_only(), py::arg("k") = 3);
|
133 |
+
|
134 |
+
|
135 |
+
// These should fail to compile:
|
136 |
+
// argument annotations are required when using kw_only
|
137 |
+
// m.def("bad_kw_only1", [](int) {}, py::kw_only());
|
138 |
+
// can't specify both `py::kw_only` and a `py::args` argument
|
139 |
+
// m.def("bad_kw_only2", [](int i, py::args) {}, py::kw_only(), "i"_a);
|
140 |
+
|
141 |
+
// test_function_signatures (along with most of the above)
|
142 |
+
struct KWClass { void foo(int, float) {} };
|
143 |
+
py::class_<KWClass>(m, "KWClass")
|
144 |
+
.def("foo0", &KWClass::foo)
|
145 |
+
.def("foo1", &KWClass::foo, "x"_a, "y"_a);
|
146 |
+
|
147 |
+
// Make sure a class (not an instance) can be used as a default argument.
|
148 |
+
// The return value doesn't matter, only that the module is importable.
|
149 |
+
m.def(
|
150 |
+
"class_default_argument",
|
151 |
+
[](py::object a) { return py::repr(std::move(a)); },
|
152 |
+
"a"_a = py::module_::import("decimal").attr("Decimal"));
|
153 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_kwargs_and_defaults.py
ADDED
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
import env # noqa: F401
|
5 |
+
|
6 |
+
from pybind11_tests import kwargs_and_defaults as m
|
7 |
+
|
8 |
+
|
9 |
+
def test_function_signatures(doc):
|
10 |
+
assert doc(m.kw_func0) == "kw_func0(arg0: int, arg1: int) -> str"
|
11 |
+
assert doc(m.kw_func1) == "kw_func1(x: int, y: int) -> str"
|
12 |
+
assert doc(m.kw_func2) == "kw_func2(x: int = 100, y: int = 200) -> str"
|
13 |
+
assert doc(m.kw_func3) == "kw_func3(data: str = 'Hello world!') -> None"
|
14 |
+
assert doc(m.kw_func4) == "kw_func4(myList: List[int] = [13, 17]) -> str"
|
15 |
+
assert doc(m.kw_func_udl) == "kw_func_udl(x: int, y: int = 300) -> str"
|
16 |
+
assert doc(m.kw_func_udl_z) == "kw_func_udl_z(x: int, y: int = 0) -> str"
|
17 |
+
assert doc(m.args_function) == "args_function(*args) -> tuple"
|
18 |
+
assert (
|
19 |
+
doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple"
|
20 |
+
)
|
21 |
+
assert (
|
22 |
+
doc(m.KWClass.foo0)
|
23 |
+
== "foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None"
|
24 |
+
)
|
25 |
+
assert (
|
26 |
+
doc(m.KWClass.foo1)
|
27 |
+
== "foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None"
|
28 |
+
)
|
29 |
+
|
30 |
+
|
31 |
+
def test_named_arguments(msg):
|
32 |
+
assert m.kw_func0(5, 10) == "x=5, y=10"
|
33 |
+
|
34 |
+
assert m.kw_func1(5, 10) == "x=5, y=10"
|
35 |
+
assert m.kw_func1(5, y=10) == "x=5, y=10"
|
36 |
+
assert m.kw_func1(y=10, x=5) == "x=5, y=10"
|
37 |
+
|
38 |
+
assert m.kw_func2() == "x=100, y=200"
|
39 |
+
assert m.kw_func2(5) == "x=5, y=200"
|
40 |
+
assert m.kw_func2(x=5) == "x=5, y=200"
|
41 |
+
assert m.kw_func2(y=10) == "x=100, y=10"
|
42 |
+
assert m.kw_func2(5, 10) == "x=5, y=10"
|
43 |
+
assert m.kw_func2(x=5, y=10) == "x=5, y=10"
|
44 |
+
|
45 |
+
with pytest.raises(TypeError) as excinfo:
|
46 |
+
# noinspection PyArgumentList
|
47 |
+
m.kw_func2(x=5, y=10, z=12)
|
48 |
+
assert excinfo.match(
|
49 |
+
r"(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))"
|
50 |
+
+ "{3}$"
|
51 |
+
)
|
52 |
+
|
53 |
+
assert m.kw_func4() == "{13 17}"
|
54 |
+
assert m.kw_func4(myList=[1, 2, 3]) == "{1 2 3}"
|
55 |
+
|
56 |
+
assert m.kw_func_udl(x=5, y=10) == "x=5, y=10"
|
57 |
+
assert m.kw_func_udl_z(x=5) == "x=5, y=0"
|
58 |
+
|
59 |
+
|
60 |
+
def test_arg_and_kwargs():
|
61 |
+
args = "arg1_value", "arg2_value", 3
|
62 |
+
assert m.args_function(*args) == args
|
63 |
+
|
64 |
+
args = "a1", "a2"
|
65 |
+
kwargs = dict(arg3="a3", arg4=4)
|
66 |
+
assert m.args_kwargs_function(*args, **kwargs) == (args, kwargs)
|
67 |
+
|
68 |
+
|
69 |
+
def test_mixed_args_and_kwargs(msg):
|
70 |
+
mpa = m.mixed_plus_args
|
71 |
+
mpk = m.mixed_plus_kwargs
|
72 |
+
mpak = m.mixed_plus_args_kwargs
|
73 |
+
mpakd = m.mixed_plus_args_kwargs_defaults
|
74 |
+
|
75 |
+
assert mpa(1, 2.5, 4, 99.5, None) == (1, 2.5, (4, 99.5, None))
|
76 |
+
assert mpa(1, 2.5) == (1, 2.5, ())
|
77 |
+
with pytest.raises(TypeError) as excinfo:
|
78 |
+
assert mpa(1)
|
79 |
+
assert (
|
80 |
+
msg(excinfo.value)
|
81 |
+
== """
|
82 |
+
mixed_plus_args(): incompatible function arguments. The following argument types are supported:
|
83 |
+
1. (arg0: int, arg1: float, *args) -> tuple
|
84 |
+
|
85 |
+
Invoked with: 1
|
86 |
+
""" # noqa: E501 line too long
|
87 |
+
)
|
88 |
+
with pytest.raises(TypeError) as excinfo:
|
89 |
+
assert mpa()
|
90 |
+
assert (
|
91 |
+
msg(excinfo.value)
|
92 |
+
== """
|
93 |
+
mixed_plus_args(): incompatible function arguments. The following argument types are supported:
|
94 |
+
1. (arg0: int, arg1: float, *args) -> tuple
|
95 |
+
|
96 |
+
Invoked with:
|
97 |
+
""" # noqa: E501 line too long
|
98 |
+
)
|
99 |
+
|
100 |
+
assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (
|
101 |
+
-2,
|
102 |
+
3.5,
|
103 |
+
{"e": 2.71828, "pi": 3.14159},
|
104 |
+
)
|
105 |
+
assert mpak(7, 7.7, 7.77, 7.777, 7.7777, minusseven=-7) == (
|
106 |
+
7,
|
107 |
+
7.7,
|
108 |
+
(7.77, 7.777, 7.7777),
|
109 |
+
{"minusseven": -7},
|
110 |
+
)
|
111 |
+
assert mpakd() == (1, 3.14159, (), {})
|
112 |
+
assert mpakd(3) == (3, 3.14159, (), {})
|
113 |
+
assert mpakd(j=2.71828) == (1, 2.71828, (), {})
|
114 |
+
assert mpakd(k=42) == (1, 3.14159, (), {"k": 42})
|
115 |
+
assert mpakd(1, 1, 2, 3, 5, 8, then=13, followedby=21) == (
|
116 |
+
1,
|
117 |
+
1,
|
118 |
+
(2, 3, 5, 8),
|
119 |
+
{"then": 13, "followedby": 21},
|
120 |
+
)
|
121 |
+
# Arguments specified both positionally and via kwargs should fail:
|
122 |
+
with pytest.raises(TypeError) as excinfo:
|
123 |
+
assert mpakd(1, i=1)
|
124 |
+
assert (
|
125 |
+
msg(excinfo.value)
|
126 |
+
== """
|
127 |
+
mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:
|
128 |
+
1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
|
129 |
+
|
130 |
+
Invoked with: 1; kwargs: i=1
|
131 |
+
""" # noqa: E501 line too long
|
132 |
+
)
|
133 |
+
with pytest.raises(TypeError) as excinfo:
|
134 |
+
assert mpakd(1, 2, j=1)
|
135 |
+
assert (
|
136 |
+
msg(excinfo.value)
|
137 |
+
== """
|
138 |
+
mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:
|
139 |
+
1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
|
140 |
+
|
141 |
+
Invoked with: 1, 2; kwargs: j=1
|
142 |
+
""" # noqa: E501 line too long
|
143 |
+
)
|
144 |
+
|
145 |
+
|
146 |
+
def test_keyword_only_args(msg):
|
147 |
+
assert m.kw_only_all(i=1, j=2) == (1, 2)
|
148 |
+
assert m.kw_only_all(j=1, i=2) == (2, 1)
|
149 |
+
|
150 |
+
with pytest.raises(TypeError) as excinfo:
|
151 |
+
assert m.kw_only_all(i=1) == (1,)
|
152 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
153 |
+
|
154 |
+
with pytest.raises(TypeError) as excinfo:
|
155 |
+
assert m.kw_only_all(1, 2) == (1, 2)
|
156 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
157 |
+
|
158 |
+
assert m.kw_only_some(1, k=3, j=2) == (1, 2, 3)
|
159 |
+
|
160 |
+
assert m.kw_only_with_defaults(z=8) == (3, 4, 5, 8)
|
161 |
+
assert m.kw_only_with_defaults(2, z=8) == (2, 4, 5, 8)
|
162 |
+
assert m.kw_only_with_defaults(2, j=7, k=8, z=9) == (2, 7, 8, 9)
|
163 |
+
assert m.kw_only_with_defaults(2, 7, z=9, k=8) == (2, 7, 8, 9)
|
164 |
+
|
165 |
+
assert m.kw_only_mixed(1, j=2) == (1, 2)
|
166 |
+
assert m.kw_only_mixed(j=2, i=3) == (3, 2)
|
167 |
+
assert m.kw_only_mixed(i=2, j=3) == (2, 3)
|
168 |
+
|
169 |
+
assert m.kw_only_plus_more(4, 5, k=6, extra=7) == (4, 5, 6, {"extra": 7})
|
170 |
+
assert m.kw_only_plus_more(3, k=5, j=4, extra=6) == (3, 4, 5, {"extra": 6})
|
171 |
+
assert m.kw_only_plus_more(2, k=3, extra=4) == (2, -1, 3, {"extra": 4})
|
172 |
+
|
173 |
+
with pytest.raises(TypeError) as excinfo:
|
174 |
+
assert m.kw_only_mixed(i=1) == (1,)
|
175 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
176 |
+
|
177 |
+
with pytest.raises(RuntimeError) as excinfo:
|
178 |
+
m.register_invalid_kw_only(m)
|
179 |
+
assert (
|
180 |
+
msg(excinfo.value)
|
181 |
+
== """
|
182 |
+
arg(): cannot specify an unnamed argument after an kw_only() annotation
|
183 |
+
"""
|
184 |
+
)
|
185 |
+
|
186 |
+
|
187 |
+
def test_positional_only_args(msg):
|
188 |
+
assert m.pos_only_all(1, 2) == (1, 2)
|
189 |
+
assert m.pos_only_all(2, 1) == (2, 1)
|
190 |
+
|
191 |
+
with pytest.raises(TypeError) as excinfo:
|
192 |
+
m.pos_only_all(i=1, j=2)
|
193 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
194 |
+
|
195 |
+
assert m.pos_only_mix(1, 2) == (1, 2)
|
196 |
+
assert m.pos_only_mix(2, j=1) == (2, 1)
|
197 |
+
|
198 |
+
with pytest.raises(TypeError) as excinfo:
|
199 |
+
m.pos_only_mix(i=1, j=2)
|
200 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
201 |
+
|
202 |
+
assert m.pos_kw_only_mix(1, 2, k=3) == (1, 2, 3)
|
203 |
+
assert m.pos_kw_only_mix(1, j=2, k=3) == (1, 2, 3)
|
204 |
+
|
205 |
+
with pytest.raises(TypeError) as excinfo:
|
206 |
+
m.pos_kw_only_mix(i=1, j=2, k=3)
|
207 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
208 |
+
|
209 |
+
with pytest.raises(TypeError) as excinfo:
|
210 |
+
m.pos_kw_only_mix(1, 2, 3)
|
211 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
212 |
+
|
213 |
+
with pytest.raises(TypeError) as excinfo:
|
214 |
+
m.pos_only_def_mix()
|
215 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
216 |
+
|
217 |
+
assert m.pos_only_def_mix(1) == (1, 2, 3)
|
218 |
+
assert m.pos_only_def_mix(1, 4) == (1, 4, 3)
|
219 |
+
assert m.pos_only_def_mix(1, 4, 7) == (1, 4, 7)
|
220 |
+
assert m.pos_only_def_mix(1, 4, k=7) == (1, 4, 7)
|
221 |
+
|
222 |
+
with pytest.raises(TypeError) as excinfo:
|
223 |
+
m.pos_only_def_mix(1, j=4)
|
224 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
225 |
+
|
226 |
+
|
227 |
+
def test_signatures():
|
228 |
+
assert "kw_only_all(*, i: int, j: int) -> tuple\n" == m.kw_only_all.__doc__
|
229 |
+
assert "kw_only_mixed(i: int, *, j: int) -> tuple\n" == m.kw_only_mixed.__doc__
|
230 |
+
assert "pos_only_all(i: int, j: int, /) -> tuple\n" == m.pos_only_all.__doc__
|
231 |
+
assert "pos_only_mix(i: int, /, j: int) -> tuple\n" == m.pos_only_mix.__doc__
|
232 |
+
assert (
|
233 |
+
"pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple\n"
|
234 |
+
== m.pos_kw_only_mix.__doc__
|
235 |
+
)
|
236 |
+
|
237 |
+
|
238 |
+
@pytest.mark.xfail("env.PYPY and env.PY2", reason="PyPy2 doesn't double count")
|
239 |
+
def test_args_refcount():
|
240 |
+
"""Issue/PR #1216 - py::args elements get double-inc_ref()ed when combined with regular
|
241 |
+
arguments"""
|
242 |
+
refcount = m.arg_refcount_h
|
243 |
+
|
244 |
+
myval = 54321
|
245 |
+
expected = refcount(myval)
|
246 |
+
assert m.arg_refcount_h(myval) == expected
|
247 |
+
assert m.arg_refcount_o(myval) == expected + 1
|
248 |
+
assert m.arg_refcount_h(myval) == expected
|
249 |
+
assert refcount(myval) == expected
|
250 |
+
|
251 |
+
assert m.mixed_plus_args(1, 2.0, "a", myval) == (1, 2.0, ("a", myval))
|
252 |
+
assert refcount(myval) == expected
|
253 |
+
|
254 |
+
assert m.mixed_plus_kwargs(3, 4.0, a=1, b=myval) == (3, 4.0, {"a": 1, "b": myval})
|
255 |
+
assert refcount(myval) == expected
|
256 |
+
|
257 |
+
assert m.args_function(-1, myval) == (-1, myval)
|
258 |
+
assert refcount(myval) == expected
|
259 |
+
|
260 |
+
assert m.mixed_plus_args_kwargs(5, 6.0, myval, a=myval) == (
|
261 |
+
5,
|
262 |
+
6.0,
|
263 |
+
(myval,),
|
264 |
+
{"a": myval},
|
265 |
+
)
|
266 |
+
assert refcount(myval) == expected
|
267 |
+
|
268 |
+
assert m.args_kwargs_function(7, 8, myval, a=1, b=myval) == (
|
269 |
+
(7, 8, myval),
|
270 |
+
{"a": 1, "b": myval},
|
271 |
+
)
|
272 |
+
assert refcount(myval) == expected
|
273 |
+
|
274 |
+
exp3 = refcount(myval, myval, myval)
|
275 |
+
assert m.args_refcount(myval, myval, myval) == (exp3, exp3, exp3)
|
276 |
+
assert refcount(myval) == expected
|
277 |
+
|
278 |
+
# This function takes the first arg as a `py::object` and the rest as a `py::args`. Unlike the
|
279 |
+
# previous case, when we have both positional and `py::args` we need to construct a new tuple
|
280 |
+
# for the `py::args`; in the previous case, we could simply inc_ref and pass on Python's input
|
281 |
+
# tuple without having to inc_ref the individual elements, but here we can't, hence the extra
|
282 |
+
# refs.
|
283 |
+
assert m.mixed_args_refcount(myval, myval, myval) == (exp3 + 3, exp3 + 3, exp3 + 3)
|
284 |
+
|
285 |
+
assert m.class_default_argument() == "<class 'decimal.Decimal'>"
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_local_bindings.cpp
ADDED
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_local_bindings.cpp -- tests the py::module_local class feature which makes a class
|
3 |
+
binding local to the module in which it is defined.
|
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 "pybind11_tests.h"
|
12 |
+
#include "local_bindings.h"
|
13 |
+
|
14 |
+
#include <pybind11/stl.h>
|
15 |
+
#include <pybind11/stl_bind.h>
|
16 |
+
|
17 |
+
#include <numeric>
|
18 |
+
#include <utility>
|
19 |
+
|
20 |
+
TEST_SUBMODULE(local_bindings, m) {
|
21 |
+
// test_load_external
|
22 |
+
m.def("load_external1", [](ExternalType1 &e) { return e.i; });
|
23 |
+
m.def("load_external2", [](ExternalType2 &e) { return e.i; });
|
24 |
+
|
25 |
+
// test_local_bindings
|
26 |
+
// Register a class with py::module_local:
|
27 |
+
bind_local<LocalType, -1>(m, "LocalType", py::module_local())
|
28 |
+
.def("get3", [](LocalType &t) { return t.i + 3; })
|
29 |
+
;
|
30 |
+
|
31 |
+
m.def("local_value", [](LocalType &l) { return l.i; });
|
32 |
+
|
33 |
+
// test_nonlocal_failure
|
34 |
+
// The main pybind11 test module is loaded first, so this registration will succeed (the second
|
35 |
+
// one, in pybind11_cross_module_tests.cpp, is designed to fail):
|
36 |
+
bind_local<NonLocalType, 0>(m, "NonLocalType")
|
37 |
+
.def(py::init<int>())
|
38 |
+
.def("get", [](LocalType &i) { return i.i; })
|
39 |
+
;
|
40 |
+
|
41 |
+
// test_duplicate_local
|
42 |
+
// py::module_local declarations should be visible across compilation units that get linked together;
|
43 |
+
// this tries to register a duplicate local. It depends on a definition in test_class.cpp and
|
44 |
+
// should raise a runtime error from the duplicate definition attempt. If test_class isn't
|
45 |
+
// available it *also* throws a runtime error (with "test_class not enabled" as value).
|
46 |
+
m.def("register_local_external", [m]() {
|
47 |
+
auto main = py::module_::import("pybind11_tests");
|
48 |
+
if (py::hasattr(main, "class_")) {
|
49 |
+
bind_local<LocalExternal, 7>(m, "LocalExternal", py::module_local());
|
50 |
+
}
|
51 |
+
else throw std::runtime_error("test_class not enabled");
|
52 |
+
});
|
53 |
+
|
54 |
+
// test_stl_bind_local
|
55 |
+
// stl_bind.h binders defaults to py::module_local if the types are local or converting:
|
56 |
+
py::bind_vector<LocalVec>(m, "LocalVec");
|
57 |
+
py::bind_map<LocalMap>(m, "LocalMap");
|
58 |
+
// and global if the type (or one of the types, for the map) is global:
|
59 |
+
py::bind_vector<NonLocalVec>(m, "NonLocalVec");
|
60 |
+
py::bind_map<NonLocalMap>(m, "NonLocalMap");
|
61 |
+
|
62 |
+
// test_stl_bind_global
|
63 |
+
// They can, however, be overridden to global using `py::module_local(false)`:
|
64 |
+
bind_local<NonLocal2, 10>(m, "NonLocal2");
|
65 |
+
py::bind_vector<LocalVec2>(m, "LocalVec2", py::module_local());
|
66 |
+
py::bind_map<NonLocalMap2>(m, "NonLocalMap2", py::module_local(false));
|
67 |
+
|
68 |
+
// test_mixed_local_global
|
69 |
+
// We try this both with the global type registered first and vice versa (the order shouldn't
|
70 |
+
// matter).
|
71 |
+
m.def("register_mixed_global", [m]() {
|
72 |
+
bind_local<MixedGlobalLocal, 100>(m, "MixedGlobalLocal", py::module_local(false));
|
73 |
+
});
|
74 |
+
m.def("register_mixed_local", [m]() {
|
75 |
+
bind_local<MixedLocalGlobal, 1000>(m, "MixedLocalGlobal", py::module_local());
|
76 |
+
});
|
77 |
+
m.def("get_mixed_gl", [](int i) { return MixedGlobalLocal(i); });
|
78 |
+
m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });
|
79 |
+
|
80 |
+
// test_internal_locals_differ
|
81 |
+
m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); });
|
82 |
+
|
83 |
+
// test_stl_caster_vs_stl_bind
|
84 |
+
m.def("load_vector_via_caster", [](std::vector<int> v) {
|
85 |
+
return std::accumulate(v.begin(), v.end(), 0);
|
86 |
+
});
|
87 |
+
|
88 |
+
// test_cross_module_calls
|
89 |
+
m.def("return_self", [](LocalVec *v) { return v; });
|
90 |
+
m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); });
|
91 |
+
|
92 |
+
class Cat : public pets::Pet {
|
93 |
+
public:
|
94 |
+
Cat(std::string name) : Pet(std::move(name)) {}
|
95 |
+
};
|
96 |
+
py::class_<pets::Pet>(m, "Pet", py::module_local())
|
97 |
+
.def("get_name", &pets::Pet::name);
|
98 |
+
// Binding for local extending class:
|
99 |
+
py::class_<Cat, pets::Pet>(m, "Cat")
|
100 |
+
.def(py::init<std::string>());
|
101 |
+
m.def("pet_name", [](pets::Pet &p) { return p.name(); });
|
102 |
+
|
103 |
+
py::class_<MixGL>(m, "MixGL").def(py::init<int>());
|
104 |
+
m.def("get_gl_value", [](MixGL &o) { return o.i + 10; });
|
105 |
+
|
106 |
+
py::class_<MixGL2>(m, "MixGL2").def(py::init<int>());
|
107 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_local_bindings.py
ADDED
@@ -0,0 +1,258 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
import env # noqa: F401
|
5 |
+
|
6 |
+
from pybind11_tests import local_bindings as m
|
7 |
+
|
8 |
+
|
9 |
+
def test_load_external():
|
10 |
+
"""Load a `py::module_local` type that's only registered in an external module"""
|
11 |
+
import pybind11_cross_module_tests as cm
|
12 |
+
|
13 |
+
assert m.load_external1(cm.ExternalType1(11)) == 11
|
14 |
+
assert m.load_external2(cm.ExternalType2(22)) == 22
|
15 |
+
|
16 |
+
with pytest.raises(TypeError) as excinfo:
|
17 |
+
assert m.load_external2(cm.ExternalType1(21)) == 21
|
18 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
19 |
+
|
20 |
+
with pytest.raises(TypeError) as excinfo:
|
21 |
+
assert m.load_external1(cm.ExternalType2(12)) == 12
|
22 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
23 |
+
|
24 |
+
|
25 |
+
def test_local_bindings():
|
26 |
+
"""Tests that duplicate `py::module_local` class bindings work across modules"""
|
27 |
+
|
28 |
+
# Make sure we can load the second module with the conflicting (but local) definition:
|
29 |
+
import pybind11_cross_module_tests as cm
|
30 |
+
|
31 |
+
i1 = m.LocalType(5)
|
32 |
+
assert i1.get() == 4
|
33 |
+
assert i1.get3() == 8
|
34 |
+
|
35 |
+
i2 = cm.LocalType(10)
|
36 |
+
assert i2.get() == 11
|
37 |
+
assert i2.get2() == 12
|
38 |
+
|
39 |
+
assert not hasattr(i1, "get2")
|
40 |
+
assert not hasattr(i2, "get3")
|
41 |
+
|
42 |
+
# Loading within the local module
|
43 |
+
assert m.local_value(i1) == 5
|
44 |
+
assert cm.local_value(i2) == 10
|
45 |
+
|
46 |
+
# Cross-module loading works as well (on failure, the type loader looks for
|
47 |
+
# external module-local converters):
|
48 |
+
assert m.local_value(i2) == 10
|
49 |
+
assert cm.local_value(i1) == 5
|
50 |
+
|
51 |
+
|
52 |
+
def test_nonlocal_failure():
|
53 |
+
"""Tests that attempting to register a non-local type in multiple modules fails"""
|
54 |
+
import pybind11_cross_module_tests as cm
|
55 |
+
|
56 |
+
with pytest.raises(RuntimeError) as excinfo:
|
57 |
+
cm.register_nonlocal()
|
58 |
+
assert (
|
59 |
+
str(excinfo.value) == 'generic_type: type "NonLocalType" is already registered!'
|
60 |
+
)
|
61 |
+
|
62 |
+
|
63 |
+
def test_duplicate_local():
|
64 |
+
"""Tests expected failure when registering a class twice with py::local in the same module"""
|
65 |
+
with pytest.raises(RuntimeError) as excinfo:
|
66 |
+
m.register_local_external()
|
67 |
+
import pybind11_tests
|
68 |
+
|
69 |
+
assert str(excinfo.value) == (
|
70 |
+
'generic_type: type "LocalExternal" is already registered!'
|
71 |
+
if hasattr(pybind11_tests, "class_")
|
72 |
+
else "test_class not enabled"
|
73 |
+
)
|
74 |
+
|
75 |
+
|
76 |
+
def test_stl_bind_local():
|
77 |
+
import pybind11_cross_module_tests as cm
|
78 |
+
|
79 |
+
v1, v2 = m.LocalVec(), cm.LocalVec()
|
80 |
+
v1.append(m.LocalType(1))
|
81 |
+
v1.append(m.LocalType(2))
|
82 |
+
v2.append(cm.LocalType(1))
|
83 |
+
v2.append(cm.LocalType(2))
|
84 |
+
|
85 |
+
# Cross module value loading:
|
86 |
+
v1.append(cm.LocalType(3))
|
87 |
+
v2.append(m.LocalType(3))
|
88 |
+
|
89 |
+
assert [i.get() for i in v1] == [0, 1, 2]
|
90 |
+
assert [i.get() for i in v2] == [2, 3, 4]
|
91 |
+
|
92 |
+
v3, v4 = m.NonLocalVec(), cm.NonLocalVec2()
|
93 |
+
v3.append(m.NonLocalType(1))
|
94 |
+
v3.append(m.NonLocalType(2))
|
95 |
+
v4.append(m.NonLocal2(3))
|
96 |
+
v4.append(m.NonLocal2(4))
|
97 |
+
|
98 |
+
assert [i.get() for i in v3] == [1, 2]
|
99 |
+
assert [i.get() for i in v4] == [13, 14]
|
100 |
+
|
101 |
+
d1, d2 = m.LocalMap(), cm.LocalMap()
|
102 |
+
d1["a"] = v1[0]
|
103 |
+
d1["b"] = v1[1]
|
104 |
+
d2["c"] = v2[0]
|
105 |
+
d2["d"] = v2[1]
|
106 |
+
assert {i: d1[i].get() for i in d1} == {"a": 0, "b": 1}
|
107 |
+
assert {i: d2[i].get() for i in d2} == {"c": 2, "d": 3}
|
108 |
+
|
109 |
+
|
110 |
+
def test_stl_bind_global():
|
111 |
+
import pybind11_cross_module_tests as cm
|
112 |
+
|
113 |
+
with pytest.raises(RuntimeError) as excinfo:
|
114 |
+
cm.register_nonlocal_map()
|
115 |
+
assert (
|
116 |
+
str(excinfo.value) == 'generic_type: type "NonLocalMap" is already registered!'
|
117 |
+
)
|
118 |
+
|
119 |
+
with pytest.raises(RuntimeError) as excinfo:
|
120 |
+
cm.register_nonlocal_vec()
|
121 |
+
assert (
|
122 |
+
str(excinfo.value) == 'generic_type: type "NonLocalVec" is already registered!'
|
123 |
+
)
|
124 |
+
|
125 |
+
with pytest.raises(RuntimeError) as excinfo:
|
126 |
+
cm.register_nonlocal_map2()
|
127 |
+
assert (
|
128 |
+
str(excinfo.value) == 'generic_type: type "NonLocalMap2" is already registered!'
|
129 |
+
)
|
130 |
+
|
131 |
+
|
132 |
+
def test_mixed_local_global():
|
133 |
+
"""Local types take precedence over globally registered types: a module with a `module_local`
|
134 |
+
type can be registered even if the type is already registered globally. With the module,
|
135 |
+
casting will go to the local type; outside the module casting goes to the global type."""
|
136 |
+
import pybind11_cross_module_tests as cm
|
137 |
+
|
138 |
+
m.register_mixed_global()
|
139 |
+
m.register_mixed_local()
|
140 |
+
|
141 |
+
a = []
|
142 |
+
a.append(m.MixedGlobalLocal(1))
|
143 |
+
a.append(m.MixedLocalGlobal(2))
|
144 |
+
a.append(m.get_mixed_gl(3))
|
145 |
+
a.append(m.get_mixed_lg(4))
|
146 |
+
|
147 |
+
assert [x.get() for x in a] == [101, 1002, 103, 1004]
|
148 |
+
|
149 |
+
cm.register_mixed_global_local()
|
150 |
+
cm.register_mixed_local_global()
|
151 |
+
a.append(m.MixedGlobalLocal(5))
|
152 |
+
a.append(m.MixedLocalGlobal(6))
|
153 |
+
a.append(cm.MixedGlobalLocal(7))
|
154 |
+
a.append(cm.MixedLocalGlobal(8))
|
155 |
+
a.append(m.get_mixed_gl(9))
|
156 |
+
a.append(m.get_mixed_lg(10))
|
157 |
+
a.append(cm.get_mixed_gl(11))
|
158 |
+
a.append(cm.get_mixed_lg(12))
|
159 |
+
|
160 |
+
assert [x.get() for x in a] == [
|
161 |
+
101,
|
162 |
+
1002,
|
163 |
+
103,
|
164 |
+
1004,
|
165 |
+
105,
|
166 |
+
1006,
|
167 |
+
207,
|
168 |
+
2008,
|
169 |
+
109,
|
170 |
+
1010,
|
171 |
+
211,
|
172 |
+
2012,
|
173 |
+
]
|
174 |
+
|
175 |
+
|
176 |
+
def test_internal_locals_differ():
|
177 |
+
"""Makes sure the internal local type map differs across the two modules"""
|
178 |
+
import pybind11_cross_module_tests as cm
|
179 |
+
|
180 |
+
assert m.local_cpp_types_addr() != cm.local_cpp_types_addr()
|
181 |
+
|
182 |
+
|
183 |
+
@pytest.mark.xfail("env.PYPY and sys.pypy_version_info < (7, 3, 2)")
|
184 |
+
def test_stl_caster_vs_stl_bind(msg):
|
185 |
+
"""One module uses a generic vector caster from `<pybind11/stl.h>` while the other
|
186 |
+
exports `std::vector<int>` via `py:bind_vector` and `py::module_local`"""
|
187 |
+
import pybind11_cross_module_tests as cm
|
188 |
+
|
189 |
+
v1 = cm.VectorInt([1, 2, 3])
|
190 |
+
assert m.load_vector_via_caster(v1) == 6
|
191 |
+
assert cm.load_vector_via_binding(v1) == 6
|
192 |
+
|
193 |
+
v2 = [1, 2, 3]
|
194 |
+
assert m.load_vector_via_caster(v2) == 6
|
195 |
+
with pytest.raises(TypeError) as excinfo:
|
196 |
+
cm.load_vector_via_binding(v2)
|
197 |
+
assert (
|
198 |
+
msg(excinfo.value)
|
199 |
+
== """
|
200 |
+
load_vector_via_binding(): incompatible function arguments. The following argument types are supported:
|
201 |
+
1. (arg0: pybind11_cross_module_tests.VectorInt) -> int
|
202 |
+
|
203 |
+
Invoked with: [1, 2, 3]
|
204 |
+
""" # noqa: E501 line too long
|
205 |
+
)
|
206 |
+
|
207 |
+
|
208 |
+
def test_cross_module_calls():
|
209 |
+
import pybind11_cross_module_tests as cm
|
210 |
+
|
211 |
+
v1 = m.LocalVec()
|
212 |
+
v1.append(m.LocalType(1))
|
213 |
+
v2 = cm.LocalVec()
|
214 |
+
v2.append(cm.LocalType(2))
|
215 |
+
|
216 |
+
# Returning the self pointer should get picked up as returning an existing
|
217 |
+
# instance (even when that instance is of a foreign, non-local type).
|
218 |
+
assert m.return_self(v1) is v1
|
219 |
+
assert cm.return_self(v2) is v2
|
220 |
+
assert m.return_self(v2) is v2
|
221 |
+
assert cm.return_self(v1) is v1
|
222 |
+
|
223 |
+
assert m.LocalVec is not cm.LocalVec
|
224 |
+
# Returning a copy, on the other hand, always goes to the local type,
|
225 |
+
# regardless of where the source type came from.
|
226 |
+
assert type(m.return_copy(v1)) is m.LocalVec
|
227 |
+
assert type(m.return_copy(v2)) is m.LocalVec
|
228 |
+
assert type(cm.return_copy(v1)) is cm.LocalVec
|
229 |
+
assert type(cm.return_copy(v2)) is cm.LocalVec
|
230 |
+
|
231 |
+
# Test the example given in the documentation (which also tests inheritance casting):
|
232 |
+
mycat = m.Cat("Fluffy")
|
233 |
+
mydog = cm.Dog("Rover")
|
234 |
+
assert mycat.get_name() == "Fluffy"
|
235 |
+
assert mydog.name() == "Rover"
|
236 |
+
assert m.Cat.__base__.__name__ == "Pet"
|
237 |
+
assert cm.Dog.__base__.__name__ == "Pet"
|
238 |
+
assert m.Cat.__base__ is not cm.Dog.__base__
|
239 |
+
assert m.pet_name(mycat) == "Fluffy"
|
240 |
+
assert m.pet_name(mydog) == "Rover"
|
241 |
+
assert cm.pet_name(mycat) == "Fluffy"
|
242 |
+
assert cm.pet_name(mydog) == "Rover"
|
243 |
+
|
244 |
+
assert m.MixGL is not cm.MixGL
|
245 |
+
a = m.MixGL(1)
|
246 |
+
b = cm.MixGL(2)
|
247 |
+
assert m.get_gl_value(a) == 11
|
248 |
+
assert m.get_gl_value(b) == 12
|
249 |
+
assert cm.get_gl_value(a) == 101
|
250 |
+
assert cm.get_gl_value(b) == 102
|
251 |
+
|
252 |
+
c, d = m.MixGL2(3), cm.MixGL2(4)
|
253 |
+
with pytest.raises(TypeError) as excinfo:
|
254 |
+
m.get_gl_value(c)
|
255 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
256 |
+
with pytest.raises(TypeError) as excinfo:
|
257 |
+
m.get_gl_value(d)
|
258 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_methods_and_attributes.cpp
ADDED
@@ -0,0 +1,412 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_methods_and_attributes.cpp -- constructors, deconstructors, attribute access,
|
3 |
+
__str__, argument and return value conventions
|
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 |
+
#include "constructor_stats.h"
|
13 |
+
|
14 |
+
#if !defined(PYBIND11_OVERLOAD_CAST)
|
15 |
+
template <typename... Args>
|
16 |
+
using overload_cast_ = pybind11::detail::overload_cast_impl<Args...>;
|
17 |
+
#endif
|
18 |
+
|
19 |
+
class ExampleMandA {
|
20 |
+
public:
|
21 |
+
ExampleMandA() { print_default_created(this); }
|
22 |
+
ExampleMandA(int value) : value(value) { print_created(this, value); }
|
23 |
+
ExampleMandA(const ExampleMandA &e) : value(e.value) { print_copy_created(this); }
|
24 |
+
ExampleMandA(std::string&&) {}
|
25 |
+
ExampleMandA(ExampleMandA &&e) noexcept : value(e.value) { print_move_created(this); }
|
26 |
+
~ExampleMandA() { print_destroyed(this); }
|
27 |
+
|
28 |
+
std::string toString() const { return "ExampleMandA[value=" + std::to_string(value) + "]"; }
|
29 |
+
|
30 |
+
void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; }
|
31 |
+
void operator=(ExampleMandA &&e) noexcept {
|
32 |
+
print_move_assigned(this);
|
33 |
+
value = e.value;
|
34 |
+
}
|
35 |
+
|
36 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
37 |
+
void add1(ExampleMandA other) { value += other.value; } // passing by value
|
38 |
+
void add2(ExampleMandA &other) { value += other.value; } // passing by reference
|
39 |
+
void add3(const ExampleMandA &other) { value += other.value; } // passing by const reference
|
40 |
+
void add4(ExampleMandA *other) { value += other->value; } // passing by pointer
|
41 |
+
void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer
|
42 |
+
|
43 |
+
void add6(int other) { value += other; } // passing by value
|
44 |
+
void add7(int &other) { value += other; } // passing by reference
|
45 |
+
void add8(const int &other) { value += other; } // passing by const reference
|
46 |
+
// NOLINTNEXTLINE(readability-non-const-parameter) Deliberately non-const for testing
|
47 |
+
void add9(int *other) { value += *other; } // passing by pointer
|
48 |
+
void add10(const int *other) { value += *other; } // passing by const pointer
|
49 |
+
|
50 |
+
void consume_str(std::string&&) {}
|
51 |
+
|
52 |
+
ExampleMandA self1() { return *this; } // return by value
|
53 |
+
ExampleMandA &self2() { return *this; } // return by reference
|
54 |
+
const ExampleMandA &self3() const { return *this; } // return by const reference
|
55 |
+
ExampleMandA *self4() { return this; } // return by pointer
|
56 |
+
const ExampleMandA *self5() const { return this; } // return by const pointer
|
57 |
+
|
58 |
+
int internal1() const { return value; } // return by value
|
59 |
+
int &internal2() { return value; } // return by reference
|
60 |
+
const int &internal3() const { return value; } // return by const reference
|
61 |
+
int *internal4() { return &value; } // return by pointer
|
62 |
+
const int *internal5() { return &value; } // return by const pointer
|
63 |
+
|
64 |
+
py::str overloaded() { return "()"; }
|
65 |
+
py::str overloaded(int) { return "(int)"; }
|
66 |
+
py::str overloaded(int, float) { return "(int, float)"; }
|
67 |
+
py::str overloaded(float, int) { return "(float, int)"; }
|
68 |
+
py::str overloaded(int, int) { return "(int, int)"; }
|
69 |
+
py::str overloaded(float, float) { return "(float, float)"; }
|
70 |
+
py::str overloaded(int) const { return "(int) const"; }
|
71 |
+
py::str overloaded(int, float) const { return "(int, float) const"; }
|
72 |
+
py::str overloaded(float, int) const { return "(float, int) const"; }
|
73 |
+
py::str overloaded(int, int) const { return "(int, int) const"; }
|
74 |
+
py::str overloaded(float, float) const { return "(float, float) const"; }
|
75 |
+
|
76 |
+
static py::str overloaded(float) { return "static float"; }
|
77 |
+
|
78 |
+
int value = 0;
|
79 |
+
};
|
80 |
+
|
81 |
+
struct TestProperties {
|
82 |
+
int value = 1;
|
83 |
+
static int static_value;
|
84 |
+
|
85 |
+
int get() const { return value; }
|
86 |
+
void set(int v) { value = v; }
|
87 |
+
|
88 |
+
static int static_get() { return static_value; }
|
89 |
+
static void static_set(int v) { static_value = v; }
|
90 |
+
};
|
91 |
+
int TestProperties::static_value = 1;
|
92 |
+
|
93 |
+
struct TestPropertiesOverride : TestProperties {
|
94 |
+
int value = 99;
|
95 |
+
static int static_value;
|
96 |
+
};
|
97 |
+
int TestPropertiesOverride::static_value = 99;
|
98 |
+
|
99 |
+
struct TestPropRVP {
|
100 |
+
UserType v1{1};
|
101 |
+
UserType v2{1};
|
102 |
+
static UserType sv1;
|
103 |
+
static UserType sv2;
|
104 |
+
|
105 |
+
const UserType &get1() const { return v1; }
|
106 |
+
const UserType &get2() const { return v2; }
|
107 |
+
UserType get_rvalue() const { return v2; }
|
108 |
+
void set1(int v) { v1.set(v); }
|
109 |
+
void set2(int v) { v2.set(v); }
|
110 |
+
};
|
111 |
+
UserType TestPropRVP::sv1(1);
|
112 |
+
UserType TestPropRVP::sv2(1);
|
113 |
+
|
114 |
+
// Test None-allowed py::arg argument policy
|
115 |
+
class NoneTester { public: int answer = 42; };
|
116 |
+
int none1(const NoneTester &obj) { return obj.answer; }
|
117 |
+
int none2(NoneTester *obj) { return obj ? obj->answer : -1; }
|
118 |
+
int none3(std::shared_ptr<NoneTester> &obj) { return obj ? obj->answer : -1; }
|
119 |
+
int none4(std::shared_ptr<NoneTester> *obj) { return obj && *obj ? (*obj)->answer : -1; }
|
120 |
+
int none5(const std::shared_ptr<NoneTester> &obj) { return obj ? obj->answer : -1; }
|
121 |
+
|
122 |
+
// Issue #2778: implicit casting from None to object (not pointer)
|
123 |
+
class NoneCastTester {
|
124 |
+
public:
|
125 |
+
int answer = -1;
|
126 |
+
NoneCastTester() = default;
|
127 |
+
NoneCastTester(int v) : answer(v) {}
|
128 |
+
};
|
129 |
+
|
130 |
+
struct StrIssue {
|
131 |
+
int val = -1;
|
132 |
+
|
133 |
+
StrIssue() = default;
|
134 |
+
StrIssue(int i) : val{i} {}
|
135 |
+
};
|
136 |
+
|
137 |
+
// Issues #854, #910: incompatible function args when member function/pointer is in unregistered base class
|
138 |
+
class UnregisteredBase {
|
139 |
+
public:
|
140 |
+
void do_nothing() const {}
|
141 |
+
void increase_value() { rw_value++; ro_value += 0.25; }
|
142 |
+
void set_int(int v) { rw_value = v; }
|
143 |
+
int get_int() const { return rw_value; }
|
144 |
+
double get_double() const { return ro_value; }
|
145 |
+
int rw_value = 42;
|
146 |
+
double ro_value = 1.25;
|
147 |
+
};
|
148 |
+
class RegisteredDerived : public UnregisteredBase {
|
149 |
+
public:
|
150 |
+
using UnregisteredBase::UnregisteredBase;
|
151 |
+
double sum() const { return rw_value + ro_value; }
|
152 |
+
};
|
153 |
+
|
154 |
+
// Test explicit lvalue ref-qualification
|
155 |
+
struct RefQualified {
|
156 |
+
int value = 0;
|
157 |
+
|
158 |
+
void refQualified(int other) & { value += other; }
|
159 |
+
int constRefQualified(int other) const & { return value + other; }
|
160 |
+
};
|
161 |
+
|
162 |
+
TEST_SUBMODULE(methods_and_attributes, m) {
|
163 |
+
// test_methods_and_attributes
|
164 |
+
py::class_<ExampleMandA> emna(m, "ExampleMandA");
|
165 |
+
emna.def(py::init<>())
|
166 |
+
.def(py::init<int>())
|
167 |
+
.def(py::init<std::string&&>())
|
168 |
+
.def(py::init<const ExampleMandA&>())
|
169 |
+
.def("add1", &ExampleMandA::add1)
|
170 |
+
.def("add2", &ExampleMandA::add2)
|
171 |
+
.def("add3", &ExampleMandA::add3)
|
172 |
+
.def("add4", &ExampleMandA::add4)
|
173 |
+
.def("add5", &ExampleMandA::add5)
|
174 |
+
.def("add6", &ExampleMandA::add6)
|
175 |
+
.def("add7", &ExampleMandA::add7)
|
176 |
+
.def("add8", &ExampleMandA::add8)
|
177 |
+
.def("add9", &ExampleMandA::add9)
|
178 |
+
.def("add10", &ExampleMandA::add10)
|
179 |
+
.def("consume_str", &ExampleMandA::consume_str)
|
180 |
+
.def("self1", &ExampleMandA::self1)
|
181 |
+
.def("self2", &ExampleMandA::self2)
|
182 |
+
.def("self3", &ExampleMandA::self3)
|
183 |
+
.def("self4", &ExampleMandA::self4)
|
184 |
+
.def("self5", &ExampleMandA::self5)
|
185 |
+
.def("internal1", &ExampleMandA::internal1)
|
186 |
+
.def("internal2", &ExampleMandA::internal2)
|
187 |
+
.def("internal3", &ExampleMandA::internal3)
|
188 |
+
.def("internal4", &ExampleMandA::internal4)
|
189 |
+
.def("internal5", &ExampleMandA::internal5)
|
190 |
+
#if defined(PYBIND11_OVERLOAD_CAST)
|
191 |
+
.def("overloaded", py::overload_cast<>(&ExampleMandA::overloaded))
|
192 |
+
.def("overloaded", py::overload_cast<int>(&ExampleMandA::overloaded))
|
193 |
+
.def("overloaded", py::overload_cast<int, float>(&ExampleMandA::overloaded))
|
194 |
+
.def("overloaded", py::overload_cast<float, int>(&ExampleMandA::overloaded))
|
195 |
+
.def("overloaded", py::overload_cast<int, int>(&ExampleMandA::overloaded))
|
196 |
+
.def("overloaded", py::overload_cast<float, float>(&ExampleMandA::overloaded))
|
197 |
+
.def("overloaded_float", py::overload_cast<float, float>(&ExampleMandA::overloaded))
|
198 |
+
.def("overloaded_const", py::overload_cast<int >(&ExampleMandA::overloaded, py::const_))
|
199 |
+
.def("overloaded_const", py::overload_cast<int, float>(&ExampleMandA::overloaded, py::const_))
|
200 |
+
.def("overloaded_const", py::overload_cast<float, int>(&ExampleMandA::overloaded, py::const_))
|
201 |
+
.def("overloaded_const", py::overload_cast<int, int>(&ExampleMandA::overloaded, py::const_))
|
202 |
+
.def("overloaded_const", py::overload_cast<float, float>(&ExampleMandA::overloaded, py::const_))
|
203 |
+
#else
|
204 |
+
// Use both the traditional static_cast method and the C++11 compatible overload_cast_
|
205 |
+
.def("overloaded", overload_cast_<>()(&ExampleMandA::overloaded))
|
206 |
+
.def("overloaded", overload_cast_<int>()(&ExampleMandA::overloaded))
|
207 |
+
.def("overloaded", overload_cast_<int, float>()(&ExampleMandA::overloaded))
|
208 |
+
.def("overloaded", static_cast<py::str (ExampleMandA::*)(float, int)>(&ExampleMandA::overloaded))
|
209 |
+
.def("overloaded", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
|
210 |
+
.def("overloaded", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded))
|
211 |
+
.def("overloaded_float", overload_cast_<float, float>()(&ExampleMandA::overloaded))
|
212 |
+
.def("overloaded_const", overload_cast_<int >()(&ExampleMandA::overloaded, py::const_))
|
213 |
+
.def("overloaded_const", overload_cast_<int, float>()(&ExampleMandA::overloaded, py::const_))
|
214 |
+
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, int) const>(&ExampleMandA::overloaded))
|
215 |
+
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, int) const>(&ExampleMandA::overloaded))
|
216 |
+
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, float) const>(&ExampleMandA::overloaded))
|
217 |
+
#endif
|
218 |
+
// test_no_mixed_overloads
|
219 |
+
// Raise error if trying to mix static/non-static overloads on the same name:
|
220 |
+
.def_static("add_mixed_overloads1", []() {
|
221 |
+
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module_::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
|
222 |
+
emna.def ("overload_mixed1", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
|
223 |
+
.def_static("overload_mixed1", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded));
|
224 |
+
})
|
225 |
+
.def_static("add_mixed_overloads2", []() {
|
226 |
+
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module_::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
|
227 |
+
emna.def_static("overload_mixed2", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded))
|
228 |
+
.def ("overload_mixed2", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded));
|
229 |
+
})
|
230 |
+
.def("__str__", &ExampleMandA::toString)
|
231 |
+
.def_readwrite("value", &ExampleMandA::value);
|
232 |
+
|
233 |
+
// test_copy_method
|
234 |
+
// Issue #443: can't call copied methods in Python 3
|
235 |
+
emna.attr("add2b") = emna.attr("add2");
|
236 |
+
|
237 |
+
// test_properties, test_static_properties, test_static_cls
|
238 |
+
py::class_<TestProperties>(m, "TestProperties")
|
239 |
+
.def(py::init<>())
|
240 |
+
.def_readonly("def_readonly", &TestProperties::value)
|
241 |
+
.def_readwrite("def_readwrite", &TestProperties::value)
|
242 |
+
.def_property("def_writeonly", nullptr, [](TestProperties &s, int v) { s.value = v; })
|
243 |
+
.def_property("def_property_writeonly", nullptr, &TestProperties::set)
|
244 |
+
.def_property_readonly("def_property_readonly", &TestProperties::get)
|
245 |
+
.def_property("def_property", &TestProperties::get, &TestProperties::set)
|
246 |
+
.def_property("def_property_impossible", nullptr, nullptr)
|
247 |
+
.def_readonly_static("def_readonly_static", &TestProperties::static_value)
|
248 |
+
.def_readwrite_static("def_readwrite_static", &TestProperties::static_value)
|
249 |
+
.def_property_static("def_writeonly_static",
|
250 |
+
nullptr,
|
251 |
+
[](const py::object &, int v) { TestProperties::static_value = v; })
|
252 |
+
.def_property_readonly_static(
|
253 |
+
"def_property_readonly_static",
|
254 |
+
[](const py::object &) { return TestProperties::static_get(); })
|
255 |
+
.def_property_static(
|
256 |
+
"def_property_writeonly_static",
|
257 |
+
nullptr,
|
258 |
+
[](const py::object &, int v) { return TestProperties::static_set(v); })
|
259 |
+
.def_property_static(
|
260 |
+
"def_property_static",
|
261 |
+
[](const py::object &) { return TestProperties::static_get(); },
|
262 |
+
[](const py::object &, int v) { TestProperties::static_set(v); })
|
263 |
+
.def_property_static(
|
264 |
+
"static_cls",
|
265 |
+
[](py::object cls) { return cls; },
|
266 |
+
[](const py::object &cls, const py::function &f) { f(cls); });
|
267 |
+
|
268 |
+
py::class_<TestPropertiesOverride, TestProperties>(m, "TestPropertiesOverride")
|
269 |
+
.def(py::init<>())
|
270 |
+
.def_readonly("def_readonly", &TestPropertiesOverride::value)
|
271 |
+
.def_readonly_static("def_readonly_static", &TestPropertiesOverride::static_value);
|
272 |
+
|
273 |
+
auto static_get1 = [](const py::object &) -> const UserType & { return TestPropRVP::sv1; };
|
274 |
+
auto static_get2 = [](const py::object &) -> const UserType & { return TestPropRVP::sv2; };
|
275 |
+
auto static_set1 = [](const py::object &, int v) { TestPropRVP::sv1.set(v); };
|
276 |
+
auto static_set2 = [](const py::object &, int v) { TestPropRVP::sv2.set(v); };
|
277 |
+
auto rvp_copy = py::return_value_policy::copy;
|
278 |
+
|
279 |
+
// test_property_return_value_policies
|
280 |
+
py::class_<TestPropRVP>(m, "TestPropRVP")
|
281 |
+
.def(py::init<>())
|
282 |
+
.def_property_readonly("ro_ref", &TestPropRVP::get1)
|
283 |
+
.def_property_readonly("ro_copy", &TestPropRVP::get2, rvp_copy)
|
284 |
+
.def_property_readonly("ro_func", py::cpp_function(&TestPropRVP::get2, rvp_copy))
|
285 |
+
.def_property("rw_ref", &TestPropRVP::get1, &TestPropRVP::set1)
|
286 |
+
.def_property("rw_copy", &TestPropRVP::get2, &TestPropRVP::set2, rvp_copy)
|
287 |
+
.def_property(
|
288 |
+
"rw_func", py::cpp_function(&TestPropRVP::get2, rvp_copy), &TestPropRVP::set2)
|
289 |
+
.def_property_readonly_static("static_ro_ref", static_get1)
|
290 |
+
.def_property_readonly_static("static_ro_copy", static_get2, rvp_copy)
|
291 |
+
.def_property_readonly_static("static_ro_func", py::cpp_function(static_get2, rvp_copy))
|
292 |
+
.def_property_static("static_rw_ref", static_get1, static_set1)
|
293 |
+
.def_property_static("static_rw_copy", static_get2, static_set2, rvp_copy)
|
294 |
+
.def_property_static(
|
295 |
+
"static_rw_func", py::cpp_function(static_get2, rvp_copy), static_set2)
|
296 |
+
// test_property_rvalue_policy
|
297 |
+
.def_property_readonly("rvalue", &TestPropRVP::get_rvalue)
|
298 |
+
.def_property_readonly_static("static_rvalue",
|
299 |
+
[](const py::object &) { return UserType(1); });
|
300 |
+
|
301 |
+
// test_metaclass_override
|
302 |
+
struct MetaclassOverride { };
|
303 |
+
py::class_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type))
|
304 |
+
.def_property_readonly_static("readonly", [](const py::object &) { return 1; });
|
305 |
+
|
306 |
+
// test_overload_ordering
|
307 |
+
m.def("overload_order", [](const std::string &) { return 1; });
|
308 |
+
m.def("overload_order", [](const std::string &) { return 2; });
|
309 |
+
m.def("overload_order", [](int) { return 3; });
|
310 |
+
m.def("overload_order", [](int) { return 4; }, py::prepend{});
|
311 |
+
|
312 |
+
#if !defined(PYPY_VERSION)
|
313 |
+
// test_dynamic_attributes
|
314 |
+
class DynamicClass {
|
315 |
+
public:
|
316 |
+
DynamicClass() { print_default_created(this); }
|
317 |
+
DynamicClass(const DynamicClass&) = delete;
|
318 |
+
~DynamicClass() { print_destroyed(this); }
|
319 |
+
};
|
320 |
+
py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr())
|
321 |
+
.def(py::init());
|
322 |
+
|
323 |
+
class CppDerivedDynamicClass : public DynamicClass { };
|
324 |
+
py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass")
|
325 |
+
.def(py::init());
|
326 |
+
#endif
|
327 |
+
|
328 |
+
// test_bad_arg_default
|
329 |
+
// Issue/PR #648: bad arg default debugging output
|
330 |
+
#if !defined(NDEBUG)
|
331 |
+
m.attr("debug_enabled") = true;
|
332 |
+
#else
|
333 |
+
m.attr("debug_enabled") = false;
|
334 |
+
#endif
|
335 |
+
m.def("bad_arg_def_named", []{
|
336 |
+
auto m = py::module_::import("pybind11_tests");
|
337 |
+
m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg("a") = UnregisteredType());
|
338 |
+
});
|
339 |
+
m.def("bad_arg_def_unnamed", []{
|
340 |
+
auto m = py::module_::import("pybind11_tests");
|
341 |
+
m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType());
|
342 |
+
});
|
343 |
+
|
344 |
+
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
|
345 |
+
|
346 |
+
// test_accepts_none
|
347 |
+
py::class_<NoneTester, std::shared_ptr<NoneTester>>(m, "NoneTester")
|
348 |
+
.def(py::init<>());
|
349 |
+
m.def("no_none1", &none1, py::arg{}.none(false));
|
350 |
+
m.def("no_none2", &none2, py::arg{}.none(false));
|
351 |
+
m.def("no_none3", &none3, py::arg{}.none(false));
|
352 |
+
m.def("no_none4", &none4, py::arg{}.none(false));
|
353 |
+
m.def("no_none5", &none5, py::arg{}.none(false));
|
354 |
+
m.def("ok_none1", &none1);
|
355 |
+
m.def("ok_none2", &none2, py::arg{}.none(true));
|
356 |
+
m.def("ok_none3", &none3);
|
357 |
+
m.def("ok_none4", &none4, py::arg{}.none(true));
|
358 |
+
m.def("ok_none5", &none5);
|
359 |
+
|
360 |
+
m.def("no_none_kwarg", &none2, "a"_a.none(false));
|
361 |
+
m.def("no_none_kwarg_kw_only", &none2, py::kw_only(), "a"_a.none(false));
|
362 |
+
|
363 |
+
// test_casts_none
|
364 |
+
// Issue #2778: implicit casting from None to object (not pointer)
|
365 |
+
py::class_<NoneCastTester>(m, "NoneCastTester")
|
366 |
+
.def(py::init<>())
|
367 |
+
.def(py::init<int>())
|
368 |
+
.def(py::init([](py::none const&) { return NoneCastTester{}; }));
|
369 |
+
py::implicitly_convertible<py::none, NoneCastTester>();
|
370 |
+
m.def("ok_obj_or_none", [](NoneCastTester const& foo) { return foo.answer; });
|
371 |
+
|
372 |
+
|
373 |
+
// test_str_issue
|
374 |
+
// Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
|
375 |
+
py::class_<StrIssue>(m, "StrIssue")
|
376 |
+
.def(py::init<int>())
|
377 |
+
.def(py::init<>())
|
378 |
+
.def("__str__", [](const StrIssue &si) {
|
379 |
+
return "StrIssue[" + std::to_string(si.val) + "]"; }
|
380 |
+
);
|
381 |
+
|
382 |
+
// test_unregistered_base_implementations
|
383 |
+
//
|
384 |
+
// Issues #854/910: incompatible function args when member function/pointer is in unregistered
|
385 |
+
// base class The methods and member pointers below actually resolve to members/pointers in
|
386 |
+
// UnregisteredBase; before this test/fix they would be registered via lambda with a first
|
387 |
+
// argument of an unregistered type, and thus uncallable.
|
388 |
+
py::class_<RegisteredDerived>(m, "RegisteredDerived")
|
389 |
+
.def(py::init<>())
|
390 |
+
.def("do_nothing", &RegisteredDerived::do_nothing)
|
391 |
+
.def("increase_value", &RegisteredDerived::increase_value)
|
392 |
+
.def_readwrite("rw_value", &RegisteredDerived::rw_value)
|
393 |
+
.def_readonly("ro_value", &RegisteredDerived::ro_value)
|
394 |
+
// Uncommenting the next line should trigger a static_assert:
|
395 |
+
// .def_readwrite("fails", &UserType::value)
|
396 |
+
// Uncommenting the next line should trigger a static_assert:
|
397 |
+
// .def_readonly("fails", &UserType::value)
|
398 |
+
.def_property("rw_value_prop", &RegisteredDerived::get_int, &RegisteredDerived::set_int)
|
399 |
+
.def_property_readonly("ro_value_prop", &RegisteredDerived::get_double)
|
400 |
+
// This one is in the registered class:
|
401 |
+
.def("sum", &RegisteredDerived::sum);
|
402 |
+
|
403 |
+
using Adapted = decltype(py::method_adaptor<RegisteredDerived>(&RegisteredDerived::do_nothing));
|
404 |
+
static_assert(std::is_same<Adapted, void (RegisteredDerived::*)() const>::value, "");
|
405 |
+
|
406 |
+
// test_methods_and_attributes
|
407 |
+
py::class_<RefQualified>(m, "RefQualified")
|
408 |
+
.def(py::init<>())
|
409 |
+
.def_readonly("value", &RefQualified::value)
|
410 |
+
.def("refQualified", &RefQualified::refQualified)
|
411 |
+
.def("constRefQualified", &RefQualified::constRefQualified);
|
412 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_methods_and_attributes.py
ADDED
@@ -0,0 +1,518 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
import env # noqa: F401
|
5 |
+
|
6 |
+
from pybind11_tests import methods_and_attributes as m
|
7 |
+
from pybind11_tests import ConstructorStats
|
8 |
+
|
9 |
+
|
10 |
+
def test_methods_and_attributes():
|
11 |
+
instance1 = m.ExampleMandA()
|
12 |
+
instance2 = m.ExampleMandA(32)
|
13 |
+
|
14 |
+
instance1.add1(instance2)
|
15 |
+
instance1.add2(instance2)
|
16 |
+
instance1.add3(instance2)
|
17 |
+
instance1.add4(instance2)
|
18 |
+
instance1.add5(instance2)
|
19 |
+
instance1.add6(32)
|
20 |
+
instance1.add7(32)
|
21 |
+
instance1.add8(32)
|
22 |
+
instance1.add9(32)
|
23 |
+
instance1.add10(32)
|
24 |
+
|
25 |
+
assert str(instance1) == "ExampleMandA[value=320]"
|
26 |
+
assert str(instance2) == "ExampleMandA[value=32]"
|
27 |
+
assert str(instance1.self1()) == "ExampleMandA[value=320]"
|
28 |
+
assert str(instance1.self2()) == "ExampleMandA[value=320]"
|
29 |
+
assert str(instance1.self3()) == "ExampleMandA[value=320]"
|
30 |
+
assert str(instance1.self4()) == "ExampleMandA[value=320]"
|
31 |
+
assert str(instance1.self5()) == "ExampleMandA[value=320]"
|
32 |
+
|
33 |
+
assert instance1.internal1() == 320
|
34 |
+
assert instance1.internal2() == 320
|
35 |
+
assert instance1.internal3() == 320
|
36 |
+
assert instance1.internal4() == 320
|
37 |
+
assert instance1.internal5() == 320
|
38 |
+
|
39 |
+
assert instance1.overloaded() == "()"
|
40 |
+
assert instance1.overloaded(0) == "(int)"
|
41 |
+
assert instance1.overloaded(1, 1.0) == "(int, float)"
|
42 |
+
assert instance1.overloaded(2.0, 2) == "(float, int)"
|
43 |
+
assert instance1.overloaded(3, 3) == "(int, int)"
|
44 |
+
assert instance1.overloaded(4.0, 4.0) == "(float, float)"
|
45 |
+
assert instance1.overloaded_const(-3) == "(int) const"
|
46 |
+
assert instance1.overloaded_const(5, 5.0) == "(int, float) const"
|
47 |
+
assert instance1.overloaded_const(6.0, 6) == "(float, int) const"
|
48 |
+
assert instance1.overloaded_const(7, 7) == "(int, int) const"
|
49 |
+
assert instance1.overloaded_const(8.0, 8.0) == "(float, float) const"
|
50 |
+
assert instance1.overloaded_float(1, 1) == "(float, float)"
|
51 |
+
assert instance1.overloaded_float(1, 1.0) == "(float, float)"
|
52 |
+
assert instance1.overloaded_float(1.0, 1) == "(float, float)"
|
53 |
+
assert instance1.overloaded_float(1.0, 1.0) == "(float, float)"
|
54 |
+
|
55 |
+
assert instance1.value == 320
|
56 |
+
instance1.value = 100
|
57 |
+
assert str(instance1) == "ExampleMandA[value=100]"
|
58 |
+
|
59 |
+
cstats = ConstructorStats.get(m.ExampleMandA)
|
60 |
+
assert cstats.alive() == 2
|
61 |
+
del instance1, instance2
|
62 |
+
assert cstats.alive() == 0
|
63 |
+
assert cstats.values() == ["32"]
|
64 |
+
assert cstats.default_constructions == 1
|
65 |
+
assert cstats.copy_constructions == 2
|
66 |
+
assert cstats.move_constructions >= 2
|
67 |
+
assert cstats.copy_assignments == 0
|
68 |
+
assert cstats.move_assignments == 0
|
69 |
+
|
70 |
+
|
71 |
+
def test_copy_method():
|
72 |
+
"""Issue #443: calling copied methods fails in Python 3"""
|
73 |
+
|
74 |
+
m.ExampleMandA.add2c = m.ExampleMandA.add2
|
75 |
+
m.ExampleMandA.add2d = m.ExampleMandA.add2b
|
76 |
+
a = m.ExampleMandA(123)
|
77 |
+
assert a.value == 123
|
78 |
+
a.add2(m.ExampleMandA(-100))
|
79 |
+
assert a.value == 23
|
80 |
+
a.add2b(m.ExampleMandA(20))
|
81 |
+
assert a.value == 43
|
82 |
+
a.add2c(m.ExampleMandA(6))
|
83 |
+
assert a.value == 49
|
84 |
+
a.add2d(m.ExampleMandA(-7))
|
85 |
+
assert a.value == 42
|
86 |
+
|
87 |
+
|
88 |
+
def test_properties():
|
89 |
+
instance = m.TestProperties()
|
90 |
+
|
91 |
+
assert instance.def_readonly == 1
|
92 |
+
with pytest.raises(AttributeError):
|
93 |
+
instance.def_readonly = 2
|
94 |
+
|
95 |
+
instance.def_readwrite = 2
|
96 |
+
assert instance.def_readwrite == 2
|
97 |
+
|
98 |
+
assert instance.def_property_readonly == 2
|
99 |
+
with pytest.raises(AttributeError):
|
100 |
+
instance.def_property_readonly = 3
|
101 |
+
|
102 |
+
instance.def_property = 3
|
103 |
+
assert instance.def_property == 3
|
104 |
+
|
105 |
+
with pytest.raises(AttributeError) as excinfo:
|
106 |
+
dummy = instance.def_property_writeonly # noqa: F841 unused var
|
107 |
+
assert "unreadable attribute" in str(excinfo.value)
|
108 |
+
|
109 |
+
instance.def_property_writeonly = 4
|
110 |
+
assert instance.def_property_readonly == 4
|
111 |
+
|
112 |
+
with pytest.raises(AttributeError) as excinfo:
|
113 |
+
dummy = instance.def_property_impossible # noqa: F841 unused var
|
114 |
+
assert "unreadable attribute" in str(excinfo.value)
|
115 |
+
|
116 |
+
with pytest.raises(AttributeError) as excinfo:
|
117 |
+
instance.def_property_impossible = 5
|
118 |
+
assert "can't set attribute" in str(excinfo.value)
|
119 |
+
|
120 |
+
|
121 |
+
def test_static_properties():
|
122 |
+
assert m.TestProperties.def_readonly_static == 1
|
123 |
+
with pytest.raises(AttributeError) as excinfo:
|
124 |
+
m.TestProperties.def_readonly_static = 2
|
125 |
+
assert "can't set attribute" in str(excinfo.value)
|
126 |
+
|
127 |
+
m.TestProperties.def_readwrite_static = 2
|
128 |
+
assert m.TestProperties.def_readwrite_static == 2
|
129 |
+
|
130 |
+
with pytest.raises(AttributeError) as excinfo:
|
131 |
+
dummy = m.TestProperties.def_writeonly_static # noqa: F841 unused var
|
132 |
+
assert "unreadable attribute" in str(excinfo.value)
|
133 |
+
|
134 |
+
m.TestProperties.def_writeonly_static = 3
|
135 |
+
assert m.TestProperties.def_readonly_static == 3
|
136 |
+
|
137 |
+
assert m.TestProperties.def_property_readonly_static == 3
|
138 |
+
with pytest.raises(AttributeError) as excinfo:
|
139 |
+
m.TestProperties.def_property_readonly_static = 99
|
140 |
+
assert "can't set attribute" in str(excinfo.value)
|
141 |
+
|
142 |
+
m.TestProperties.def_property_static = 4
|
143 |
+
assert m.TestProperties.def_property_static == 4
|
144 |
+
|
145 |
+
with pytest.raises(AttributeError) as excinfo:
|
146 |
+
dummy = m.TestProperties.def_property_writeonly_static
|
147 |
+
assert "unreadable attribute" in str(excinfo.value)
|
148 |
+
|
149 |
+
m.TestProperties.def_property_writeonly_static = 5
|
150 |
+
assert m.TestProperties.def_property_static == 5
|
151 |
+
|
152 |
+
# Static property read and write via instance
|
153 |
+
instance = m.TestProperties()
|
154 |
+
|
155 |
+
m.TestProperties.def_readwrite_static = 0
|
156 |
+
assert m.TestProperties.def_readwrite_static == 0
|
157 |
+
assert instance.def_readwrite_static == 0
|
158 |
+
|
159 |
+
instance.def_readwrite_static = 2
|
160 |
+
assert m.TestProperties.def_readwrite_static == 2
|
161 |
+
assert instance.def_readwrite_static == 2
|
162 |
+
|
163 |
+
with pytest.raises(AttributeError) as excinfo:
|
164 |
+
dummy = instance.def_property_writeonly_static # noqa: F841 unused var
|
165 |
+
assert "unreadable attribute" in str(excinfo.value)
|
166 |
+
|
167 |
+
instance.def_property_writeonly_static = 4
|
168 |
+
assert instance.def_property_static == 4
|
169 |
+
|
170 |
+
# It should be possible to override properties in derived classes
|
171 |
+
assert m.TestPropertiesOverride().def_readonly == 99
|
172 |
+
assert m.TestPropertiesOverride.def_readonly_static == 99
|
173 |
+
|
174 |
+
# Only static attributes can be deleted
|
175 |
+
del m.TestPropertiesOverride.def_readonly_static
|
176 |
+
assert (
|
177 |
+
hasattr(m.TestPropertiesOverride, "def_readonly_static")
|
178 |
+
and m.TestPropertiesOverride.def_readonly_static
|
179 |
+
is m.TestProperties.def_readonly_static
|
180 |
+
)
|
181 |
+
assert "def_readonly_static" not in m.TestPropertiesOverride.__dict__
|
182 |
+
properties_override = m.TestPropertiesOverride()
|
183 |
+
with pytest.raises(AttributeError) as excinfo:
|
184 |
+
del properties_override.def_readonly
|
185 |
+
assert "can't delete attribute" in str(excinfo.value)
|
186 |
+
|
187 |
+
|
188 |
+
def test_static_cls():
|
189 |
+
"""Static property getter and setters expect the type object as the their only argument"""
|
190 |
+
|
191 |
+
instance = m.TestProperties()
|
192 |
+
assert m.TestProperties.static_cls is m.TestProperties
|
193 |
+
assert instance.static_cls is m.TestProperties
|
194 |
+
|
195 |
+
def check_self(self):
|
196 |
+
assert self is m.TestProperties
|
197 |
+
|
198 |
+
m.TestProperties.static_cls = check_self
|
199 |
+
instance.static_cls = check_self
|
200 |
+
|
201 |
+
|
202 |
+
def test_metaclass_override():
|
203 |
+
"""Overriding pybind11's default metaclass changes the behavior of `static_property`"""
|
204 |
+
|
205 |
+
assert type(m.ExampleMandA).__name__ == "pybind11_type"
|
206 |
+
assert type(m.MetaclassOverride).__name__ == "type"
|
207 |
+
|
208 |
+
assert m.MetaclassOverride.readonly == 1
|
209 |
+
assert (
|
210 |
+
type(m.MetaclassOverride.__dict__["readonly"]).__name__
|
211 |
+
== "pybind11_static_property"
|
212 |
+
)
|
213 |
+
|
214 |
+
# Regular `type` replaces the property instead of calling `__set__()`
|
215 |
+
m.MetaclassOverride.readonly = 2
|
216 |
+
assert m.MetaclassOverride.readonly == 2
|
217 |
+
assert isinstance(m.MetaclassOverride.__dict__["readonly"], int)
|
218 |
+
|
219 |
+
|
220 |
+
def test_no_mixed_overloads():
|
221 |
+
from pybind11_tests import debug_enabled
|
222 |
+
|
223 |
+
with pytest.raises(RuntimeError) as excinfo:
|
224 |
+
m.ExampleMandA.add_mixed_overloads1()
|
225 |
+
assert str(
|
226 |
+
excinfo.value
|
227 |
+
) == "overloading a method with both static and instance methods is not supported; " + (
|
228 |
+
"compile in debug mode for more details"
|
229 |
+
if not debug_enabled
|
230 |
+
else "error while attempting to bind static method ExampleMandA.overload_mixed1"
|
231 |
+
"(arg0: float) -> str"
|
232 |
+
)
|
233 |
+
|
234 |
+
with pytest.raises(RuntimeError) as excinfo:
|
235 |
+
m.ExampleMandA.add_mixed_overloads2()
|
236 |
+
assert str(
|
237 |
+
excinfo.value
|
238 |
+
) == "overloading a method with both static and instance methods is not supported; " + (
|
239 |
+
"compile in debug mode for more details"
|
240 |
+
if not debug_enabled
|
241 |
+
else "error while attempting to bind instance method ExampleMandA.overload_mixed2"
|
242 |
+
"(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)"
|
243 |
+
" -> str"
|
244 |
+
)
|
245 |
+
|
246 |
+
|
247 |
+
@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
|
248 |
+
def test_property_return_value_policies(access):
|
249 |
+
if not access.startswith("static"):
|
250 |
+
obj = m.TestPropRVP()
|
251 |
+
else:
|
252 |
+
obj = m.TestPropRVP
|
253 |
+
|
254 |
+
ref = getattr(obj, access + "_ref")
|
255 |
+
assert ref.value == 1
|
256 |
+
ref.value = 2
|
257 |
+
assert getattr(obj, access + "_ref").value == 2
|
258 |
+
ref.value = 1 # restore original value for static properties
|
259 |
+
|
260 |
+
copy = getattr(obj, access + "_copy")
|
261 |
+
assert copy.value == 1
|
262 |
+
copy.value = 2
|
263 |
+
assert getattr(obj, access + "_copy").value == 1
|
264 |
+
|
265 |
+
copy = getattr(obj, access + "_func")
|
266 |
+
assert copy.value == 1
|
267 |
+
copy.value = 2
|
268 |
+
assert getattr(obj, access + "_func").value == 1
|
269 |
+
|
270 |
+
|
271 |
+
def test_property_rvalue_policy():
|
272 |
+
"""When returning an rvalue, the return value policy is automatically changed from
|
273 |
+
`reference(_internal)` to `move`. The following would not work otherwise."""
|
274 |
+
|
275 |
+
instance = m.TestPropRVP()
|
276 |
+
o = instance.rvalue
|
277 |
+
assert o.value == 1
|
278 |
+
|
279 |
+
os = m.TestPropRVP.static_rvalue
|
280 |
+
assert os.value == 1
|
281 |
+
|
282 |
+
|
283 |
+
# https://foss.heptapod.net/pypy/pypy/-/issues/2447
|
284 |
+
@pytest.mark.xfail("env.PYPY")
|
285 |
+
def test_dynamic_attributes():
|
286 |
+
instance = m.DynamicClass()
|
287 |
+
assert not hasattr(instance, "foo")
|
288 |
+
assert "foo" not in dir(instance)
|
289 |
+
|
290 |
+
# Dynamically add attribute
|
291 |
+
instance.foo = 42
|
292 |
+
assert hasattr(instance, "foo")
|
293 |
+
assert instance.foo == 42
|
294 |
+
assert "foo" in dir(instance)
|
295 |
+
|
296 |
+
# __dict__ should be accessible and replaceable
|
297 |
+
assert "foo" in instance.__dict__
|
298 |
+
instance.__dict__ = {"bar": True}
|
299 |
+
assert not hasattr(instance, "foo")
|
300 |
+
assert hasattr(instance, "bar")
|
301 |
+
|
302 |
+
with pytest.raises(TypeError) as excinfo:
|
303 |
+
instance.__dict__ = []
|
304 |
+
assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'"
|
305 |
+
|
306 |
+
cstats = ConstructorStats.get(m.DynamicClass)
|
307 |
+
assert cstats.alive() == 1
|
308 |
+
del instance
|
309 |
+
assert cstats.alive() == 0
|
310 |
+
|
311 |
+
# Derived classes should work as well
|
312 |
+
class PythonDerivedDynamicClass(m.DynamicClass):
|
313 |
+
pass
|
314 |
+
|
315 |
+
for cls in m.CppDerivedDynamicClass, PythonDerivedDynamicClass:
|
316 |
+
derived = cls()
|
317 |
+
derived.foobar = 100
|
318 |
+
assert derived.foobar == 100
|
319 |
+
|
320 |
+
assert cstats.alive() == 1
|
321 |
+
del derived
|
322 |
+
assert cstats.alive() == 0
|
323 |
+
|
324 |
+
|
325 |
+
# https://foss.heptapod.net/pypy/pypy/-/issues/2447
|
326 |
+
@pytest.mark.xfail("env.PYPY")
|
327 |
+
def test_cyclic_gc():
|
328 |
+
# One object references itself
|
329 |
+
instance = m.DynamicClass()
|
330 |
+
instance.circular_reference = instance
|
331 |
+
|
332 |
+
cstats = ConstructorStats.get(m.DynamicClass)
|
333 |
+
assert cstats.alive() == 1
|
334 |
+
del instance
|
335 |
+
assert cstats.alive() == 0
|
336 |
+
|
337 |
+
# Two object reference each other
|
338 |
+
i1 = m.DynamicClass()
|
339 |
+
i2 = m.DynamicClass()
|
340 |
+
i1.cycle = i2
|
341 |
+
i2.cycle = i1
|
342 |
+
|
343 |
+
assert cstats.alive() == 2
|
344 |
+
del i1, i2
|
345 |
+
assert cstats.alive() == 0
|
346 |
+
|
347 |
+
|
348 |
+
def test_bad_arg_default(msg):
|
349 |
+
from pybind11_tests import debug_enabled
|
350 |
+
|
351 |
+
with pytest.raises(RuntimeError) as excinfo:
|
352 |
+
m.bad_arg_def_named()
|
353 |
+
assert msg(excinfo.value) == (
|
354 |
+
"arg(): could not convert default argument 'a: UnregisteredType' in function "
|
355 |
+
"'should_fail' into a Python object (type not registered yet?)"
|
356 |
+
if debug_enabled
|
357 |
+
else "arg(): could not convert default argument into a Python object (type not registered "
|
358 |
+
"yet?). Compile in debug mode for more information."
|
359 |
+
)
|
360 |
+
|
361 |
+
with pytest.raises(RuntimeError) as excinfo:
|
362 |
+
m.bad_arg_def_unnamed()
|
363 |
+
assert msg(excinfo.value) == (
|
364 |
+
"arg(): could not convert default argument 'UnregisteredType' in function "
|
365 |
+
"'should_fail' into a Python object (type not registered yet?)"
|
366 |
+
if debug_enabled
|
367 |
+
else "arg(): could not convert default argument into a Python object (type not registered "
|
368 |
+
"yet?). Compile in debug mode for more information."
|
369 |
+
)
|
370 |
+
|
371 |
+
|
372 |
+
def test_accepts_none(msg):
|
373 |
+
a = m.NoneTester()
|
374 |
+
assert m.no_none1(a) == 42
|
375 |
+
assert m.no_none2(a) == 42
|
376 |
+
assert m.no_none3(a) == 42
|
377 |
+
assert m.no_none4(a) == 42
|
378 |
+
assert m.no_none5(a) == 42
|
379 |
+
assert m.ok_none1(a) == 42
|
380 |
+
assert m.ok_none2(a) == 42
|
381 |
+
assert m.ok_none3(a) == 42
|
382 |
+
assert m.ok_none4(a) == 42
|
383 |
+
assert m.ok_none5(a) == 42
|
384 |
+
|
385 |
+
with pytest.raises(TypeError) as excinfo:
|
386 |
+
m.no_none1(None)
|
387 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
388 |
+
with pytest.raises(TypeError) as excinfo:
|
389 |
+
m.no_none2(None)
|
390 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
391 |
+
with pytest.raises(TypeError) as excinfo:
|
392 |
+
m.no_none3(None)
|
393 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
394 |
+
with pytest.raises(TypeError) as excinfo:
|
395 |
+
m.no_none4(None)
|
396 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
397 |
+
with pytest.raises(TypeError) as excinfo:
|
398 |
+
m.no_none5(None)
|
399 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
400 |
+
|
401 |
+
# The first one still raises because you can't pass None as a lvalue reference arg:
|
402 |
+
with pytest.raises(TypeError) as excinfo:
|
403 |
+
assert m.ok_none1(None) == -1
|
404 |
+
assert (
|
405 |
+
msg(excinfo.value)
|
406 |
+
== """
|
407 |
+
ok_none1(): incompatible function arguments. The following argument types are supported:
|
408 |
+
1. (arg0: m.methods_and_attributes.NoneTester) -> int
|
409 |
+
|
410 |
+
Invoked with: None
|
411 |
+
"""
|
412 |
+
)
|
413 |
+
|
414 |
+
# The rest take the argument as pointer or holder, and accept None:
|
415 |
+
assert m.ok_none2(None) == -1
|
416 |
+
assert m.ok_none3(None) == -1
|
417 |
+
assert m.ok_none4(None) == -1
|
418 |
+
assert m.ok_none5(None) == -1
|
419 |
+
|
420 |
+
with pytest.raises(TypeError) as excinfo:
|
421 |
+
m.no_none_kwarg(None)
|
422 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
423 |
+
with pytest.raises(TypeError) as excinfo:
|
424 |
+
m.no_none_kwarg(a=None)
|
425 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
426 |
+
with pytest.raises(TypeError) as excinfo:
|
427 |
+
m.no_none_kwarg_kw_only(None)
|
428 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
429 |
+
with pytest.raises(TypeError) as excinfo:
|
430 |
+
m.no_none_kwarg_kw_only(a=None)
|
431 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
432 |
+
|
433 |
+
|
434 |
+
def test_casts_none():
|
435 |
+
"""#2778: implicit casting from None to object (not pointer)"""
|
436 |
+
a = m.NoneCastTester()
|
437 |
+
assert m.ok_obj_or_none(a) == -1
|
438 |
+
a = m.NoneCastTester(4)
|
439 |
+
assert m.ok_obj_or_none(a) == 4
|
440 |
+
a = m.NoneCastTester(None)
|
441 |
+
assert m.ok_obj_or_none(a) == -1
|
442 |
+
assert m.ok_obj_or_none(None) == -1
|
443 |
+
|
444 |
+
|
445 |
+
def test_str_issue(msg):
|
446 |
+
"""#283: __str__ called on uninitialized instance when constructor arguments invalid"""
|
447 |
+
|
448 |
+
assert str(m.StrIssue(3)) == "StrIssue[3]"
|
449 |
+
|
450 |
+
with pytest.raises(TypeError) as excinfo:
|
451 |
+
str(m.StrIssue("no", "such", "constructor"))
|
452 |
+
assert (
|
453 |
+
msg(excinfo.value)
|
454 |
+
== """
|
455 |
+
__init__(): incompatible constructor arguments. The following argument types are supported:
|
456 |
+
1. m.methods_and_attributes.StrIssue(arg0: int)
|
457 |
+
2. m.methods_and_attributes.StrIssue()
|
458 |
+
|
459 |
+
Invoked with: 'no', 'such', 'constructor'
|
460 |
+
"""
|
461 |
+
)
|
462 |
+
|
463 |
+
|
464 |
+
def test_unregistered_base_implementations():
|
465 |
+
a = m.RegisteredDerived()
|
466 |
+
a.do_nothing()
|
467 |
+
assert a.rw_value == 42
|
468 |
+
assert a.ro_value == 1.25
|
469 |
+
a.rw_value += 5
|
470 |
+
assert a.sum() == 48.25
|
471 |
+
a.increase_value()
|
472 |
+
assert a.rw_value == 48
|
473 |
+
assert a.ro_value == 1.5
|
474 |
+
assert a.sum() == 49.5
|
475 |
+
assert a.rw_value_prop == 48
|
476 |
+
a.rw_value_prop += 1
|
477 |
+
assert a.rw_value_prop == 49
|
478 |
+
a.increase_value()
|
479 |
+
assert a.ro_value_prop == 1.75
|
480 |
+
|
481 |
+
|
482 |
+
def test_ref_qualified():
|
483 |
+
"""Tests that explicit lvalue ref-qualified methods can be called just like their
|
484 |
+
non ref-qualified counterparts."""
|
485 |
+
|
486 |
+
r = m.RefQualified()
|
487 |
+
assert r.value == 0
|
488 |
+
r.refQualified(17)
|
489 |
+
assert r.value == 17
|
490 |
+
assert r.constRefQualified(23) == 40
|
491 |
+
|
492 |
+
|
493 |
+
def test_overload_ordering():
|
494 |
+
"Check to see if the normal overload order (first defined) and prepend overload order works"
|
495 |
+
assert m.overload_order("string") == 1
|
496 |
+
assert m.overload_order(0) == 4
|
497 |
+
|
498 |
+
# Different for Python 2 vs. 3
|
499 |
+
uni_name = type(u"").__name__
|
500 |
+
|
501 |
+
assert "1. overload_order(arg0: int) -> int" in m.overload_order.__doc__
|
502 |
+
assert (
|
503 |
+
"2. overload_order(arg0: {}) -> int".format(uni_name)
|
504 |
+
in m.overload_order.__doc__
|
505 |
+
)
|
506 |
+
assert (
|
507 |
+
"3. overload_order(arg0: {}) -> int".format(uni_name)
|
508 |
+
in m.overload_order.__doc__
|
509 |
+
)
|
510 |
+
assert "4. overload_order(arg0: int) -> int" in m.overload_order.__doc__
|
511 |
+
|
512 |
+
with pytest.raises(TypeError) as err:
|
513 |
+
m.overload_order(1.1)
|
514 |
+
|
515 |
+
assert "1. (arg0: int) -> int" in str(err.value)
|
516 |
+
assert "2. (arg0: {}) -> int".format(uni_name) in str(err.value)
|
517 |
+
assert "3. (arg0: {}) -> int".format(uni_name) in str(err.value)
|
518 |
+
assert "4. (arg0: int) -> int" in str(err.value)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_modules.cpp
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_modules.cpp -- nested modules, importing modules, and
|
3 |
+
internal references
|
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 |
+
#include "constructor_stats.h"
|
13 |
+
|
14 |
+
TEST_SUBMODULE(modules, m) {
|
15 |
+
// test_nested_modules
|
16 |
+
// This is intentionally "py::module" to verify it still can be used in place of "py::module_"
|
17 |
+
py::module m_sub = m.def_submodule("subsubmodule");
|
18 |
+
m_sub.def("submodule_func", []() { return "submodule_func()"; });
|
19 |
+
|
20 |
+
// test_reference_internal
|
21 |
+
class A {
|
22 |
+
public:
|
23 |
+
A(int v) : v(v) { print_created(this, v); }
|
24 |
+
~A() { print_destroyed(this); }
|
25 |
+
A(const A&) { print_copy_created(this); }
|
26 |
+
A& operator=(const A ©) { print_copy_assigned(this); v = copy.v; return *this; }
|
27 |
+
std::string toString() const { return "A[" + std::to_string(v) + "]"; }
|
28 |
+
|
29 |
+
private:
|
30 |
+
int v;
|
31 |
+
};
|
32 |
+
py::class_<A>(m_sub, "A")
|
33 |
+
.def(py::init<int>())
|
34 |
+
.def("__repr__", &A::toString);
|
35 |
+
|
36 |
+
class B {
|
37 |
+
public:
|
38 |
+
B() { print_default_created(this); }
|
39 |
+
~B() { print_destroyed(this); }
|
40 |
+
B(const B&) { print_copy_created(this); }
|
41 |
+
B& operator=(const B ©) { print_copy_assigned(this); a1 = copy.a1; a2 = copy.a2; return *this; }
|
42 |
+
A &get_a1() { return a1; }
|
43 |
+
A &get_a2() { return a2; }
|
44 |
+
|
45 |
+
A a1{1};
|
46 |
+
A a2{2};
|
47 |
+
};
|
48 |
+
py::class_<B>(m_sub, "B")
|
49 |
+
.def(py::init<>())
|
50 |
+
.def("get_a1", &B::get_a1, "Return the internal A 1", py::return_value_policy::reference_internal)
|
51 |
+
.def("get_a2", &B::get_a2, "Return the internal A 2", py::return_value_policy::reference_internal)
|
52 |
+
.def_readwrite("a1", &B::a1) // def_readonly uses an internal reference return policy by default
|
53 |
+
.def_readwrite("a2", &B::a2);
|
54 |
+
|
55 |
+
// This is intentionally "py::module" to verify it still can be used in place of "py::module_"
|
56 |
+
m.attr("OD") = py::module::import("collections").attr("OrderedDict");
|
57 |
+
|
58 |
+
// test_duplicate_registration
|
59 |
+
// Registering two things with the same name
|
60 |
+
m.def("duplicate_registration", []() {
|
61 |
+
class Dupe1 { };
|
62 |
+
class Dupe2 { };
|
63 |
+
class Dupe3 { };
|
64 |
+
class DupeException { };
|
65 |
+
|
66 |
+
// Go ahead and leak, until we have a non-leaking py::module_ constructor
|
67 |
+
auto dm = py::module_::create_extension_module("dummy", nullptr, new py::module_::module_def);
|
68 |
+
auto failures = py::list();
|
69 |
+
|
70 |
+
py::class_<Dupe1>(dm, "Dupe1");
|
71 |
+
py::class_<Dupe2>(dm, "Dupe2");
|
72 |
+
dm.def("dupe1_factory", []() { return Dupe1(); });
|
73 |
+
py::exception<DupeException>(dm, "DupeException");
|
74 |
+
|
75 |
+
try {
|
76 |
+
py::class_<Dupe1>(dm, "Dupe1");
|
77 |
+
failures.append("Dupe1 class");
|
78 |
+
} catch (std::runtime_error &) {}
|
79 |
+
try {
|
80 |
+
dm.def("Dupe1", []() { return Dupe1(); });
|
81 |
+
failures.append("Dupe1 function");
|
82 |
+
} catch (std::runtime_error &) {}
|
83 |
+
try {
|
84 |
+
py::class_<Dupe3>(dm, "dupe1_factory");
|
85 |
+
failures.append("dupe1_factory");
|
86 |
+
} catch (std::runtime_error &) {}
|
87 |
+
try {
|
88 |
+
py::exception<Dupe3>(dm, "Dupe2");
|
89 |
+
failures.append("Dupe2");
|
90 |
+
} catch (std::runtime_error &) {}
|
91 |
+
try {
|
92 |
+
dm.def("DupeException", []() { return 30; });
|
93 |
+
failures.append("DupeException1");
|
94 |
+
} catch (std::runtime_error &) {}
|
95 |
+
try {
|
96 |
+
py::class_<DupeException>(dm, "DupeException");
|
97 |
+
failures.append("DupeException2");
|
98 |
+
} catch (std::runtime_error &) {}
|
99 |
+
|
100 |
+
return failures;
|
101 |
+
});
|
102 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_modules.py
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
from pybind11_tests import modules as m
|
3 |
+
from pybind11_tests.modules import subsubmodule as ms
|
4 |
+
from pybind11_tests import ConstructorStats
|
5 |
+
|
6 |
+
|
7 |
+
def test_nested_modules():
|
8 |
+
import pybind11_tests
|
9 |
+
|
10 |
+
assert pybind11_tests.__name__ == "pybind11_tests"
|
11 |
+
assert pybind11_tests.modules.__name__ == "pybind11_tests.modules"
|
12 |
+
assert (
|
13 |
+
pybind11_tests.modules.subsubmodule.__name__
|
14 |
+
== "pybind11_tests.modules.subsubmodule"
|
15 |
+
)
|
16 |
+
assert m.__name__ == "pybind11_tests.modules"
|
17 |
+
assert ms.__name__ == "pybind11_tests.modules.subsubmodule"
|
18 |
+
|
19 |
+
assert ms.submodule_func() == "submodule_func()"
|
20 |
+
|
21 |
+
|
22 |
+
def test_reference_internal():
|
23 |
+
b = ms.B()
|
24 |
+
assert str(b.get_a1()) == "A[1]"
|
25 |
+
assert str(b.a1) == "A[1]"
|
26 |
+
assert str(b.get_a2()) == "A[2]"
|
27 |
+
assert str(b.a2) == "A[2]"
|
28 |
+
|
29 |
+
b.a1 = ms.A(42)
|
30 |
+
b.a2 = ms.A(43)
|
31 |
+
assert str(b.get_a1()) == "A[42]"
|
32 |
+
assert str(b.a1) == "A[42]"
|
33 |
+
assert str(b.get_a2()) == "A[43]"
|
34 |
+
assert str(b.a2) == "A[43]"
|
35 |
+
|
36 |
+
astats, bstats = ConstructorStats.get(ms.A), ConstructorStats.get(ms.B)
|
37 |
+
assert astats.alive() == 2
|
38 |
+
assert bstats.alive() == 1
|
39 |
+
del b
|
40 |
+
assert astats.alive() == 0
|
41 |
+
assert bstats.alive() == 0
|
42 |
+
assert astats.values() == ["1", "2", "42", "43"]
|
43 |
+
assert bstats.values() == []
|
44 |
+
assert astats.default_constructions == 0
|
45 |
+
assert bstats.default_constructions == 1
|
46 |
+
assert astats.copy_constructions == 0
|
47 |
+
assert bstats.copy_constructions == 0
|
48 |
+
# assert astats.move_constructions >= 0 # Don't invoke any
|
49 |
+
# assert bstats.move_constructions >= 0 # Don't invoke any
|
50 |
+
assert astats.copy_assignments == 2
|
51 |
+
assert bstats.copy_assignments == 0
|
52 |
+
assert astats.move_assignments == 0
|
53 |
+
assert bstats.move_assignments == 0
|
54 |
+
|
55 |
+
|
56 |
+
def test_importing():
|
57 |
+
from pybind11_tests.modules import OD
|
58 |
+
from collections import OrderedDict
|
59 |
+
|
60 |
+
assert OD is OrderedDict
|
61 |
+
assert str(OD([(1, "a"), (2, "b")])) == "OrderedDict([(1, 'a'), (2, 'b')])"
|
62 |
+
|
63 |
+
|
64 |
+
def test_pydoc():
|
65 |
+
"""Pydoc needs to be able to provide help() for everything inside a pybind11 module"""
|
66 |
+
import pybind11_tests
|
67 |
+
import pydoc
|
68 |
+
|
69 |
+
assert pybind11_tests.__name__ == "pybind11_tests"
|
70 |
+
assert pybind11_tests.__doc__ == "pybind11 test module"
|
71 |
+
assert pydoc.text.docmodule(pybind11_tests)
|
72 |
+
|
73 |
+
|
74 |
+
def test_duplicate_registration():
|
75 |
+
"""Registering two things with the same name"""
|
76 |
+
|
77 |
+
assert m.duplicate_registration() == []
|
78 |
+
|
79 |
+
|
80 |
+
def test_builtin_key_type():
|
81 |
+
"""Test that all the keys in the builtin modules have type str.
|
82 |
+
|
83 |
+
Previous versions of pybind11 would add a unicode key in python 2.
|
84 |
+
"""
|
85 |
+
if hasattr(__builtins__, "keys"):
|
86 |
+
keys = __builtins__.keys()
|
87 |
+
else: # this is to make pypy happy since builtins is different there.
|
88 |
+
keys = __builtins__.__dict__.keys()
|
89 |
+
|
90 |
+
assert {type(k) for k in keys} == {str}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_multiple_inheritance.cpp
ADDED
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_multiple_inheritance.cpp -- multiple inheritance,
|
3 |
+
implicit MI casts
|
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 |
+
#include "constructor_stats.h"
|
13 |
+
|
14 |
+
namespace {
|
15 |
+
|
16 |
+
// Many bases for testing that multiple inheritance from many classes (i.e. requiring extra
|
17 |
+
// space for holder constructed flags) works.
|
18 |
+
template <int N> struct BaseN {
|
19 |
+
BaseN(int i) : i(i) { }
|
20 |
+
int i;
|
21 |
+
};
|
22 |
+
|
23 |
+
// test_mi_static_properties
|
24 |
+
struct Vanilla {
|
25 |
+
std::string vanilla() { return "Vanilla"; };
|
26 |
+
};
|
27 |
+
struct WithStatic1 {
|
28 |
+
static std::string static_func1() { return "WithStatic1"; };
|
29 |
+
static int static_value1;
|
30 |
+
};
|
31 |
+
struct WithStatic2 {
|
32 |
+
static std::string static_func2() { return "WithStatic2"; };
|
33 |
+
static int static_value2;
|
34 |
+
};
|
35 |
+
struct VanillaStaticMix1 : Vanilla, WithStatic1, WithStatic2 {
|
36 |
+
static std::string static_func() { return "VanillaStaticMix1"; }
|
37 |
+
static int static_value;
|
38 |
+
};
|
39 |
+
struct VanillaStaticMix2 : WithStatic1, Vanilla, WithStatic2 {
|
40 |
+
static std::string static_func() { return "VanillaStaticMix2"; }
|
41 |
+
static int static_value;
|
42 |
+
};
|
43 |
+
int WithStatic1::static_value1 = 1;
|
44 |
+
int WithStatic2::static_value2 = 2;
|
45 |
+
int VanillaStaticMix1::static_value = 12;
|
46 |
+
int VanillaStaticMix2::static_value = 12;
|
47 |
+
|
48 |
+
// test_multiple_inheritance_virtbase
|
49 |
+
struct Base1a {
|
50 |
+
Base1a(int i) : i(i) { }
|
51 |
+
int foo() const { return i; }
|
52 |
+
int i;
|
53 |
+
};
|
54 |
+
struct Base2a {
|
55 |
+
Base2a(int i) : i(i) { }
|
56 |
+
int bar() const { return i; }
|
57 |
+
int i;
|
58 |
+
};
|
59 |
+
struct Base12a : Base1a, Base2a {
|
60 |
+
Base12a(int i, int j) : Base1a(i), Base2a(j) { }
|
61 |
+
};
|
62 |
+
|
63 |
+
// test_mi_unaligned_base
|
64 |
+
// test_mi_base_return
|
65 |
+
struct I801B1 { int a = 1; I801B1() = default; I801B1(const I801B1 &) = default; virtual ~I801B1() = default; };
|
66 |
+
struct I801B2 { int b = 2; I801B2() = default; I801B2(const I801B2 &) = default; virtual ~I801B2() = default; };
|
67 |
+
struct I801C : I801B1, I801B2 {};
|
68 |
+
struct I801D : I801C {}; // Indirect MI
|
69 |
+
|
70 |
+
} // namespace
|
71 |
+
|
72 |
+
TEST_SUBMODULE(multiple_inheritance, m) {
|
73 |
+
// Please do not interleave `struct` and `class` definitions with bindings code,
|
74 |
+
// but implement `struct`s and `class`es in the anonymous namespace above.
|
75 |
+
// This helps keeping the smart_holder branch in sync with master.
|
76 |
+
|
77 |
+
// test_multiple_inheritance_mix1
|
78 |
+
// test_multiple_inheritance_mix2
|
79 |
+
struct Base1 {
|
80 |
+
Base1(int i) : i(i) { }
|
81 |
+
int foo() const { return i; }
|
82 |
+
int i;
|
83 |
+
};
|
84 |
+
py::class_<Base1> b1(m, "Base1");
|
85 |
+
b1.def(py::init<int>())
|
86 |
+
.def("foo", &Base1::foo);
|
87 |
+
|
88 |
+
struct Base2 {
|
89 |
+
Base2(int i) : i(i) { }
|
90 |
+
int bar() const { return i; }
|
91 |
+
int i;
|
92 |
+
};
|
93 |
+
py::class_<Base2> b2(m, "Base2");
|
94 |
+
b2.def(py::init<int>())
|
95 |
+
.def("bar", &Base2::bar);
|
96 |
+
|
97 |
+
|
98 |
+
// test_multiple_inheritance_cpp
|
99 |
+
struct Base12 : Base1, Base2 {
|
100 |
+
Base12(int i, int j) : Base1(i), Base2(j) { }
|
101 |
+
};
|
102 |
+
struct MIType : Base12 {
|
103 |
+
MIType(int i, int j) : Base12(i, j) { }
|
104 |
+
};
|
105 |
+
py::class_<Base12, Base1, Base2>(m, "Base12");
|
106 |
+
py::class_<MIType, Base12>(m, "MIType")
|
107 |
+
.def(py::init<int, int>());
|
108 |
+
|
109 |
+
|
110 |
+
// test_multiple_inheritance_python_many_bases
|
111 |
+
#define PYBIND11_BASEN(N) py::class_<BaseN<N>>(m, "BaseN" #N).def(py::init<int>()).def("f" #N, [](BaseN<N> &b) { return b.i + N; })
|
112 |
+
PYBIND11_BASEN( 1); PYBIND11_BASEN( 2); PYBIND11_BASEN( 3); PYBIND11_BASEN( 4);
|
113 |
+
PYBIND11_BASEN( 5); PYBIND11_BASEN( 6); PYBIND11_BASEN( 7); PYBIND11_BASEN( 8);
|
114 |
+
PYBIND11_BASEN( 9); PYBIND11_BASEN(10); PYBIND11_BASEN(11); PYBIND11_BASEN(12);
|
115 |
+
PYBIND11_BASEN(13); PYBIND11_BASEN(14); PYBIND11_BASEN(15); PYBIND11_BASEN(16);
|
116 |
+
PYBIND11_BASEN(17);
|
117 |
+
|
118 |
+
// Uncommenting this should result in a compile time failure (MI can only be specified via
|
119 |
+
// template parameters because pybind has to know the types involved; see discussion in #742 for
|
120 |
+
// details).
|
121 |
+
// struct Base12v2 : Base1, Base2 {
|
122 |
+
// Base12v2(int i, int j) : Base1(i), Base2(j) { }
|
123 |
+
// };
|
124 |
+
// py::class_<Base12v2>(m, "Base12v2", b1, b2)
|
125 |
+
// .def(py::init<int, int>());
|
126 |
+
|
127 |
+
|
128 |
+
// test_multiple_inheritance_virtbase
|
129 |
+
// Test the case where not all base classes are specified, and where pybind11 requires the
|
130 |
+
// py::multiple_inheritance flag to perform proper casting between types.
|
131 |
+
py::class_<Base1a, std::shared_ptr<Base1a>>(m, "Base1a")
|
132 |
+
.def(py::init<int>())
|
133 |
+
.def("foo", &Base1a::foo);
|
134 |
+
|
135 |
+
py::class_<Base2a, std::shared_ptr<Base2a>>(m, "Base2a")
|
136 |
+
.def(py::init<int>())
|
137 |
+
.def("bar", &Base2a::bar);
|
138 |
+
|
139 |
+
py::class_<Base12a, /* Base1 missing */ Base2a,
|
140 |
+
std::shared_ptr<Base12a>>(m, "Base12a", py::multiple_inheritance())
|
141 |
+
.def(py::init<int, int>());
|
142 |
+
|
143 |
+
m.def("bar_base2a", [](Base2a *b) { return b->bar(); });
|
144 |
+
m.def("bar_base2a_sharedptr", [](const std::shared_ptr<Base2a> &b) { return b->bar(); });
|
145 |
+
|
146 |
+
// test_mi_unaligned_base
|
147 |
+
// test_mi_base_return
|
148 |
+
// Issue #801: invalid casting to derived type with MI bases
|
149 |
+
// Unregistered classes:
|
150 |
+
struct I801B3 { int c = 3; virtual ~I801B3() = default; };
|
151 |
+
struct I801E : I801B3, I801D {};
|
152 |
+
|
153 |
+
py::class_<I801B1, std::shared_ptr<I801B1>>(m, "I801B1").def(py::init<>()).def_readonly("a", &I801B1::a);
|
154 |
+
py::class_<I801B2, std::shared_ptr<I801B2>>(m, "I801B2").def(py::init<>()).def_readonly("b", &I801B2::b);
|
155 |
+
py::class_<I801C, I801B1, I801B2, std::shared_ptr<I801C>>(m, "I801C").def(py::init<>());
|
156 |
+
py::class_<I801D, I801C, std::shared_ptr<I801D>>(m, "I801D").def(py::init<>());
|
157 |
+
|
158 |
+
// Two separate issues here: first, we want to recognize a pointer to a base type as being a
|
159 |
+
// known instance even when the pointer value is unequal (i.e. due to a non-first
|
160 |
+
// multiple-inheritance base class):
|
161 |
+
m.def("i801b1_c", [](I801C *c) { return static_cast<I801B1 *>(c); });
|
162 |
+
m.def("i801b2_c", [](I801C *c) { return static_cast<I801B2 *>(c); });
|
163 |
+
m.def("i801b1_d", [](I801D *d) { return static_cast<I801B1 *>(d); });
|
164 |
+
m.def("i801b2_d", [](I801D *d) { return static_cast<I801B2 *>(d); });
|
165 |
+
|
166 |
+
// Second, when returned a base class pointer to a derived instance, we cannot assume that the
|
167 |
+
// pointer is `reinterpret_cast`able to the derived pointer because, like above, the base class
|
168 |
+
// pointer could be offset.
|
169 |
+
m.def("i801c_b1", []() -> I801B1 * { return new I801C(); });
|
170 |
+
m.def("i801c_b2", []() -> I801B2 * { return new I801C(); });
|
171 |
+
m.def("i801d_b1", []() -> I801B1 * { return new I801D(); });
|
172 |
+
m.def("i801d_b2", []() -> I801B2 * { return new I801D(); });
|
173 |
+
|
174 |
+
// Return a base class pointer to a pybind-registered type when the actual derived type
|
175 |
+
// isn't pybind-registered (and uses multiple-inheritance to offset the pybind base)
|
176 |
+
m.def("i801e_c", []() -> I801C * { return new I801E(); });
|
177 |
+
m.def("i801e_b2", []() -> I801B2 * { return new I801E(); });
|
178 |
+
|
179 |
+
|
180 |
+
// test_mi_static_properties
|
181 |
+
py::class_<Vanilla>(m, "Vanilla")
|
182 |
+
.def(py::init<>())
|
183 |
+
.def("vanilla", &Vanilla::vanilla);
|
184 |
+
|
185 |
+
py::class_<WithStatic1>(m, "WithStatic1")
|
186 |
+
.def(py::init<>())
|
187 |
+
.def_static("static_func1", &WithStatic1::static_func1)
|
188 |
+
.def_readwrite_static("static_value1", &WithStatic1::static_value1);
|
189 |
+
|
190 |
+
py::class_<WithStatic2>(m, "WithStatic2")
|
191 |
+
.def(py::init<>())
|
192 |
+
.def_static("static_func2", &WithStatic2::static_func2)
|
193 |
+
.def_readwrite_static("static_value2", &WithStatic2::static_value2);
|
194 |
+
|
195 |
+
py::class_<VanillaStaticMix1, Vanilla, WithStatic1, WithStatic2>(
|
196 |
+
m, "VanillaStaticMix1")
|
197 |
+
.def(py::init<>())
|
198 |
+
.def_static("static_func", &VanillaStaticMix1::static_func)
|
199 |
+
.def_readwrite_static("static_value", &VanillaStaticMix1::static_value);
|
200 |
+
|
201 |
+
py::class_<VanillaStaticMix2, WithStatic1, Vanilla, WithStatic2>(
|
202 |
+
m, "VanillaStaticMix2")
|
203 |
+
.def(py::init<>())
|
204 |
+
.def_static("static_func", &VanillaStaticMix2::static_func)
|
205 |
+
.def_readwrite_static("static_value", &VanillaStaticMix2::static_value);
|
206 |
+
|
207 |
+
|
208 |
+
struct WithDict { };
|
209 |
+
struct VanillaDictMix1 : Vanilla, WithDict { };
|
210 |
+
struct VanillaDictMix2 : WithDict, Vanilla { };
|
211 |
+
py::class_<WithDict>(m, "WithDict", py::dynamic_attr()).def(py::init<>());
|
212 |
+
py::class_<VanillaDictMix1, Vanilla, WithDict>(m, "VanillaDictMix1").def(py::init<>());
|
213 |
+
py::class_<VanillaDictMix2, WithDict, Vanilla>(m, "VanillaDictMix2").def(py::init<>());
|
214 |
+
|
215 |
+
// test_diamond_inheritance
|
216 |
+
// Issue #959: segfault when constructing diamond inheritance instance
|
217 |
+
// All of these have int members so that there will be various unequal pointers involved.
|
218 |
+
struct B { int b; B() = default; B(const B&) = default; virtual ~B() = default; };
|
219 |
+
struct C0 : public virtual B { int c0; };
|
220 |
+
struct C1 : public virtual B { int c1; };
|
221 |
+
struct D : public C0, public C1 { int d; };
|
222 |
+
py::class_<B>(m, "B")
|
223 |
+
.def("b", [](B *self) { return self; });
|
224 |
+
py::class_<C0, B>(m, "C0")
|
225 |
+
.def("c0", [](C0 *self) { return self; });
|
226 |
+
py::class_<C1, B>(m, "C1")
|
227 |
+
.def("c1", [](C1 *self) { return self; });
|
228 |
+
py::class_<D, C0, C1>(m, "D")
|
229 |
+
.def(py::init<>());
|
230 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_multiple_inheritance.py
ADDED
@@ -0,0 +1,361 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
import env # noqa: F401
|
5 |
+
|
6 |
+
from pybind11_tests import ConstructorStats
|
7 |
+
from pybind11_tests import multiple_inheritance as m
|
8 |
+
|
9 |
+
|
10 |
+
def test_multiple_inheritance_cpp():
|
11 |
+
mt = m.MIType(3, 4)
|
12 |
+
|
13 |
+
assert mt.foo() == 3
|
14 |
+
assert mt.bar() == 4
|
15 |
+
|
16 |
+
|
17 |
+
@pytest.mark.skipif("env.PYPY and env.PY2")
|
18 |
+
@pytest.mark.xfail("env.PYPY and not env.PY2")
|
19 |
+
def test_multiple_inheritance_mix1():
|
20 |
+
class Base1:
|
21 |
+
def __init__(self, i):
|
22 |
+
self.i = i
|
23 |
+
|
24 |
+
def foo(self):
|
25 |
+
return self.i
|
26 |
+
|
27 |
+
class MITypePy(Base1, m.Base2):
|
28 |
+
def __init__(self, i, j):
|
29 |
+
Base1.__init__(self, i)
|
30 |
+
m.Base2.__init__(self, j)
|
31 |
+
|
32 |
+
mt = MITypePy(3, 4)
|
33 |
+
|
34 |
+
assert mt.foo() == 3
|
35 |
+
assert mt.bar() == 4
|
36 |
+
|
37 |
+
|
38 |
+
def test_multiple_inheritance_mix2():
|
39 |
+
class Base2:
|
40 |
+
def __init__(self, i):
|
41 |
+
self.i = i
|
42 |
+
|
43 |
+
def bar(self):
|
44 |
+
return self.i
|
45 |
+
|
46 |
+
class MITypePy(m.Base1, Base2):
|
47 |
+
def __init__(self, i, j):
|
48 |
+
m.Base1.__init__(self, i)
|
49 |
+
Base2.__init__(self, j)
|
50 |
+
|
51 |
+
mt = MITypePy(3, 4)
|
52 |
+
|
53 |
+
assert mt.foo() == 3
|
54 |
+
assert mt.bar() == 4
|
55 |
+
|
56 |
+
|
57 |
+
@pytest.mark.skipif("env.PYPY and env.PY2")
|
58 |
+
@pytest.mark.xfail("env.PYPY and not env.PY2")
|
59 |
+
def test_multiple_inheritance_python():
|
60 |
+
class MI1(m.Base1, m.Base2):
|
61 |
+
def __init__(self, i, j):
|
62 |
+
m.Base1.__init__(self, i)
|
63 |
+
m.Base2.__init__(self, j)
|
64 |
+
|
65 |
+
class B1(object):
|
66 |
+
def v(self):
|
67 |
+
return 1
|
68 |
+
|
69 |
+
class MI2(B1, m.Base1, m.Base2):
|
70 |
+
def __init__(self, i, j):
|
71 |
+
B1.__init__(self)
|
72 |
+
m.Base1.__init__(self, i)
|
73 |
+
m.Base2.__init__(self, j)
|
74 |
+
|
75 |
+
class MI3(MI2):
|
76 |
+
def __init__(self, i, j):
|
77 |
+
MI2.__init__(self, i, j)
|
78 |
+
|
79 |
+
class MI4(MI3, m.Base2):
|
80 |
+
def __init__(self, i, j):
|
81 |
+
MI3.__init__(self, i, j)
|
82 |
+
# This should be ignored (Base2 is already initialized via MI2):
|
83 |
+
m.Base2.__init__(self, i + 100)
|
84 |
+
|
85 |
+
class MI5(m.Base2, B1, m.Base1):
|
86 |
+
def __init__(self, i, j):
|
87 |
+
B1.__init__(self)
|
88 |
+
m.Base1.__init__(self, i)
|
89 |
+
m.Base2.__init__(self, j)
|
90 |
+
|
91 |
+
class MI6(m.Base2, B1):
|
92 |
+
def __init__(self, i):
|
93 |
+
m.Base2.__init__(self, i)
|
94 |
+
B1.__init__(self)
|
95 |
+
|
96 |
+
class B2(B1):
|
97 |
+
def v(self):
|
98 |
+
return 2
|
99 |
+
|
100 |
+
class B3(object):
|
101 |
+
def v(self):
|
102 |
+
return 3
|
103 |
+
|
104 |
+
class B4(B3, B2):
|
105 |
+
def v(self):
|
106 |
+
return 4
|
107 |
+
|
108 |
+
class MI7(B4, MI6):
|
109 |
+
def __init__(self, i):
|
110 |
+
B4.__init__(self)
|
111 |
+
MI6.__init__(self, i)
|
112 |
+
|
113 |
+
class MI8(MI6, B3):
|
114 |
+
def __init__(self, i):
|
115 |
+
MI6.__init__(self, i)
|
116 |
+
B3.__init__(self)
|
117 |
+
|
118 |
+
class MI8b(B3, MI6):
|
119 |
+
def __init__(self, i):
|
120 |
+
B3.__init__(self)
|
121 |
+
MI6.__init__(self, i)
|
122 |
+
|
123 |
+
mi1 = MI1(1, 2)
|
124 |
+
assert mi1.foo() == 1
|
125 |
+
assert mi1.bar() == 2
|
126 |
+
|
127 |
+
mi2 = MI2(3, 4)
|
128 |
+
assert mi2.v() == 1
|
129 |
+
assert mi2.foo() == 3
|
130 |
+
assert mi2.bar() == 4
|
131 |
+
|
132 |
+
mi3 = MI3(5, 6)
|
133 |
+
assert mi3.v() == 1
|
134 |
+
assert mi3.foo() == 5
|
135 |
+
assert mi3.bar() == 6
|
136 |
+
|
137 |
+
mi4 = MI4(7, 8)
|
138 |
+
assert mi4.v() == 1
|
139 |
+
assert mi4.foo() == 7
|
140 |
+
assert mi4.bar() == 8
|
141 |
+
|
142 |
+
mi5 = MI5(10, 11)
|
143 |
+
assert mi5.v() == 1
|
144 |
+
assert mi5.foo() == 10
|
145 |
+
assert mi5.bar() == 11
|
146 |
+
|
147 |
+
mi6 = MI6(12)
|
148 |
+
assert mi6.v() == 1
|
149 |
+
assert mi6.bar() == 12
|
150 |
+
|
151 |
+
mi7 = MI7(13)
|
152 |
+
assert mi7.v() == 4
|
153 |
+
assert mi7.bar() == 13
|
154 |
+
|
155 |
+
mi8 = MI8(14)
|
156 |
+
assert mi8.v() == 1
|
157 |
+
assert mi8.bar() == 14
|
158 |
+
|
159 |
+
mi8b = MI8b(15)
|
160 |
+
assert mi8b.v() == 3
|
161 |
+
assert mi8b.bar() == 15
|
162 |
+
|
163 |
+
|
164 |
+
def test_multiple_inheritance_python_many_bases():
|
165 |
+
class MIMany14(m.BaseN1, m.BaseN2, m.BaseN3, m.BaseN4):
|
166 |
+
def __init__(self):
|
167 |
+
m.BaseN1.__init__(self, 1)
|
168 |
+
m.BaseN2.__init__(self, 2)
|
169 |
+
m.BaseN3.__init__(self, 3)
|
170 |
+
m.BaseN4.__init__(self, 4)
|
171 |
+
|
172 |
+
class MIMany58(m.BaseN5, m.BaseN6, m.BaseN7, m.BaseN8):
|
173 |
+
def __init__(self):
|
174 |
+
m.BaseN5.__init__(self, 5)
|
175 |
+
m.BaseN6.__init__(self, 6)
|
176 |
+
m.BaseN7.__init__(self, 7)
|
177 |
+
m.BaseN8.__init__(self, 8)
|
178 |
+
|
179 |
+
class MIMany916(
|
180 |
+
m.BaseN9,
|
181 |
+
m.BaseN10,
|
182 |
+
m.BaseN11,
|
183 |
+
m.BaseN12,
|
184 |
+
m.BaseN13,
|
185 |
+
m.BaseN14,
|
186 |
+
m.BaseN15,
|
187 |
+
m.BaseN16,
|
188 |
+
):
|
189 |
+
def __init__(self):
|
190 |
+
m.BaseN9.__init__(self, 9)
|
191 |
+
m.BaseN10.__init__(self, 10)
|
192 |
+
m.BaseN11.__init__(self, 11)
|
193 |
+
m.BaseN12.__init__(self, 12)
|
194 |
+
m.BaseN13.__init__(self, 13)
|
195 |
+
m.BaseN14.__init__(self, 14)
|
196 |
+
m.BaseN15.__init__(self, 15)
|
197 |
+
m.BaseN16.__init__(self, 16)
|
198 |
+
|
199 |
+
class MIMany19(MIMany14, MIMany58, m.BaseN9):
|
200 |
+
def __init__(self):
|
201 |
+
MIMany14.__init__(self)
|
202 |
+
MIMany58.__init__(self)
|
203 |
+
m.BaseN9.__init__(self, 9)
|
204 |
+
|
205 |
+
class MIMany117(MIMany14, MIMany58, MIMany916, m.BaseN17):
|
206 |
+
def __init__(self):
|
207 |
+
MIMany14.__init__(self)
|
208 |
+
MIMany58.__init__(self)
|
209 |
+
MIMany916.__init__(self)
|
210 |
+
m.BaseN17.__init__(self, 17)
|
211 |
+
|
212 |
+
# Inherits from 4 registered C++ classes: can fit in one pointer on any modern arch:
|
213 |
+
a = MIMany14()
|
214 |
+
for i in range(1, 4):
|
215 |
+
assert getattr(a, "f" + str(i))() == 2 * i
|
216 |
+
|
217 |
+
# Inherits from 8: requires 1/2 pointers worth of holder flags on 32/64-bit arch:
|
218 |
+
b = MIMany916()
|
219 |
+
for i in range(9, 16):
|
220 |
+
assert getattr(b, "f" + str(i))() == 2 * i
|
221 |
+
|
222 |
+
# Inherits from 9: requires >= 2 pointers worth of holder flags
|
223 |
+
c = MIMany19()
|
224 |
+
for i in range(1, 9):
|
225 |
+
assert getattr(c, "f" + str(i))() == 2 * i
|
226 |
+
|
227 |
+
# Inherits from 17: requires >= 3 pointers worth of holder flags
|
228 |
+
d = MIMany117()
|
229 |
+
for i in range(1, 17):
|
230 |
+
assert getattr(d, "f" + str(i))() == 2 * i
|
231 |
+
|
232 |
+
|
233 |
+
def test_multiple_inheritance_virtbase():
|
234 |
+
class MITypePy(m.Base12a):
|
235 |
+
def __init__(self, i, j):
|
236 |
+
m.Base12a.__init__(self, i, j)
|
237 |
+
|
238 |
+
mt = MITypePy(3, 4)
|
239 |
+
assert mt.bar() == 4
|
240 |
+
assert m.bar_base2a(mt) == 4
|
241 |
+
assert m.bar_base2a_sharedptr(mt) == 4
|
242 |
+
|
243 |
+
|
244 |
+
def test_mi_static_properties():
|
245 |
+
"""Mixing bases with and without static properties should be possible
|
246 |
+
and the result should be independent of base definition order"""
|
247 |
+
|
248 |
+
for d in (m.VanillaStaticMix1(), m.VanillaStaticMix2()):
|
249 |
+
assert d.vanilla() == "Vanilla"
|
250 |
+
assert d.static_func1() == "WithStatic1"
|
251 |
+
assert d.static_func2() == "WithStatic2"
|
252 |
+
assert d.static_func() == d.__class__.__name__
|
253 |
+
|
254 |
+
m.WithStatic1.static_value1 = 1
|
255 |
+
m.WithStatic2.static_value2 = 2
|
256 |
+
assert d.static_value1 == 1
|
257 |
+
assert d.static_value2 == 2
|
258 |
+
assert d.static_value == 12
|
259 |
+
|
260 |
+
d.static_value1 = 0
|
261 |
+
assert d.static_value1 == 0
|
262 |
+
d.static_value2 = 0
|
263 |
+
assert d.static_value2 == 0
|
264 |
+
d.static_value = 0
|
265 |
+
assert d.static_value == 0
|
266 |
+
|
267 |
+
|
268 |
+
# Requires PyPy 6+
|
269 |
+
def test_mi_dynamic_attributes():
|
270 |
+
"""Mixing bases with and without dynamic attribute support"""
|
271 |
+
|
272 |
+
for d in (m.VanillaDictMix1(), m.VanillaDictMix2()):
|
273 |
+
d.dynamic = 1
|
274 |
+
assert d.dynamic == 1
|
275 |
+
|
276 |
+
|
277 |
+
def test_mi_unaligned_base():
|
278 |
+
"""Returning an offset (non-first MI) base class pointer should recognize the instance"""
|
279 |
+
|
280 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
281 |
+
|
282 |
+
c = m.I801C()
|
283 |
+
d = m.I801D()
|
284 |
+
# + 4 below because we have the two instances, and each instance has offset base I801B2
|
285 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 4
|
286 |
+
b1c = m.i801b1_c(c)
|
287 |
+
assert b1c is c
|
288 |
+
b2c = m.i801b2_c(c)
|
289 |
+
assert b2c is c
|
290 |
+
b1d = m.i801b1_d(d)
|
291 |
+
assert b1d is d
|
292 |
+
b2d = m.i801b2_d(d)
|
293 |
+
assert b2d is d
|
294 |
+
|
295 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 4 # no extra instances
|
296 |
+
del c, b1c, b2c
|
297 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 2
|
298 |
+
del d, b1d, b2d
|
299 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
300 |
+
|
301 |
+
|
302 |
+
def test_mi_base_return():
|
303 |
+
"""Tests returning an offset (non-first MI) base class pointer to a derived instance"""
|
304 |
+
|
305 |
+
n_inst = ConstructorStats.detail_reg_inst()
|
306 |
+
|
307 |
+
c1 = m.i801c_b1()
|
308 |
+
assert type(c1) is m.I801C
|
309 |
+
assert c1.a == 1
|
310 |
+
assert c1.b == 2
|
311 |
+
|
312 |
+
d1 = m.i801d_b1()
|
313 |
+
assert type(d1) is m.I801D
|
314 |
+
assert d1.a == 1
|
315 |
+
assert d1.b == 2
|
316 |
+
|
317 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 4
|
318 |
+
|
319 |
+
c2 = m.i801c_b2()
|
320 |
+
assert type(c2) is m.I801C
|
321 |
+
assert c2.a == 1
|
322 |
+
assert c2.b == 2
|
323 |
+
|
324 |
+
d2 = m.i801d_b2()
|
325 |
+
assert type(d2) is m.I801D
|
326 |
+
assert d2.a == 1
|
327 |
+
assert d2.b == 2
|
328 |
+
|
329 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 8
|
330 |
+
|
331 |
+
del c2
|
332 |
+
assert ConstructorStats.detail_reg_inst() == n_inst + 6
|
333 |
+
del c1, d1, d2
|
334 |
+
assert ConstructorStats.detail_reg_inst() == n_inst
|
335 |
+
|
336 |
+
# Returning an unregistered derived type with a registered base; we won't
|
337 |
+
# pick up the derived type, obviously, but should still work (as an object
|
338 |
+
# of whatever type was returned).
|
339 |
+
e1 = m.i801e_c()
|
340 |
+
assert type(e1) is m.I801C
|
341 |
+
assert e1.a == 1
|
342 |
+
assert e1.b == 2
|
343 |
+
|
344 |
+
e2 = m.i801e_b2()
|
345 |
+
assert type(e2) is m.I801B2
|
346 |
+
assert e2.b == 2
|
347 |
+
|
348 |
+
|
349 |
+
def test_diamond_inheritance():
|
350 |
+
"""Tests that diamond inheritance works as expected (issue #959)"""
|
351 |
+
|
352 |
+
# Issue #959: this shouldn't segfault:
|
353 |
+
d = m.D()
|
354 |
+
|
355 |
+
# Make sure all the various distinct pointers are all recognized as registered instances:
|
356 |
+
assert d is d.c0()
|
357 |
+
assert d is d.c1()
|
358 |
+
assert d is d.b()
|
359 |
+
assert d is d.c0().b()
|
360 |
+
assert d is d.c1().b()
|
361 |
+
assert d is d.c0().c1().b().c0().b()
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_numpy_array.cpp
ADDED
@@ -0,0 +1,462 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_numpy_array.cpp -- test core array functionality
|
3 |
+
|
4 |
+
Copyright (c) 2016 Ivan Smirnov <[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 |
+
#include <pybind11/numpy.h>
|
13 |
+
#include <pybind11/stl.h>
|
14 |
+
|
15 |
+
#include <cstdint>
|
16 |
+
#include <utility>
|
17 |
+
|
18 |
+
// Size / dtype checks.
|
19 |
+
struct DtypeCheck {
|
20 |
+
py::dtype numpy{};
|
21 |
+
py::dtype pybind11{};
|
22 |
+
};
|
23 |
+
|
24 |
+
template <typename T>
|
25 |
+
DtypeCheck get_dtype_check(const char* name) {
|
26 |
+
py::module_ np = py::module_::import("numpy");
|
27 |
+
DtypeCheck check{};
|
28 |
+
check.numpy = np.attr("dtype")(np.attr(name));
|
29 |
+
check.pybind11 = py::dtype::of<T>();
|
30 |
+
return check;
|
31 |
+
}
|
32 |
+
|
33 |
+
std::vector<DtypeCheck> get_concrete_dtype_checks() {
|
34 |
+
return {
|
35 |
+
// Normalization
|
36 |
+
get_dtype_check<std::int8_t>("int8"),
|
37 |
+
get_dtype_check<std::uint8_t>("uint8"),
|
38 |
+
get_dtype_check<std::int16_t>("int16"),
|
39 |
+
get_dtype_check<std::uint16_t>("uint16"),
|
40 |
+
get_dtype_check<std::int32_t>("int32"),
|
41 |
+
get_dtype_check<std::uint32_t>("uint32"),
|
42 |
+
get_dtype_check<std::int64_t>("int64"),
|
43 |
+
get_dtype_check<std::uint64_t>("uint64")
|
44 |
+
};
|
45 |
+
}
|
46 |
+
|
47 |
+
struct DtypeSizeCheck {
|
48 |
+
std::string name{};
|
49 |
+
int size_cpp{};
|
50 |
+
int size_numpy{};
|
51 |
+
// For debugging.
|
52 |
+
py::dtype dtype{};
|
53 |
+
};
|
54 |
+
|
55 |
+
template <typename T>
|
56 |
+
DtypeSizeCheck get_dtype_size_check() {
|
57 |
+
DtypeSizeCheck check{};
|
58 |
+
check.name = py::type_id<T>();
|
59 |
+
check.size_cpp = sizeof(T);
|
60 |
+
check.dtype = py::dtype::of<T>();
|
61 |
+
check.size_numpy = check.dtype.attr("itemsize").template cast<int>();
|
62 |
+
return check;
|
63 |
+
}
|
64 |
+
|
65 |
+
std::vector<DtypeSizeCheck> get_platform_dtype_size_checks() {
|
66 |
+
return {
|
67 |
+
get_dtype_size_check<short>(),
|
68 |
+
get_dtype_size_check<unsigned short>(),
|
69 |
+
get_dtype_size_check<int>(),
|
70 |
+
get_dtype_size_check<unsigned int>(),
|
71 |
+
get_dtype_size_check<long>(),
|
72 |
+
get_dtype_size_check<unsigned long>(),
|
73 |
+
get_dtype_size_check<long long>(),
|
74 |
+
get_dtype_size_check<unsigned long long>(),
|
75 |
+
};
|
76 |
+
}
|
77 |
+
|
78 |
+
// Arrays.
|
79 |
+
using arr = py::array;
|
80 |
+
using arr_t = py::array_t<uint16_t, 0>;
|
81 |
+
static_assert(std::is_same<arr_t::value_type, uint16_t>::value, "");
|
82 |
+
|
83 |
+
template<typename... Ix> arr data(const arr& a, Ix... index) {
|
84 |
+
return arr(a.nbytes() - a.offset_at(index...), (const uint8_t *) a.data(index...));
|
85 |
+
}
|
86 |
+
|
87 |
+
template<typename... Ix> arr data_t(const arr_t& a, Ix... index) {
|
88 |
+
return arr(a.size() - a.index_at(index...), a.data(index...));
|
89 |
+
}
|
90 |
+
|
91 |
+
template<typename... Ix> arr& mutate_data(arr& a, Ix... index) {
|
92 |
+
auto ptr = (uint8_t *) a.mutable_data(index...);
|
93 |
+
for (py::ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++)
|
94 |
+
ptr[i] = (uint8_t) (ptr[i] * 2);
|
95 |
+
return a;
|
96 |
+
}
|
97 |
+
|
98 |
+
template<typename... Ix> arr_t& mutate_data_t(arr_t& a, Ix... index) {
|
99 |
+
auto ptr = a.mutable_data(index...);
|
100 |
+
for (py::ssize_t i = 0; i < a.size() - a.index_at(index...); i++)
|
101 |
+
ptr[i]++;
|
102 |
+
return a;
|
103 |
+
}
|
104 |
+
|
105 |
+
template<typename... Ix> py::ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); }
|
106 |
+
template<typename... Ix> py::ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); }
|
107 |
+
template<typename... Ix> py::ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); }
|
108 |
+
template<typename... Ix> py::ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); }
|
109 |
+
template<typename... Ix> py::ssize_t at_t(const arr_t& a, Ix... idx) { return a.at(idx...); }
|
110 |
+
template<typename... Ix> arr_t& mutate_at_t(arr_t& a, Ix... idx) { a.mutable_at(idx...)++; return a; }
|
111 |
+
|
112 |
+
#define def_index_fn(name, type) \
|
113 |
+
sm.def(#name, [](type a) { return name(a); }); \
|
114 |
+
sm.def(#name, [](type a, int i) { return name(a, i); }); \
|
115 |
+
sm.def(#name, [](type a, int i, int j) { return name(a, i, j); }); \
|
116 |
+
sm.def(#name, [](type a, int i, int j, int k) { return name(a, i, j, k); });
|
117 |
+
|
118 |
+
template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) {
|
119 |
+
if (r.ndim() != 2) throw std::domain_error("error: ndim != 2");
|
120 |
+
py::list l;
|
121 |
+
l.append(*r.data(0, 0));
|
122 |
+
l.append(*r2.mutable_data(0, 0));
|
123 |
+
l.append(r.data(0, 1) == r2.mutable_data(0, 1));
|
124 |
+
l.append(r.ndim());
|
125 |
+
l.append(r.itemsize());
|
126 |
+
l.append(r.shape(0));
|
127 |
+
l.append(r.shape(1));
|
128 |
+
l.append(r.size());
|
129 |
+
l.append(r.nbytes());
|
130 |
+
return l.release();
|
131 |
+
}
|
132 |
+
|
133 |
+
// note: declaration at local scope would create a dangling reference!
|
134 |
+
static int data_i = 42;
|
135 |
+
|
136 |
+
TEST_SUBMODULE(numpy_array, sm) {
|
137 |
+
try { py::module_::import("numpy"); }
|
138 |
+
catch (...) { return; }
|
139 |
+
|
140 |
+
// test_dtypes
|
141 |
+
py::class_<DtypeCheck>(sm, "DtypeCheck")
|
142 |
+
.def_readonly("numpy", &DtypeCheck::numpy)
|
143 |
+
.def_readonly("pybind11", &DtypeCheck::pybind11)
|
144 |
+
.def("__repr__", [](const DtypeCheck& self) {
|
145 |
+
return py::str("<DtypeCheck numpy={} pybind11={}>").format(
|
146 |
+
self.numpy, self.pybind11);
|
147 |
+
});
|
148 |
+
sm.def("get_concrete_dtype_checks", &get_concrete_dtype_checks);
|
149 |
+
|
150 |
+
py::class_<DtypeSizeCheck>(sm, "DtypeSizeCheck")
|
151 |
+
.def_readonly("name", &DtypeSizeCheck::name)
|
152 |
+
.def_readonly("size_cpp", &DtypeSizeCheck::size_cpp)
|
153 |
+
.def_readonly("size_numpy", &DtypeSizeCheck::size_numpy)
|
154 |
+
.def("__repr__", [](const DtypeSizeCheck& self) {
|
155 |
+
return py::str("<DtypeSizeCheck name='{}' size_cpp={} size_numpy={} dtype={}>").format(
|
156 |
+
self.name, self.size_cpp, self.size_numpy, self.dtype);
|
157 |
+
});
|
158 |
+
sm.def("get_platform_dtype_size_checks", &get_platform_dtype_size_checks);
|
159 |
+
|
160 |
+
// test_array_attributes
|
161 |
+
sm.def("ndim", [](const arr& a) { return a.ndim(); });
|
162 |
+
sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); });
|
163 |
+
sm.def("shape", [](const arr& a, py::ssize_t dim) { return a.shape(dim); });
|
164 |
+
sm.def("strides", [](const arr& a) { return arr(a.ndim(), a.strides()); });
|
165 |
+
sm.def("strides", [](const arr& a, py::ssize_t dim) { return a.strides(dim); });
|
166 |
+
sm.def("writeable", [](const arr& a) { return a.writeable(); });
|
167 |
+
sm.def("size", [](const arr& a) { return a.size(); });
|
168 |
+
sm.def("itemsize", [](const arr& a) { return a.itemsize(); });
|
169 |
+
sm.def("nbytes", [](const arr& a) { return a.nbytes(); });
|
170 |
+
sm.def("owndata", [](const arr& a) { return a.owndata(); });
|
171 |
+
|
172 |
+
// test_index_offset
|
173 |
+
def_index_fn(index_at, const arr&);
|
174 |
+
def_index_fn(index_at_t, const arr_t&);
|
175 |
+
def_index_fn(offset_at, const arr&);
|
176 |
+
def_index_fn(offset_at_t, const arr_t&);
|
177 |
+
// test_data
|
178 |
+
def_index_fn(data, const arr&);
|
179 |
+
def_index_fn(data_t, const arr_t&);
|
180 |
+
// test_mutate_data, test_mutate_readonly
|
181 |
+
def_index_fn(mutate_data, arr&);
|
182 |
+
def_index_fn(mutate_data_t, arr_t&);
|
183 |
+
def_index_fn(at_t, const arr_t&);
|
184 |
+
def_index_fn(mutate_at_t, arr_t&);
|
185 |
+
|
186 |
+
// test_make_c_f_array
|
187 |
+
sm.def("make_f_array", [] { return py::array_t<float>({ 2, 2 }, { 4, 8 }); });
|
188 |
+
sm.def("make_c_array", [] { return py::array_t<float>({ 2, 2 }, { 8, 4 }); });
|
189 |
+
|
190 |
+
// test_empty_shaped_array
|
191 |
+
sm.def("make_empty_shaped_array", [] { return py::array(py::dtype("f"), {}, {}); });
|
192 |
+
// test numpy scalars (empty shape, ndim==0)
|
193 |
+
sm.def("scalar_int", []() { return py::array(py::dtype("i"), {}, {}, &data_i); });
|
194 |
+
|
195 |
+
// test_wrap
|
196 |
+
sm.def("wrap", [](const py::array &a) {
|
197 |
+
return py::array(
|
198 |
+
a.dtype(),
|
199 |
+
{a.shape(), a.shape() + a.ndim()},
|
200 |
+
{a.strides(), a.strides() + a.ndim()},
|
201 |
+
a.data(),
|
202 |
+
a
|
203 |
+
);
|
204 |
+
});
|
205 |
+
|
206 |
+
// test_numpy_view
|
207 |
+
struct ArrayClass {
|
208 |
+
int data[2] = { 1, 2 };
|
209 |
+
ArrayClass() { py::print("ArrayClass()"); }
|
210 |
+
~ArrayClass() { py::print("~ArrayClass()"); }
|
211 |
+
};
|
212 |
+
py::class_<ArrayClass>(sm, "ArrayClass")
|
213 |
+
.def(py::init<>())
|
214 |
+
.def("numpy_view", [](py::object &obj) {
|
215 |
+
py::print("ArrayClass::numpy_view()");
|
216 |
+
auto &a = obj.cast<ArrayClass&>();
|
217 |
+
return py::array_t<int>({2}, {4}, a.data, obj);
|
218 |
+
}
|
219 |
+
);
|
220 |
+
|
221 |
+
// test_cast_numpy_int64_to_uint64
|
222 |
+
sm.def("function_taking_uint64", [](uint64_t) { });
|
223 |
+
|
224 |
+
// test_isinstance
|
225 |
+
sm.def("isinstance_untyped", [](py::object yes, py::object no) {
|
226 |
+
return py::isinstance<py::array>(std::move(yes))
|
227 |
+
&& !py::isinstance<py::array>(std::move(no));
|
228 |
+
});
|
229 |
+
sm.def("isinstance_typed", [](const py::object &o) {
|
230 |
+
return py::isinstance<py::array_t<double>>(o) && !py::isinstance<py::array_t<int>>(o);
|
231 |
+
});
|
232 |
+
|
233 |
+
// test_constructors
|
234 |
+
sm.def("default_constructors", []() {
|
235 |
+
return py::dict(
|
236 |
+
"array"_a=py::array(),
|
237 |
+
"array_t<int32>"_a=py::array_t<std::int32_t>(),
|
238 |
+
"array_t<double>"_a=py::array_t<double>()
|
239 |
+
);
|
240 |
+
});
|
241 |
+
sm.def("converting_constructors", [](const py::object &o) {
|
242 |
+
return py::dict(
|
243 |
+
"array"_a=py::array(o),
|
244 |
+
"array_t<int32>"_a=py::array_t<std::int32_t>(o),
|
245 |
+
"array_t<double>"_a=py::array_t<double>(o)
|
246 |
+
);
|
247 |
+
});
|
248 |
+
|
249 |
+
// test_overload_resolution
|
250 |
+
sm.def("overloaded", [](const py::array_t<double> &) { return "double"; });
|
251 |
+
sm.def("overloaded", [](const py::array_t<float> &) { return "float"; });
|
252 |
+
sm.def("overloaded", [](const py::array_t<int> &) { return "int"; });
|
253 |
+
sm.def("overloaded", [](const py::array_t<unsigned short> &) { return "unsigned short"; });
|
254 |
+
sm.def("overloaded", [](const py::array_t<long long> &) { return "long long"; });
|
255 |
+
sm.def("overloaded",
|
256 |
+
[](const py::array_t<std::complex<double>> &) { return "double complex"; });
|
257 |
+
sm.def("overloaded", [](const py::array_t<std::complex<float>> &) { return "float complex"; });
|
258 |
+
|
259 |
+
sm.def("overloaded2",
|
260 |
+
[](const py::array_t<std::complex<double>> &) { return "double complex"; });
|
261 |
+
sm.def("overloaded2", [](const py::array_t<double> &) { return "double"; });
|
262 |
+
sm.def("overloaded2",
|
263 |
+
[](const py::array_t<std::complex<float>> &) { return "float complex"; });
|
264 |
+
sm.def("overloaded2", [](const py::array_t<float> &) { return "float"; });
|
265 |
+
|
266 |
+
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
|
267 |
+
|
268 |
+
// Only accept the exact types:
|
269 |
+
sm.def(
|
270 |
+
"overloaded3", [](const py::array_t<int> &) { return "int"; }, py::arg{}.noconvert());
|
271 |
+
sm.def(
|
272 |
+
"overloaded3",
|
273 |
+
[](const py::array_t<double> &) { return "double"; },
|
274 |
+
py::arg{}.noconvert());
|
275 |
+
|
276 |
+
// Make sure we don't do unsafe coercion (e.g. float to int) when not using forcecast, but
|
277 |
+
// rather that float gets converted via the safe (conversion to double) overload:
|
278 |
+
sm.def("overloaded4", [](const py::array_t<long long, 0> &) { return "long long"; });
|
279 |
+
sm.def("overloaded4", [](const py::array_t<double, 0> &) { return "double"; });
|
280 |
+
|
281 |
+
// But we do allow conversion to int if forcecast is enabled (but only if no overload matches
|
282 |
+
// without conversion)
|
283 |
+
sm.def("overloaded5", [](const py::array_t<unsigned int> &) { return "unsigned int"; });
|
284 |
+
sm.def("overloaded5", [](const py::array_t<double> &) { return "double"; });
|
285 |
+
|
286 |
+
// test_greedy_string_overload
|
287 |
+
// Issue 685: ndarray shouldn't go to std::string overload
|
288 |
+
sm.def("issue685", [](const std::string &) { return "string"; });
|
289 |
+
sm.def("issue685", [](const py::array &) { return "array"; });
|
290 |
+
sm.def("issue685", [](const py::object &) { return "other"; });
|
291 |
+
|
292 |
+
// test_array_unchecked_fixed_dims
|
293 |
+
sm.def("proxy_add2", [](py::array_t<double> a, double v) {
|
294 |
+
auto r = a.mutable_unchecked<2>();
|
295 |
+
for (py::ssize_t i = 0; i < r.shape(0); i++)
|
296 |
+
for (py::ssize_t j = 0; j < r.shape(1); j++)
|
297 |
+
r(i, j) += v;
|
298 |
+
}, py::arg{}.noconvert(), py::arg());
|
299 |
+
|
300 |
+
sm.def("proxy_init3", [](double start) {
|
301 |
+
py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
|
302 |
+
auto r = a.mutable_unchecked<3>();
|
303 |
+
for (py::ssize_t i = 0; i < r.shape(0); i++)
|
304 |
+
for (py::ssize_t j = 0; j < r.shape(1); j++)
|
305 |
+
for (py::ssize_t k = 0; k < r.shape(2); k++)
|
306 |
+
r(i, j, k) = start++;
|
307 |
+
return a;
|
308 |
+
});
|
309 |
+
sm.def("proxy_init3F", [](double start) {
|
310 |
+
py::array_t<double, py::array::f_style> a({ 3, 3, 3 });
|
311 |
+
auto r = a.mutable_unchecked<3>();
|
312 |
+
for (py::ssize_t k = 0; k < r.shape(2); k++)
|
313 |
+
for (py::ssize_t j = 0; j < r.shape(1); j++)
|
314 |
+
for (py::ssize_t i = 0; i < r.shape(0); i++)
|
315 |
+
r(i, j, k) = start++;
|
316 |
+
return a;
|
317 |
+
});
|
318 |
+
sm.def("proxy_squared_L2_norm", [](const py::array_t<double> &a) {
|
319 |
+
auto r = a.unchecked<1>();
|
320 |
+
double sumsq = 0;
|
321 |
+
for (py::ssize_t i = 0; i < r.shape(0); i++)
|
322 |
+
sumsq += r[i] * r(i); // Either notation works for a 1D array
|
323 |
+
return sumsq;
|
324 |
+
});
|
325 |
+
|
326 |
+
sm.def("proxy_auxiliaries2", [](py::array_t<double> a) {
|
327 |
+
auto r = a.unchecked<2>();
|
328 |
+
auto r2 = a.mutable_unchecked<2>();
|
329 |
+
return auxiliaries(r, r2);
|
330 |
+
});
|
331 |
+
|
332 |
+
sm.def("proxy_auxiliaries1_const_ref", [](py::array_t<double> a) {
|
333 |
+
const auto &r = a.unchecked<1>();
|
334 |
+
const auto &r2 = a.mutable_unchecked<1>();
|
335 |
+
return r(0) == r2(0) && r[0] == r2[0];
|
336 |
+
});
|
337 |
+
|
338 |
+
sm.def("proxy_auxiliaries2_const_ref", [](py::array_t<double> a) {
|
339 |
+
const auto &r = a.unchecked<2>();
|
340 |
+
const auto &r2 = a.mutable_unchecked<2>();
|
341 |
+
return r(0, 0) == r2(0, 0);
|
342 |
+
});
|
343 |
+
|
344 |
+
// test_array_unchecked_dyn_dims
|
345 |
+
// Same as the above, but without a compile-time dimensions specification:
|
346 |
+
sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) {
|
347 |
+
auto r = a.mutable_unchecked();
|
348 |
+
if (r.ndim() != 2) throw std::domain_error("error: ndim != 2");
|
349 |
+
for (py::ssize_t i = 0; i < r.shape(0); i++)
|
350 |
+
for (py::ssize_t j = 0; j < r.shape(1); j++)
|
351 |
+
r(i, j) += v;
|
352 |
+
}, py::arg{}.noconvert(), py::arg());
|
353 |
+
sm.def("proxy_init3_dyn", [](double start) {
|
354 |
+
py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
|
355 |
+
auto r = a.mutable_unchecked();
|
356 |
+
if (r.ndim() != 3) throw std::domain_error("error: ndim != 3");
|
357 |
+
for (py::ssize_t i = 0; i < r.shape(0); i++)
|
358 |
+
for (py::ssize_t j = 0; j < r.shape(1); j++)
|
359 |
+
for (py::ssize_t k = 0; k < r.shape(2); k++)
|
360 |
+
r(i, j, k) = start++;
|
361 |
+
return a;
|
362 |
+
});
|
363 |
+
sm.def("proxy_auxiliaries2_dyn", [](py::array_t<double> a) {
|
364 |
+
return auxiliaries(a.unchecked(), a.mutable_unchecked());
|
365 |
+
});
|
366 |
+
|
367 |
+
sm.def("array_auxiliaries2", [](py::array_t<double> a) {
|
368 |
+
return auxiliaries(a, a);
|
369 |
+
});
|
370 |
+
|
371 |
+
// test_array_failures
|
372 |
+
// Issue #785: Uninformative "Unknown internal error" exception when constructing array from empty object:
|
373 |
+
sm.def("array_fail_test", []() { return py::array(py::object()); });
|
374 |
+
sm.def("array_t_fail_test", []() { return py::array_t<double>(py::object()); });
|
375 |
+
// Make sure the error from numpy is being passed through:
|
376 |
+
sm.def("array_fail_test_negative_size", []() { int c = 0; return py::array(-1, &c); });
|
377 |
+
|
378 |
+
// test_initializer_list
|
379 |
+
// Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous
|
380 |
+
sm.def("array_initializer_list1", []() { return py::array_t<float>(1); }); // { 1 } also works, but clang warns about it
|
381 |
+
sm.def("array_initializer_list2", []() { return py::array_t<float>({ 1, 2 }); });
|
382 |
+
sm.def("array_initializer_list3", []() { return py::array_t<float>({ 1, 2, 3 }); });
|
383 |
+
sm.def("array_initializer_list4", []() { return py::array_t<float>({ 1, 2, 3, 4 }); });
|
384 |
+
|
385 |
+
// test_array_resize
|
386 |
+
// reshape array to 2D without changing size
|
387 |
+
sm.def("array_reshape2", [](py::array_t<double> a) {
|
388 |
+
const auto dim_sz = (py::ssize_t)std::sqrt(a.size());
|
389 |
+
if (dim_sz * dim_sz != a.size())
|
390 |
+
throw std::domain_error("array_reshape2: input array total size is not a squared integer");
|
391 |
+
a.resize({dim_sz, dim_sz});
|
392 |
+
});
|
393 |
+
|
394 |
+
// resize to 3D array with each dimension = N
|
395 |
+
sm.def("array_resize3", [](py::array_t<double> a, size_t N, bool refcheck) {
|
396 |
+
a.resize({N, N, N}, refcheck);
|
397 |
+
});
|
398 |
+
|
399 |
+
// test_array_create_and_resize
|
400 |
+
// return 2D array with Nrows = Ncols = N
|
401 |
+
sm.def("create_and_resize", [](size_t N) {
|
402 |
+
py::array_t<double> a;
|
403 |
+
a.resize({N, N});
|
404 |
+
std::fill(a.mutable_data(), a.mutable_data() + a.size(), 42.);
|
405 |
+
return a;
|
406 |
+
});
|
407 |
+
|
408 |
+
sm.def("index_using_ellipsis",
|
409 |
+
[](const py::array &a) { return a[py::make_tuple(0, py::ellipsis(), 0)]; });
|
410 |
+
|
411 |
+
// test_argument_conversions
|
412 |
+
sm.def(
|
413 |
+
"accept_double", [](const py::array_t<double, 0> &) {}, py::arg("a"));
|
414 |
+
sm.def(
|
415 |
+
"accept_double_forcecast",
|
416 |
+
[](const py::array_t<double, py::array::forcecast> &) {},
|
417 |
+
py::arg("a"));
|
418 |
+
sm.def(
|
419 |
+
"accept_double_c_style",
|
420 |
+
[](const py::array_t<double, py::array::c_style> &) {},
|
421 |
+
py::arg("a"));
|
422 |
+
sm.def(
|
423 |
+
"accept_double_c_style_forcecast",
|
424 |
+
[](const py::array_t<double, py::array::forcecast | py::array::c_style> &) {},
|
425 |
+
py::arg("a"));
|
426 |
+
sm.def(
|
427 |
+
"accept_double_f_style",
|
428 |
+
[](const py::array_t<double, py::array::f_style> &) {},
|
429 |
+
py::arg("a"));
|
430 |
+
sm.def(
|
431 |
+
"accept_double_f_style_forcecast",
|
432 |
+
[](const py::array_t<double, py::array::forcecast | py::array::f_style> &) {},
|
433 |
+
py::arg("a"));
|
434 |
+
sm.def(
|
435 |
+
"accept_double_noconvert", [](const py::array_t<double, 0> &) {}, "a"_a.noconvert());
|
436 |
+
sm.def(
|
437 |
+
"accept_double_forcecast_noconvert",
|
438 |
+
[](const py::array_t<double, py::array::forcecast> &) {},
|
439 |
+
"a"_a.noconvert());
|
440 |
+
sm.def(
|
441 |
+
"accept_double_c_style_noconvert",
|
442 |
+
[](const py::array_t<double, py::array::c_style> &) {},
|
443 |
+
"a"_a.noconvert());
|
444 |
+
sm.def(
|
445 |
+
"accept_double_c_style_forcecast_noconvert",
|
446 |
+
[](const py::array_t<double, py::array::forcecast | py::array::c_style> &) {},
|
447 |
+
"a"_a.noconvert());
|
448 |
+
sm.def(
|
449 |
+
"accept_double_f_style_noconvert",
|
450 |
+
[](const py::array_t<double, py::array::f_style> &) {},
|
451 |
+
"a"_a.noconvert());
|
452 |
+
sm.def(
|
453 |
+
"accept_double_f_style_forcecast_noconvert",
|
454 |
+
[](const py::array_t<double, py::array::forcecast | py::array::f_style> &) {},
|
455 |
+
"a"_a.noconvert());
|
456 |
+
|
457 |
+
// Check that types returns correct npy format descriptor
|
458 |
+
sm.def("test_fmt_desc_float", [](const py::array_t<float> &) {});
|
459 |
+
sm.def("test_fmt_desc_double", [](const py::array_t<double> &) {});
|
460 |
+
sm.def("test_fmt_desc_const_float", [](const py::array_t<const float> &) {});
|
461 |
+
sm.def("test_fmt_desc_const_double", [](const py::array_t<const double> &) {});
|
462 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_numpy_array.py
ADDED
@@ -0,0 +1,554 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
import env # noqa: F401
|
5 |
+
|
6 |
+
from pybind11_tests import numpy_array as m
|
7 |
+
|
8 |
+
np = pytest.importorskip("numpy")
|
9 |
+
|
10 |
+
|
11 |
+
def test_dtypes():
|
12 |
+
# See issue #1328.
|
13 |
+
# - Platform-dependent sizes.
|
14 |
+
for size_check in m.get_platform_dtype_size_checks():
|
15 |
+
print(size_check)
|
16 |
+
assert size_check.size_cpp == size_check.size_numpy, size_check
|
17 |
+
# - Concrete sizes.
|
18 |
+
for check in m.get_concrete_dtype_checks():
|
19 |
+
print(check)
|
20 |
+
assert check.numpy == check.pybind11, check
|
21 |
+
if check.numpy.num != check.pybind11.num:
|
22 |
+
print(
|
23 |
+
"NOTE: typenum mismatch for {}: {} != {}".format(
|
24 |
+
check, check.numpy.num, check.pybind11.num
|
25 |
+
)
|
26 |
+
)
|
27 |
+
|
28 |
+
|
29 |
+
@pytest.fixture(scope="function")
|
30 |
+
def arr():
|
31 |
+
return np.array([[1, 2, 3], [4, 5, 6]], "=u2")
|
32 |
+
|
33 |
+
|
34 |
+
def test_array_attributes():
|
35 |
+
a = np.array(0, "f8")
|
36 |
+
assert m.ndim(a) == 0
|
37 |
+
assert all(m.shape(a) == [])
|
38 |
+
assert all(m.strides(a) == [])
|
39 |
+
with pytest.raises(IndexError) as excinfo:
|
40 |
+
m.shape(a, 0)
|
41 |
+
assert str(excinfo.value) == "invalid axis: 0 (ndim = 0)"
|
42 |
+
with pytest.raises(IndexError) as excinfo:
|
43 |
+
m.strides(a, 0)
|
44 |
+
assert str(excinfo.value) == "invalid axis: 0 (ndim = 0)"
|
45 |
+
assert m.writeable(a)
|
46 |
+
assert m.size(a) == 1
|
47 |
+
assert m.itemsize(a) == 8
|
48 |
+
assert m.nbytes(a) == 8
|
49 |
+
assert m.owndata(a)
|
50 |
+
|
51 |
+
a = np.array([[1, 2, 3], [4, 5, 6]], "u2").view()
|
52 |
+
a.flags.writeable = False
|
53 |
+
assert m.ndim(a) == 2
|
54 |
+
assert all(m.shape(a) == [2, 3])
|
55 |
+
assert m.shape(a, 0) == 2
|
56 |
+
assert m.shape(a, 1) == 3
|
57 |
+
assert all(m.strides(a) == [6, 2])
|
58 |
+
assert m.strides(a, 0) == 6
|
59 |
+
assert m.strides(a, 1) == 2
|
60 |
+
with pytest.raises(IndexError) as excinfo:
|
61 |
+
m.shape(a, 2)
|
62 |
+
assert str(excinfo.value) == "invalid axis: 2 (ndim = 2)"
|
63 |
+
with pytest.raises(IndexError) as excinfo:
|
64 |
+
m.strides(a, 2)
|
65 |
+
assert str(excinfo.value) == "invalid axis: 2 (ndim = 2)"
|
66 |
+
assert not m.writeable(a)
|
67 |
+
assert m.size(a) == 6
|
68 |
+
assert m.itemsize(a) == 2
|
69 |
+
assert m.nbytes(a) == 12
|
70 |
+
assert not m.owndata(a)
|
71 |
+
|
72 |
+
|
73 |
+
@pytest.mark.parametrize(
|
74 |
+
"args, ret", [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)]
|
75 |
+
)
|
76 |
+
def test_index_offset(arr, args, ret):
|
77 |
+
assert m.index_at(arr, *args) == ret
|
78 |
+
assert m.index_at_t(arr, *args) == ret
|
79 |
+
assert m.offset_at(arr, *args) == ret * arr.dtype.itemsize
|
80 |
+
assert m.offset_at_t(arr, *args) == ret * arr.dtype.itemsize
|
81 |
+
|
82 |
+
|
83 |
+
def test_dim_check_fail(arr):
|
84 |
+
for func in (
|
85 |
+
m.index_at,
|
86 |
+
m.index_at_t,
|
87 |
+
m.offset_at,
|
88 |
+
m.offset_at_t,
|
89 |
+
m.data,
|
90 |
+
m.data_t,
|
91 |
+
m.mutate_data,
|
92 |
+
m.mutate_data_t,
|
93 |
+
):
|
94 |
+
with pytest.raises(IndexError) as excinfo:
|
95 |
+
func(arr, 1, 2, 3)
|
96 |
+
assert str(excinfo.value) == "too many indices for an array: 3 (ndim = 2)"
|
97 |
+
|
98 |
+
|
99 |
+
@pytest.mark.parametrize(
|
100 |
+
"args, ret",
|
101 |
+
[
|
102 |
+
([], [1, 2, 3, 4, 5, 6]),
|
103 |
+
([1], [4, 5, 6]),
|
104 |
+
([0, 1], [2, 3, 4, 5, 6]),
|
105 |
+
([1, 2], [6]),
|
106 |
+
],
|
107 |
+
)
|
108 |
+
def test_data(arr, args, ret):
|
109 |
+
from sys import byteorder
|
110 |
+
|
111 |
+
assert all(m.data_t(arr, *args) == ret)
|
112 |
+
assert all(m.data(arr, *args)[(0 if byteorder == "little" else 1) :: 2] == ret)
|
113 |
+
assert all(m.data(arr, *args)[(1 if byteorder == "little" else 0) :: 2] == 0)
|
114 |
+
|
115 |
+
|
116 |
+
@pytest.mark.parametrize("dim", [0, 1, 3])
|
117 |
+
def test_at_fail(arr, dim):
|
118 |
+
for func in m.at_t, m.mutate_at_t:
|
119 |
+
with pytest.raises(IndexError) as excinfo:
|
120 |
+
func(arr, *([0] * dim))
|
121 |
+
assert str(excinfo.value) == "index dimension mismatch: {} (ndim = 2)".format(
|
122 |
+
dim
|
123 |
+
)
|
124 |
+
|
125 |
+
|
126 |
+
def test_at(arr):
|
127 |
+
assert m.at_t(arr, 0, 2) == 3
|
128 |
+
assert m.at_t(arr, 1, 0) == 4
|
129 |
+
|
130 |
+
assert all(m.mutate_at_t(arr, 0, 2).ravel() == [1, 2, 4, 4, 5, 6])
|
131 |
+
assert all(m.mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6])
|
132 |
+
|
133 |
+
|
134 |
+
def test_mutate_readonly(arr):
|
135 |
+
arr.flags.writeable = False
|
136 |
+
for func, args in (
|
137 |
+
(m.mutate_data, ()),
|
138 |
+
(m.mutate_data_t, ()),
|
139 |
+
(m.mutate_at_t, (0, 0)),
|
140 |
+
):
|
141 |
+
with pytest.raises(ValueError) as excinfo:
|
142 |
+
func(arr, *args)
|
143 |
+
assert str(excinfo.value) == "array is not writeable"
|
144 |
+
|
145 |
+
|
146 |
+
def test_mutate_data(arr):
|
147 |
+
assert all(m.mutate_data(arr).ravel() == [2, 4, 6, 8, 10, 12])
|
148 |
+
assert all(m.mutate_data(arr).ravel() == [4, 8, 12, 16, 20, 24])
|
149 |
+
assert all(m.mutate_data(arr, 1).ravel() == [4, 8, 12, 32, 40, 48])
|
150 |
+
assert all(m.mutate_data(arr, 0, 1).ravel() == [4, 16, 24, 64, 80, 96])
|
151 |
+
assert all(m.mutate_data(arr, 1, 2).ravel() == [4, 16, 24, 64, 80, 192])
|
152 |
+
|
153 |
+
assert all(m.mutate_data_t(arr).ravel() == [5, 17, 25, 65, 81, 193])
|
154 |
+
assert all(m.mutate_data_t(arr).ravel() == [6, 18, 26, 66, 82, 194])
|
155 |
+
assert all(m.mutate_data_t(arr, 1).ravel() == [6, 18, 26, 67, 83, 195])
|
156 |
+
assert all(m.mutate_data_t(arr, 0, 1).ravel() == [6, 19, 27, 68, 84, 196])
|
157 |
+
assert all(m.mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197])
|
158 |
+
|
159 |
+
|
160 |
+
def test_bounds_check(arr):
|
161 |
+
for func in (
|
162 |
+
m.index_at,
|
163 |
+
m.index_at_t,
|
164 |
+
m.data,
|
165 |
+
m.data_t,
|
166 |
+
m.mutate_data,
|
167 |
+
m.mutate_data_t,
|
168 |
+
m.at_t,
|
169 |
+
m.mutate_at_t,
|
170 |
+
):
|
171 |
+
with pytest.raises(IndexError) as excinfo:
|
172 |
+
func(arr, 2, 0)
|
173 |
+
assert str(excinfo.value) == "index 2 is out of bounds for axis 0 with size 2"
|
174 |
+
with pytest.raises(IndexError) as excinfo:
|
175 |
+
func(arr, 0, 4)
|
176 |
+
assert str(excinfo.value) == "index 4 is out of bounds for axis 1 with size 3"
|
177 |
+
|
178 |
+
|
179 |
+
def test_make_c_f_array():
|
180 |
+
assert m.make_c_array().flags.c_contiguous
|
181 |
+
assert not m.make_c_array().flags.f_contiguous
|
182 |
+
assert m.make_f_array().flags.f_contiguous
|
183 |
+
assert not m.make_f_array().flags.c_contiguous
|
184 |
+
|
185 |
+
|
186 |
+
def test_make_empty_shaped_array():
|
187 |
+
m.make_empty_shaped_array()
|
188 |
+
|
189 |
+
# empty shape means numpy scalar, PEP 3118
|
190 |
+
assert m.scalar_int().ndim == 0
|
191 |
+
assert m.scalar_int().shape == ()
|
192 |
+
assert m.scalar_int() == 42
|
193 |
+
|
194 |
+
|
195 |
+
def test_wrap():
|
196 |
+
def assert_references(a, b, base=None):
|
197 |
+
from distutils.version import LooseVersion
|
198 |
+
|
199 |
+
if base is None:
|
200 |
+
base = a
|
201 |
+
assert a is not b
|
202 |
+
assert a.__array_interface__["data"][0] == b.__array_interface__["data"][0]
|
203 |
+
assert a.shape == b.shape
|
204 |
+
assert a.strides == b.strides
|
205 |
+
assert a.flags.c_contiguous == b.flags.c_contiguous
|
206 |
+
assert a.flags.f_contiguous == b.flags.f_contiguous
|
207 |
+
assert a.flags.writeable == b.flags.writeable
|
208 |
+
assert a.flags.aligned == b.flags.aligned
|
209 |
+
if LooseVersion(np.__version__) >= LooseVersion("1.14.0"):
|
210 |
+
assert a.flags.writebackifcopy == b.flags.writebackifcopy
|
211 |
+
else:
|
212 |
+
assert a.flags.updateifcopy == b.flags.updateifcopy
|
213 |
+
assert np.all(a == b)
|
214 |
+
assert not b.flags.owndata
|
215 |
+
assert b.base is base
|
216 |
+
if a.flags.writeable and a.ndim == 2:
|
217 |
+
a[0, 0] = 1234
|
218 |
+
assert b[0, 0] == 1234
|
219 |
+
|
220 |
+
a1 = np.array([1, 2], dtype=np.int16)
|
221 |
+
assert a1.flags.owndata and a1.base is None
|
222 |
+
a2 = m.wrap(a1)
|
223 |
+
assert_references(a1, a2)
|
224 |
+
|
225 |
+
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order="F")
|
226 |
+
assert a1.flags.owndata and a1.base is None
|
227 |
+
a2 = m.wrap(a1)
|
228 |
+
assert_references(a1, a2)
|
229 |
+
|
230 |
+
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order="C")
|
231 |
+
a1.flags.writeable = False
|
232 |
+
a2 = m.wrap(a1)
|
233 |
+
assert_references(a1, a2)
|
234 |
+
|
235 |
+
a1 = np.random.random((4, 4, 4))
|
236 |
+
a2 = m.wrap(a1)
|
237 |
+
assert_references(a1, a2)
|
238 |
+
|
239 |
+
a1t = a1.transpose()
|
240 |
+
a2 = m.wrap(a1t)
|
241 |
+
assert_references(a1t, a2, a1)
|
242 |
+
|
243 |
+
a1d = a1.diagonal()
|
244 |
+
a2 = m.wrap(a1d)
|
245 |
+
assert_references(a1d, a2, a1)
|
246 |
+
|
247 |
+
a1m = a1[::-1, ::-1, ::-1]
|
248 |
+
a2 = m.wrap(a1m)
|
249 |
+
assert_references(a1m, a2, a1)
|
250 |
+
|
251 |
+
|
252 |
+
def test_numpy_view(capture):
|
253 |
+
with capture:
|
254 |
+
ac = m.ArrayClass()
|
255 |
+
ac_view_1 = ac.numpy_view()
|
256 |
+
ac_view_2 = ac.numpy_view()
|
257 |
+
assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32))
|
258 |
+
del ac
|
259 |
+
pytest.gc_collect()
|
260 |
+
assert (
|
261 |
+
capture
|
262 |
+
== """
|
263 |
+
ArrayClass()
|
264 |
+
ArrayClass::numpy_view()
|
265 |
+
ArrayClass::numpy_view()
|
266 |
+
"""
|
267 |
+
)
|
268 |
+
ac_view_1[0] = 4
|
269 |
+
ac_view_1[1] = 3
|
270 |
+
assert ac_view_2[0] == 4
|
271 |
+
assert ac_view_2[1] == 3
|
272 |
+
with capture:
|
273 |
+
del ac_view_1
|
274 |
+
del ac_view_2
|
275 |
+
pytest.gc_collect()
|
276 |
+
pytest.gc_collect()
|
277 |
+
assert (
|
278 |
+
capture
|
279 |
+
== """
|
280 |
+
~ArrayClass()
|
281 |
+
"""
|
282 |
+
)
|
283 |
+
|
284 |
+
|
285 |
+
def test_cast_numpy_int64_to_uint64():
|
286 |
+
m.function_taking_uint64(123)
|
287 |
+
m.function_taking_uint64(np.uint64(123))
|
288 |
+
|
289 |
+
|
290 |
+
def test_isinstance():
|
291 |
+
assert m.isinstance_untyped(np.array([1, 2, 3]), "not an array")
|
292 |
+
assert m.isinstance_typed(np.array([1.0, 2.0, 3.0]))
|
293 |
+
|
294 |
+
|
295 |
+
def test_constructors():
|
296 |
+
defaults = m.default_constructors()
|
297 |
+
for a in defaults.values():
|
298 |
+
assert a.size == 0
|
299 |
+
assert defaults["array"].dtype == np.array([]).dtype
|
300 |
+
assert defaults["array_t<int32>"].dtype == np.int32
|
301 |
+
assert defaults["array_t<double>"].dtype == np.float64
|
302 |
+
|
303 |
+
results = m.converting_constructors([1, 2, 3])
|
304 |
+
for a in results.values():
|
305 |
+
np.testing.assert_array_equal(a, [1, 2, 3])
|
306 |
+
assert results["array"].dtype == np.int_
|
307 |
+
assert results["array_t<int32>"].dtype == np.int32
|
308 |
+
assert results["array_t<double>"].dtype == np.float64
|
309 |
+
|
310 |
+
|
311 |
+
def test_overload_resolution(msg):
|
312 |
+
# Exact overload matches:
|
313 |
+
assert m.overloaded(np.array([1], dtype="float64")) == "double"
|
314 |
+
assert m.overloaded(np.array([1], dtype="float32")) == "float"
|
315 |
+
assert m.overloaded(np.array([1], dtype="ushort")) == "unsigned short"
|
316 |
+
assert m.overloaded(np.array([1], dtype="intc")) == "int"
|
317 |
+
assert m.overloaded(np.array([1], dtype="longlong")) == "long long"
|
318 |
+
assert m.overloaded(np.array([1], dtype="complex")) == "double complex"
|
319 |
+
assert m.overloaded(np.array([1], dtype="csingle")) == "float complex"
|
320 |
+
|
321 |
+
# No exact match, should call first convertible version:
|
322 |
+
assert m.overloaded(np.array([1], dtype="uint8")) == "double"
|
323 |
+
|
324 |
+
with pytest.raises(TypeError) as excinfo:
|
325 |
+
m.overloaded("not an array")
|
326 |
+
assert (
|
327 |
+
msg(excinfo.value)
|
328 |
+
== """
|
329 |
+
overloaded(): incompatible function arguments. The following argument types are supported:
|
330 |
+
1. (arg0: numpy.ndarray[numpy.float64]) -> str
|
331 |
+
2. (arg0: numpy.ndarray[numpy.float32]) -> str
|
332 |
+
3. (arg0: numpy.ndarray[numpy.int32]) -> str
|
333 |
+
4. (arg0: numpy.ndarray[numpy.uint16]) -> str
|
334 |
+
5. (arg0: numpy.ndarray[numpy.int64]) -> str
|
335 |
+
6. (arg0: numpy.ndarray[numpy.complex128]) -> str
|
336 |
+
7. (arg0: numpy.ndarray[numpy.complex64]) -> str
|
337 |
+
|
338 |
+
Invoked with: 'not an array'
|
339 |
+
"""
|
340 |
+
)
|
341 |
+
|
342 |
+
assert m.overloaded2(np.array([1], dtype="float64")) == "double"
|
343 |
+
assert m.overloaded2(np.array([1], dtype="float32")) == "float"
|
344 |
+
assert m.overloaded2(np.array([1], dtype="complex64")) == "float complex"
|
345 |
+
assert m.overloaded2(np.array([1], dtype="complex128")) == "double complex"
|
346 |
+
assert m.overloaded2(np.array([1], dtype="float32")) == "float"
|
347 |
+
|
348 |
+
assert m.overloaded3(np.array([1], dtype="float64")) == "double"
|
349 |
+
assert m.overloaded3(np.array([1], dtype="intc")) == "int"
|
350 |
+
expected_exc = """
|
351 |
+
overloaded3(): incompatible function arguments. The following argument types are supported:
|
352 |
+
1. (arg0: numpy.ndarray[numpy.int32]) -> str
|
353 |
+
2. (arg0: numpy.ndarray[numpy.float64]) -> str
|
354 |
+
|
355 |
+
Invoked with: """
|
356 |
+
|
357 |
+
with pytest.raises(TypeError) as excinfo:
|
358 |
+
m.overloaded3(np.array([1], dtype="uintc"))
|
359 |
+
assert msg(excinfo.value) == expected_exc + repr(np.array([1], dtype="uint32"))
|
360 |
+
with pytest.raises(TypeError) as excinfo:
|
361 |
+
m.overloaded3(np.array([1], dtype="float32"))
|
362 |
+
assert msg(excinfo.value) == expected_exc + repr(np.array([1.0], dtype="float32"))
|
363 |
+
with pytest.raises(TypeError) as excinfo:
|
364 |
+
m.overloaded3(np.array([1], dtype="complex"))
|
365 |
+
assert msg(excinfo.value) == expected_exc + repr(np.array([1.0 + 0.0j]))
|
366 |
+
|
367 |
+
# Exact matches:
|
368 |
+
assert m.overloaded4(np.array([1], dtype="double")) == "double"
|
369 |
+
assert m.overloaded4(np.array([1], dtype="longlong")) == "long long"
|
370 |
+
# Non-exact matches requiring conversion. Since float to integer isn't a
|
371 |
+
# save conversion, it should go to the double overload, but short can go to
|
372 |
+
# either (and so should end up on the first-registered, the long long).
|
373 |
+
assert m.overloaded4(np.array([1], dtype="float32")) == "double"
|
374 |
+
assert m.overloaded4(np.array([1], dtype="short")) == "long long"
|
375 |
+
|
376 |
+
assert m.overloaded5(np.array([1], dtype="double")) == "double"
|
377 |
+
assert m.overloaded5(np.array([1], dtype="uintc")) == "unsigned int"
|
378 |
+
assert m.overloaded5(np.array([1], dtype="float32")) == "unsigned int"
|
379 |
+
|
380 |
+
|
381 |
+
def test_greedy_string_overload():
|
382 |
+
"""Tests fix for #685 - ndarray shouldn't go to std::string overload"""
|
383 |
+
|
384 |
+
assert m.issue685("abc") == "string"
|
385 |
+
assert m.issue685(np.array([97, 98, 99], dtype="b")) == "array"
|
386 |
+
assert m.issue685(123) == "other"
|
387 |
+
|
388 |
+
|
389 |
+
def test_array_unchecked_fixed_dims(msg):
|
390 |
+
z1 = np.array([[1, 2], [3, 4]], dtype="float64")
|
391 |
+
m.proxy_add2(z1, 10)
|
392 |
+
assert np.all(z1 == [[11, 12], [13, 14]])
|
393 |
+
|
394 |
+
with pytest.raises(ValueError) as excinfo:
|
395 |
+
m.proxy_add2(np.array([1.0, 2, 3]), 5.0)
|
396 |
+
assert (
|
397 |
+
msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2"
|
398 |
+
)
|
399 |
+
|
400 |
+
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype="int")
|
401 |
+
assert np.all(m.proxy_init3(3.0) == expect_c)
|
402 |
+
expect_f = np.transpose(expect_c)
|
403 |
+
assert np.all(m.proxy_init3F(3.0) == expect_f)
|
404 |
+
|
405 |
+
assert m.proxy_squared_L2_norm(np.array(range(6))) == 55
|
406 |
+
assert m.proxy_squared_L2_norm(np.array(range(6), dtype="float64")) == 55
|
407 |
+
|
408 |
+
assert m.proxy_auxiliaries2(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
|
409 |
+
assert m.proxy_auxiliaries2(z1) == m.array_auxiliaries2(z1)
|
410 |
+
|
411 |
+
assert m.proxy_auxiliaries1_const_ref(z1[0, :])
|
412 |
+
assert m.proxy_auxiliaries2_const_ref(z1)
|
413 |
+
|
414 |
+
|
415 |
+
def test_array_unchecked_dyn_dims(msg):
|
416 |
+
z1 = np.array([[1, 2], [3, 4]], dtype="float64")
|
417 |
+
m.proxy_add2_dyn(z1, 10)
|
418 |
+
assert np.all(z1 == [[11, 12], [13, 14]])
|
419 |
+
|
420 |
+
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype="int")
|
421 |
+
assert np.all(m.proxy_init3_dyn(3.0) == expect_c)
|
422 |
+
|
423 |
+
assert m.proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
|
424 |
+
assert m.proxy_auxiliaries2_dyn(z1) == m.array_auxiliaries2(z1)
|
425 |
+
|
426 |
+
|
427 |
+
def test_array_failure():
|
428 |
+
with pytest.raises(ValueError) as excinfo:
|
429 |
+
m.array_fail_test()
|
430 |
+
assert str(excinfo.value) == "cannot create a pybind11::array from a nullptr"
|
431 |
+
|
432 |
+
with pytest.raises(ValueError) as excinfo:
|
433 |
+
m.array_t_fail_test()
|
434 |
+
assert str(excinfo.value) == "cannot create a pybind11::array_t from a nullptr"
|
435 |
+
|
436 |
+
with pytest.raises(ValueError) as excinfo:
|
437 |
+
m.array_fail_test_negative_size()
|
438 |
+
assert str(excinfo.value) == "negative dimensions are not allowed"
|
439 |
+
|
440 |
+
|
441 |
+
def test_initializer_list():
|
442 |
+
assert m.array_initializer_list1().shape == (1,)
|
443 |
+
assert m.array_initializer_list2().shape == (1, 2)
|
444 |
+
assert m.array_initializer_list3().shape == (1, 2, 3)
|
445 |
+
assert m.array_initializer_list4().shape == (1, 2, 3, 4)
|
446 |
+
|
447 |
+
|
448 |
+
def test_array_resize(msg):
|
449 |
+
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype="float64")
|
450 |
+
m.array_reshape2(a)
|
451 |
+
assert a.size == 9
|
452 |
+
assert np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
453 |
+
|
454 |
+
# total size change should succced with refcheck off
|
455 |
+
m.array_resize3(a, 4, False)
|
456 |
+
assert a.size == 64
|
457 |
+
# ... and fail with refcheck on
|
458 |
+
try:
|
459 |
+
m.array_resize3(a, 3, True)
|
460 |
+
except ValueError as e:
|
461 |
+
assert str(e).startswith("cannot resize an array")
|
462 |
+
# transposed array doesn't own data
|
463 |
+
b = a.transpose()
|
464 |
+
try:
|
465 |
+
m.array_resize3(b, 3, False)
|
466 |
+
except ValueError as e:
|
467 |
+
assert str(e).startswith("cannot resize this array: it does not own its data")
|
468 |
+
# ... but reshape should be fine
|
469 |
+
m.array_reshape2(b)
|
470 |
+
assert b.shape == (8, 8)
|
471 |
+
|
472 |
+
|
473 |
+
@pytest.mark.xfail("env.PYPY")
|
474 |
+
def test_array_create_and_resize(msg):
|
475 |
+
a = m.create_and_resize(2)
|
476 |
+
assert a.size == 4
|
477 |
+
assert np.all(a == 42.0)
|
478 |
+
|
479 |
+
|
480 |
+
def test_index_using_ellipsis():
|
481 |
+
a = m.index_using_ellipsis(np.zeros((5, 6, 7)))
|
482 |
+
assert a.shape == (6,)
|
483 |
+
|
484 |
+
|
485 |
+
@pytest.mark.parametrize(
|
486 |
+
"test_func",
|
487 |
+
[
|
488 |
+
m.test_fmt_desc_float,
|
489 |
+
m.test_fmt_desc_double,
|
490 |
+
m.test_fmt_desc_const_float,
|
491 |
+
m.test_fmt_desc_const_double,
|
492 |
+
],
|
493 |
+
)
|
494 |
+
def test_format_descriptors_for_floating_point_types(test_func):
|
495 |
+
assert "numpy.ndarray[numpy.float" in test_func.__doc__
|
496 |
+
|
497 |
+
|
498 |
+
@pytest.mark.parametrize("forcecast", [False, True])
|
499 |
+
@pytest.mark.parametrize("contiguity", [None, "C", "F"])
|
500 |
+
@pytest.mark.parametrize("noconvert", [False, True])
|
501 |
+
@pytest.mark.filterwarnings(
|
502 |
+
"ignore:Casting complex values to real discards the imaginary part:numpy.ComplexWarning"
|
503 |
+
)
|
504 |
+
def test_argument_conversions(forcecast, contiguity, noconvert):
|
505 |
+
function_name = "accept_double"
|
506 |
+
if contiguity == "C":
|
507 |
+
function_name += "_c_style"
|
508 |
+
elif contiguity == "F":
|
509 |
+
function_name += "_f_style"
|
510 |
+
if forcecast:
|
511 |
+
function_name += "_forcecast"
|
512 |
+
if noconvert:
|
513 |
+
function_name += "_noconvert"
|
514 |
+
function = getattr(m, function_name)
|
515 |
+
|
516 |
+
for dtype in [np.dtype("float32"), np.dtype("float64"), np.dtype("complex128")]:
|
517 |
+
for order in ["C", "F"]:
|
518 |
+
for shape in [(2, 2), (1, 3, 1, 1), (1, 1, 1), (0,)]:
|
519 |
+
if not noconvert:
|
520 |
+
# If noconvert is not passed, only complex128 needs to be truncated and
|
521 |
+
# "cannot be safely obtained". So without `forcecast`, the argument shouldn't
|
522 |
+
# be accepted.
|
523 |
+
should_raise = dtype.name == "complex128" and not forcecast
|
524 |
+
else:
|
525 |
+
# If noconvert is passed, only float64 and the matching order is accepted.
|
526 |
+
# If at most one dimension has a size greater than 1, the array is also
|
527 |
+
# trivially contiguous.
|
528 |
+
trivially_contiguous = sum(1 for d in shape if d > 1) <= 1
|
529 |
+
should_raise = dtype.name != "float64" or (
|
530 |
+
contiguity is not None
|
531 |
+
and contiguity != order
|
532 |
+
and not trivially_contiguous
|
533 |
+
)
|
534 |
+
|
535 |
+
array = np.zeros(shape, dtype=dtype, order=order)
|
536 |
+
if not should_raise:
|
537 |
+
function(array)
|
538 |
+
else:
|
539 |
+
with pytest.raises(
|
540 |
+
TypeError, match="incompatible function arguments"
|
541 |
+
):
|
542 |
+
function(array)
|
543 |
+
|
544 |
+
|
545 |
+
@pytest.mark.xfail("env.PYPY")
|
546 |
+
def test_dtype_refcount_leak():
|
547 |
+
from sys import getrefcount
|
548 |
+
|
549 |
+
dtype = np.dtype(np.float_)
|
550 |
+
a = np.array([1], dtype=dtype)
|
551 |
+
before = getrefcount(dtype)
|
552 |
+
m.ndim(a)
|
553 |
+
after = getrefcount(dtype)
|
554 |
+
assert after == before
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_numpy_dtypes.cpp
ADDED
@@ -0,0 +1,522 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_numpy_dtypes.cpp -- Structured and compound NumPy dtypes
|
3 |
+
|
4 |
+
Copyright (c) 2016 Ivan Smirnov
|
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/numpy.h>
|
12 |
+
|
13 |
+
#ifdef __GNUC__
|
14 |
+
#define PYBIND11_PACKED(cls) cls __attribute__((__packed__))
|
15 |
+
#else
|
16 |
+
#define PYBIND11_PACKED(cls) __pragma(pack(push, 1)) cls __pragma(pack(pop))
|
17 |
+
#endif
|
18 |
+
|
19 |
+
namespace py = pybind11;
|
20 |
+
|
21 |
+
struct SimpleStruct {
|
22 |
+
bool bool_;
|
23 |
+
uint32_t uint_;
|
24 |
+
float float_;
|
25 |
+
long double ldbl_;
|
26 |
+
};
|
27 |
+
|
28 |
+
std::ostream& operator<<(std::ostream& os, const SimpleStruct& v) {
|
29 |
+
return os << "s:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_;
|
30 |
+
}
|
31 |
+
|
32 |
+
struct SimpleStructReordered {
|
33 |
+
bool bool_;
|
34 |
+
float float_;
|
35 |
+
uint32_t uint_;
|
36 |
+
long double ldbl_;
|
37 |
+
};
|
38 |
+
|
39 |
+
PYBIND11_PACKED(struct PackedStruct {
|
40 |
+
bool bool_;
|
41 |
+
uint32_t uint_;
|
42 |
+
float float_;
|
43 |
+
long double ldbl_;
|
44 |
+
});
|
45 |
+
|
46 |
+
std::ostream& operator<<(std::ostream& os, const PackedStruct& v) {
|
47 |
+
return os << "p:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_;
|
48 |
+
}
|
49 |
+
|
50 |
+
PYBIND11_PACKED(struct NestedStruct {
|
51 |
+
SimpleStruct a;
|
52 |
+
PackedStruct b;
|
53 |
+
});
|
54 |
+
|
55 |
+
std::ostream& operator<<(std::ostream& os, const NestedStruct& v) {
|
56 |
+
return os << "n:a=" << v.a << ";b=" << v.b;
|
57 |
+
}
|
58 |
+
|
59 |
+
struct PartialStruct {
|
60 |
+
bool bool_;
|
61 |
+
uint32_t uint_;
|
62 |
+
float float_;
|
63 |
+
uint64_t dummy2;
|
64 |
+
long double ldbl_;
|
65 |
+
};
|
66 |
+
|
67 |
+
struct PartialNestedStruct {
|
68 |
+
uint64_t dummy1;
|
69 |
+
PartialStruct a;
|
70 |
+
uint64_t dummy2;
|
71 |
+
};
|
72 |
+
|
73 |
+
struct UnboundStruct { };
|
74 |
+
|
75 |
+
struct StringStruct {
|
76 |
+
char a[3];
|
77 |
+
std::array<char, 3> b;
|
78 |
+
};
|
79 |
+
|
80 |
+
struct ComplexStruct {
|
81 |
+
std::complex<float> cflt;
|
82 |
+
std::complex<double> cdbl;
|
83 |
+
};
|
84 |
+
|
85 |
+
std::ostream& operator<<(std::ostream& os, const ComplexStruct& v) {
|
86 |
+
return os << "c:" << v.cflt << "," << v.cdbl;
|
87 |
+
}
|
88 |
+
|
89 |
+
struct ArrayStruct {
|
90 |
+
char a[3][4];
|
91 |
+
int32_t b[2];
|
92 |
+
std::array<uint8_t, 3> c;
|
93 |
+
std::array<float, 2> d[4];
|
94 |
+
};
|
95 |
+
|
96 |
+
PYBIND11_PACKED(struct StructWithUglyNames {
|
97 |
+
int8_t __x__;
|
98 |
+
uint64_t __y__;
|
99 |
+
});
|
100 |
+
|
101 |
+
enum class E1 : int64_t { A = -1, B = 1 };
|
102 |
+
enum E2 : uint8_t { X = 1, Y = 2 };
|
103 |
+
|
104 |
+
PYBIND11_PACKED(struct EnumStruct {
|
105 |
+
E1 e1;
|
106 |
+
E2 e2;
|
107 |
+
});
|
108 |
+
|
109 |
+
std::ostream& operator<<(std::ostream& os, const StringStruct& v) {
|
110 |
+
os << "a='";
|
111 |
+
for (size_t i = 0; i < 3 && (v.a[i] != 0); i++)
|
112 |
+
os << v.a[i];
|
113 |
+
os << "',b='";
|
114 |
+
for (size_t i = 0; i < 3 && (v.b[i] != 0); i++)
|
115 |
+
os << v.b[i];
|
116 |
+
return os << "'";
|
117 |
+
}
|
118 |
+
|
119 |
+
std::ostream& operator<<(std::ostream& os, const ArrayStruct& v) {
|
120 |
+
os << "a={";
|
121 |
+
for (int i = 0; i < 3; i++) {
|
122 |
+
if (i > 0)
|
123 |
+
os << ',';
|
124 |
+
os << '{';
|
125 |
+
for (int j = 0; j < 3; j++)
|
126 |
+
os << v.a[i][j] << ',';
|
127 |
+
os << v.a[i][3] << '}';
|
128 |
+
}
|
129 |
+
os << "},b={" << v.b[0] << ',' << v.b[1];
|
130 |
+
os << "},c={" << int(v.c[0]) << ',' << int(v.c[1]) << ',' << int(v.c[2]);
|
131 |
+
os << "},d={";
|
132 |
+
for (int i = 0; i < 4; i++) {
|
133 |
+
if (i > 0)
|
134 |
+
os << ',';
|
135 |
+
os << '{' << v.d[i][0] << ',' << v.d[i][1] << '}';
|
136 |
+
}
|
137 |
+
return os << '}';
|
138 |
+
}
|
139 |
+
|
140 |
+
std::ostream& operator<<(std::ostream& os, const EnumStruct& v) {
|
141 |
+
return os << "e1=" << (v.e1 == E1::A ? "A" : "B") << ",e2=" << (v.e2 == E2::X ? "X" : "Y");
|
142 |
+
}
|
143 |
+
|
144 |
+
template <typename T>
|
145 |
+
py::array mkarray_via_buffer(size_t n) {
|
146 |
+
return py::array(py::buffer_info(nullptr, sizeof(T),
|
147 |
+
py::format_descriptor<T>::format(),
|
148 |
+
1, { n }, { sizeof(T) }));
|
149 |
+
}
|
150 |
+
|
151 |
+
#define SET_TEST_VALS(s, i) do { \
|
152 |
+
s.bool_ = (i) % 2 != 0; \
|
153 |
+
s.uint_ = (uint32_t) (i); \
|
154 |
+
s.float_ = (float) (i) * 1.5f; \
|
155 |
+
s.ldbl_ = (long double) (i) * -2.5L; } while (0)
|
156 |
+
|
157 |
+
template <typename S>
|
158 |
+
py::array_t<S, 0> create_recarray(size_t n) {
|
159 |
+
auto arr = mkarray_via_buffer<S>(n);
|
160 |
+
auto req = arr.request();
|
161 |
+
auto ptr = static_cast<S*>(req.ptr);
|
162 |
+
for (size_t i = 0; i < n; i++) {
|
163 |
+
SET_TEST_VALS(ptr[i], i);
|
164 |
+
}
|
165 |
+
return arr;
|
166 |
+
}
|
167 |
+
|
168 |
+
template <typename S>
|
169 |
+
py::list print_recarray(py::array_t<S, 0> arr) {
|
170 |
+
const auto req = arr.request();
|
171 |
+
const auto ptr = static_cast<S*>(req.ptr);
|
172 |
+
auto l = py::list();
|
173 |
+
for (py::ssize_t i = 0; i < req.size; i++) {
|
174 |
+
std::stringstream ss;
|
175 |
+
ss << ptr[i];
|
176 |
+
l.append(py::str(ss.str()));
|
177 |
+
}
|
178 |
+
return l;
|
179 |
+
}
|
180 |
+
|
181 |
+
py::array_t<int32_t, 0> test_array_ctors(int i) {
|
182 |
+
using arr_t = py::array_t<int32_t, 0>;
|
183 |
+
|
184 |
+
std::vector<int32_t> data { 1, 2, 3, 4, 5, 6 };
|
185 |
+
std::vector<py::ssize_t> shape { 3, 2 };
|
186 |
+
std::vector<py::ssize_t> strides { 8, 4 };
|
187 |
+
|
188 |
+
auto ptr = data.data();
|
189 |
+
auto vptr = (void *) ptr;
|
190 |
+
auto dtype = py::dtype("int32");
|
191 |
+
|
192 |
+
py::buffer_info buf_ndim1(vptr, 4, "i", 6);
|
193 |
+
py::buffer_info buf_ndim1_null(nullptr, 4, "i", 6);
|
194 |
+
py::buffer_info buf_ndim2(vptr, 4, "i", 2, shape, strides);
|
195 |
+
py::buffer_info buf_ndim2_null(nullptr, 4, "i", 2, shape, strides);
|
196 |
+
|
197 |
+
auto fill = [](py::array arr) {
|
198 |
+
auto req = arr.request();
|
199 |
+
for (int i = 0; i < 6; i++) ((int32_t *) req.ptr)[i] = i + 1;
|
200 |
+
return arr;
|
201 |
+
};
|
202 |
+
|
203 |
+
switch (i) {
|
204 |
+
// shape: (3, 2)
|
205 |
+
case 10: return arr_t(shape, strides, ptr);
|
206 |
+
case 11: return py::array(shape, strides, ptr);
|
207 |
+
case 12: return py::array(dtype, shape, strides, vptr);
|
208 |
+
case 13: return arr_t(shape, ptr);
|
209 |
+
case 14: return py::array(shape, ptr);
|
210 |
+
case 15: return py::array(dtype, shape, vptr);
|
211 |
+
case 16: return arr_t(buf_ndim2);
|
212 |
+
case 17: return py::array(buf_ndim2);
|
213 |
+
// shape: (3, 2) - post-fill
|
214 |
+
case 20: return fill(arr_t(shape, strides));
|
215 |
+
case 21: return py::array(shape, strides, ptr); // can't have nullptr due to templated ctor
|
216 |
+
case 22: return fill(py::array(dtype, shape, strides));
|
217 |
+
case 23: return fill(arr_t(shape));
|
218 |
+
case 24: return py::array(shape, ptr); // can't have nullptr due to templated ctor
|
219 |
+
case 25: return fill(py::array(dtype, shape));
|
220 |
+
case 26: return fill(arr_t(buf_ndim2_null));
|
221 |
+
case 27: return fill(py::array(buf_ndim2_null));
|
222 |
+
// shape: (6, )
|
223 |
+
case 30: return arr_t(6, ptr);
|
224 |
+
case 31: return py::array(6, ptr);
|
225 |
+
case 32: return py::array(dtype, 6, vptr);
|
226 |
+
case 33: return arr_t(buf_ndim1);
|
227 |
+
case 34: return py::array(buf_ndim1);
|
228 |
+
// shape: (6, )
|
229 |
+
case 40: return fill(arr_t(6));
|
230 |
+
case 41: return py::array(6, ptr); // can't have nullptr due to templated ctor
|
231 |
+
case 42: return fill(py::array(dtype, 6));
|
232 |
+
case 43: return fill(arr_t(buf_ndim1_null));
|
233 |
+
case 44: return fill(py::array(buf_ndim1_null));
|
234 |
+
}
|
235 |
+
return arr_t();
|
236 |
+
}
|
237 |
+
|
238 |
+
py::list test_dtype_ctors() {
|
239 |
+
py::list list;
|
240 |
+
list.append(py::dtype("int32"));
|
241 |
+
list.append(py::dtype(std::string("float64")));
|
242 |
+
list.append(py::dtype::from_args(py::str("bool")));
|
243 |
+
py::list names, offsets, formats;
|
244 |
+
py::dict dict;
|
245 |
+
names.append(py::str("a")); names.append(py::str("b")); dict["names"] = names;
|
246 |
+
offsets.append(py::int_(1)); offsets.append(py::int_(10)); dict["offsets"] = offsets;
|
247 |
+
formats.append(py::dtype("int32")); formats.append(py::dtype("float64")); dict["formats"] = formats;
|
248 |
+
dict["itemsize"] = py::int_(20);
|
249 |
+
list.append(py::dtype::from_args(dict));
|
250 |
+
list.append(py::dtype(names, formats, offsets, 20));
|
251 |
+
list.append(py::dtype(py::buffer_info((void *) 0, sizeof(unsigned int), "I", 1)));
|
252 |
+
list.append(py::dtype(py::buffer_info((void *) 0, 0, "T{i:a:f:b:}", 1)));
|
253 |
+
return list;
|
254 |
+
}
|
255 |
+
|
256 |
+
struct A {};
|
257 |
+
struct B {};
|
258 |
+
|
259 |
+
TEST_SUBMODULE(numpy_dtypes, m) {
|
260 |
+
try { py::module_::import("numpy"); }
|
261 |
+
catch (...) { return; }
|
262 |
+
|
263 |
+
// typeinfo may be registered before the dtype descriptor for scalar casts to work...
|
264 |
+
py::class_<SimpleStruct>(m, "SimpleStruct")
|
265 |
+
// Explicit construct to ensure zero-valued initialization.
|
266 |
+
.def(py::init([]() { return SimpleStruct(); }))
|
267 |
+
.def_readwrite("bool_", &SimpleStruct::bool_)
|
268 |
+
.def_readwrite("uint_", &SimpleStruct::uint_)
|
269 |
+
.def_readwrite("float_", &SimpleStruct::float_)
|
270 |
+
.def_readwrite("ldbl_", &SimpleStruct::ldbl_)
|
271 |
+
.def("astuple",
|
272 |
+
[](const SimpleStruct &self) {
|
273 |
+
return py::make_tuple(self.bool_, self.uint_, self.float_, self.ldbl_);
|
274 |
+
})
|
275 |
+
.def_static("fromtuple", [](const py::tuple &tup) {
|
276 |
+
if (py::len(tup) != 4) {
|
277 |
+
throw py::cast_error("Invalid size");
|
278 |
+
}
|
279 |
+
return SimpleStruct{
|
280 |
+
tup[0].cast<bool>(),
|
281 |
+
tup[1].cast<uint32_t>(),
|
282 |
+
tup[2].cast<float>(),
|
283 |
+
tup[3].cast<long double>()};
|
284 |
+
});
|
285 |
+
|
286 |
+
PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_);
|
287 |
+
PYBIND11_NUMPY_DTYPE(SimpleStructReordered, bool_, uint_, float_, ldbl_);
|
288 |
+
PYBIND11_NUMPY_DTYPE(PackedStruct, bool_, uint_, float_, ldbl_);
|
289 |
+
PYBIND11_NUMPY_DTYPE(NestedStruct, a, b);
|
290 |
+
PYBIND11_NUMPY_DTYPE(PartialStruct, bool_, uint_, float_, ldbl_);
|
291 |
+
PYBIND11_NUMPY_DTYPE(PartialNestedStruct, a);
|
292 |
+
PYBIND11_NUMPY_DTYPE(StringStruct, a, b);
|
293 |
+
PYBIND11_NUMPY_DTYPE(ArrayStruct, a, b, c, d);
|
294 |
+
PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2);
|
295 |
+
PYBIND11_NUMPY_DTYPE(ComplexStruct, cflt, cdbl);
|
296 |
+
|
297 |
+
// ... or after
|
298 |
+
py::class_<PackedStruct>(m, "PackedStruct");
|
299 |
+
|
300 |
+
PYBIND11_NUMPY_DTYPE_EX(StructWithUglyNames, __x__, "x", __y__, "y");
|
301 |
+
|
302 |
+
// If uncommented, this should produce a static_assert failure telling the user that the struct
|
303 |
+
// is not a POD type
|
304 |
+
// struct NotPOD { std::string v; NotPOD() : v("hi") {}; };
|
305 |
+
// PYBIND11_NUMPY_DTYPE(NotPOD, v);
|
306 |
+
|
307 |
+
// Check that dtypes can be registered programmatically, both from
|
308 |
+
// initializer lists of field descriptors and from other containers.
|
309 |
+
py::detail::npy_format_descriptor<A>::register_dtype(
|
310 |
+
{}
|
311 |
+
);
|
312 |
+
py::detail::npy_format_descriptor<B>::register_dtype(
|
313 |
+
std::vector<py::detail::field_descriptor>{}
|
314 |
+
);
|
315 |
+
|
316 |
+
// test_recarray, test_scalar_conversion
|
317 |
+
m.def("create_rec_simple", &create_recarray<SimpleStruct>);
|
318 |
+
m.def("create_rec_packed", &create_recarray<PackedStruct>);
|
319 |
+
m.def("create_rec_nested", [](size_t n) { // test_signature
|
320 |
+
py::array_t<NestedStruct, 0> arr = mkarray_via_buffer<NestedStruct>(n);
|
321 |
+
auto req = arr.request();
|
322 |
+
auto ptr = static_cast<NestedStruct*>(req.ptr);
|
323 |
+
for (size_t i = 0; i < n; i++) {
|
324 |
+
SET_TEST_VALS(ptr[i].a, i);
|
325 |
+
SET_TEST_VALS(ptr[i].b, i + 1);
|
326 |
+
}
|
327 |
+
return arr;
|
328 |
+
});
|
329 |
+
m.def("create_rec_partial", &create_recarray<PartialStruct>);
|
330 |
+
m.def("create_rec_partial_nested", [](size_t n) {
|
331 |
+
py::array_t<PartialNestedStruct, 0> arr = mkarray_via_buffer<PartialNestedStruct>(n);
|
332 |
+
auto req = arr.request();
|
333 |
+
auto ptr = static_cast<PartialNestedStruct*>(req.ptr);
|
334 |
+
for (size_t i = 0; i < n; i++) {
|
335 |
+
SET_TEST_VALS(ptr[i].a, i);
|
336 |
+
}
|
337 |
+
return arr;
|
338 |
+
});
|
339 |
+
m.def("print_rec_simple", &print_recarray<SimpleStruct>);
|
340 |
+
m.def("print_rec_packed", &print_recarray<PackedStruct>);
|
341 |
+
m.def("print_rec_nested", &print_recarray<NestedStruct>);
|
342 |
+
|
343 |
+
// test_format_descriptors
|
344 |
+
m.def("get_format_unbound", []() { return py::format_descriptor<UnboundStruct>::format(); });
|
345 |
+
m.def("print_format_descriptors", []() {
|
346 |
+
py::list l;
|
347 |
+
for (const auto &fmt : {
|
348 |
+
py::format_descriptor<SimpleStruct>::format(),
|
349 |
+
py::format_descriptor<PackedStruct>::format(),
|
350 |
+
py::format_descriptor<NestedStruct>::format(),
|
351 |
+
py::format_descriptor<PartialStruct>::format(),
|
352 |
+
py::format_descriptor<PartialNestedStruct>::format(),
|
353 |
+
py::format_descriptor<StringStruct>::format(),
|
354 |
+
py::format_descriptor<ArrayStruct>::format(),
|
355 |
+
py::format_descriptor<EnumStruct>::format(),
|
356 |
+
py::format_descriptor<ComplexStruct>::format()
|
357 |
+
}) {
|
358 |
+
l.append(py::cast(fmt));
|
359 |
+
}
|
360 |
+
return l;
|
361 |
+
});
|
362 |
+
|
363 |
+
// test_dtype
|
364 |
+
std::vector<const char *> dtype_names{
|
365 |
+
"byte", "short", "intc", "int_", "longlong",
|
366 |
+
"ubyte", "ushort", "uintc", "uint", "ulonglong",
|
367 |
+
"half", "single", "double", "longdouble",
|
368 |
+
"csingle", "cdouble", "clongdouble",
|
369 |
+
"bool_", "datetime64", "timedelta64", "object_"
|
370 |
+
};
|
371 |
+
|
372 |
+
m.def("print_dtypes", []() {
|
373 |
+
py::list l;
|
374 |
+
for (const py::handle &d : {
|
375 |
+
py::dtype::of<SimpleStruct>(),
|
376 |
+
py::dtype::of<PackedStruct>(),
|
377 |
+
py::dtype::of<NestedStruct>(),
|
378 |
+
py::dtype::of<PartialStruct>(),
|
379 |
+
py::dtype::of<PartialNestedStruct>(),
|
380 |
+
py::dtype::of<StringStruct>(),
|
381 |
+
py::dtype::of<ArrayStruct>(),
|
382 |
+
py::dtype::of<EnumStruct>(),
|
383 |
+
py::dtype::of<StructWithUglyNames>(),
|
384 |
+
py::dtype::of<ComplexStruct>()
|
385 |
+
})
|
386 |
+
l.append(py::str(d));
|
387 |
+
return l;
|
388 |
+
});
|
389 |
+
m.def("test_dtype_ctors", &test_dtype_ctors);
|
390 |
+
m.def("test_dtype_kind", [dtype_names]() {
|
391 |
+
py::list list;
|
392 |
+
for (auto& dt_name : dtype_names)
|
393 |
+
list.append(py::dtype(dt_name).kind());
|
394 |
+
return list;
|
395 |
+
});
|
396 |
+
m.def("test_dtype_char_", [dtype_names]() {
|
397 |
+
py::list list;
|
398 |
+
for (auto& dt_name : dtype_names)
|
399 |
+
list.append(py::dtype(dt_name).char_());
|
400 |
+
return list;
|
401 |
+
});
|
402 |
+
m.def("test_dtype_methods", []() {
|
403 |
+
py::list list;
|
404 |
+
auto dt1 = py::dtype::of<int32_t>();
|
405 |
+
auto dt2 = py::dtype::of<SimpleStruct>();
|
406 |
+
list.append(dt1); list.append(dt2);
|
407 |
+
list.append(py::bool_(dt1.has_fields())); list.append(py::bool_(dt2.has_fields()));
|
408 |
+
list.append(py::int_(dt1.itemsize())); list.append(py::int_(dt2.itemsize()));
|
409 |
+
return list;
|
410 |
+
});
|
411 |
+
struct TrailingPaddingStruct {
|
412 |
+
int32_t a;
|
413 |
+
char b;
|
414 |
+
};
|
415 |
+
PYBIND11_NUMPY_DTYPE(TrailingPaddingStruct, a, b);
|
416 |
+
m.def("trailing_padding_dtype", []() { return py::dtype::of<TrailingPaddingStruct>(); });
|
417 |
+
|
418 |
+
// test_string_array
|
419 |
+
m.def("create_string_array", [](bool non_empty) {
|
420 |
+
py::array_t<StringStruct, 0> arr = mkarray_via_buffer<StringStruct>(non_empty ? 4 : 0);
|
421 |
+
if (non_empty) {
|
422 |
+
auto req = arr.request();
|
423 |
+
auto ptr = static_cast<StringStruct*>(req.ptr);
|
424 |
+
for (py::ssize_t i = 0; i < req.size * req.itemsize; i++)
|
425 |
+
static_cast<char*>(req.ptr)[i] = 0;
|
426 |
+
ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a';
|
427 |
+
ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a';
|
428 |
+
ptr[3].a[0] = 'a'; ptr[3].b[0] = 'a';
|
429 |
+
|
430 |
+
ptr[2].a[1] = 'b'; ptr[2].b[1] = 'b';
|
431 |
+
ptr[3].a[1] = 'b'; ptr[3].b[1] = 'b';
|
432 |
+
|
433 |
+
ptr[3].a[2] = 'c'; ptr[3].b[2] = 'c';
|
434 |
+
}
|
435 |
+
return arr;
|
436 |
+
});
|
437 |
+
m.def("print_string_array", &print_recarray<StringStruct>);
|
438 |
+
|
439 |
+
// test_array_array
|
440 |
+
m.def("create_array_array", [](size_t n) {
|
441 |
+
py::array_t<ArrayStruct, 0> arr = mkarray_via_buffer<ArrayStruct>(n);
|
442 |
+
auto ptr = (ArrayStruct *) arr.mutable_data();
|
443 |
+
for (size_t i = 0; i < n; i++) {
|
444 |
+
for (size_t j = 0; j < 3; j++)
|
445 |
+
for (size_t k = 0; k < 4; k++)
|
446 |
+
ptr[i].a[j][k] = char('A' + (i * 100 + j * 10 + k) % 26);
|
447 |
+
for (size_t j = 0; j < 2; j++)
|
448 |
+
ptr[i].b[j] = int32_t(i * 1000 + j);
|
449 |
+
for (size_t j = 0; j < 3; j++)
|
450 |
+
ptr[i].c[j] = uint8_t(i * 10 + j);
|
451 |
+
for (size_t j = 0; j < 4; j++)
|
452 |
+
for (size_t k = 0; k < 2; k++)
|
453 |
+
ptr[i].d[j][k] = float(i) * 100.0f + float(j) * 10.0f + float(k);
|
454 |
+
}
|
455 |
+
return arr;
|
456 |
+
});
|
457 |
+
m.def("print_array_array", &print_recarray<ArrayStruct>);
|
458 |
+
|
459 |
+
// test_enum_array
|
460 |
+
m.def("create_enum_array", [](size_t n) {
|
461 |
+
py::array_t<EnumStruct, 0> arr = mkarray_via_buffer<EnumStruct>(n);
|
462 |
+
auto ptr = (EnumStruct *) arr.mutable_data();
|
463 |
+
for (size_t i = 0; i < n; i++) {
|
464 |
+
ptr[i].e1 = static_cast<E1>(-1 + ((int) i % 2) * 2);
|
465 |
+
ptr[i].e2 = static_cast<E2>(1 + (i % 2));
|
466 |
+
}
|
467 |
+
return arr;
|
468 |
+
});
|
469 |
+
m.def("print_enum_array", &print_recarray<EnumStruct>);
|
470 |
+
|
471 |
+
// test_complex_array
|
472 |
+
m.def("create_complex_array", [](size_t n) {
|
473 |
+
py::array_t<ComplexStruct, 0> arr = mkarray_via_buffer<ComplexStruct>(n);
|
474 |
+
auto ptr = (ComplexStruct *) arr.mutable_data();
|
475 |
+
for (size_t i = 0; i < n; i++) {
|
476 |
+
ptr[i].cflt.real(float(i));
|
477 |
+
ptr[i].cflt.imag(float(i) + 0.25f);
|
478 |
+
ptr[i].cdbl.real(double(i) + 0.5);
|
479 |
+
ptr[i].cdbl.imag(double(i) + 0.75);
|
480 |
+
}
|
481 |
+
return arr;
|
482 |
+
});
|
483 |
+
m.def("print_complex_array", &print_recarray<ComplexStruct>);
|
484 |
+
|
485 |
+
// test_array_constructors
|
486 |
+
m.def("test_array_ctors", &test_array_ctors);
|
487 |
+
|
488 |
+
// test_compare_buffer_info
|
489 |
+
struct CompareStruct {
|
490 |
+
bool x;
|
491 |
+
uint32_t y;
|
492 |
+
float z;
|
493 |
+
};
|
494 |
+
PYBIND11_NUMPY_DTYPE(CompareStruct, x, y, z);
|
495 |
+
m.def("compare_buffer_info", []() {
|
496 |
+
py::list list;
|
497 |
+
list.append(py::bool_(py::detail::compare_buffer_info<float>::compare(py::buffer_info(nullptr, sizeof(float), "f", 1))));
|
498 |
+
list.append(py::bool_(py::detail::compare_buffer_info<unsigned>::compare(py::buffer_info(nullptr, sizeof(int), "I", 1))));
|
499 |
+
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), "l", 1))));
|
500 |
+
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), sizeof(long) == sizeof(int) ? "i" : "q", 1))));
|
501 |
+
list.append(py::bool_(py::detail::compare_buffer_info<CompareStruct>::compare(py::buffer_info(nullptr, sizeof(CompareStruct), "T{?:x:3xI:y:f:z:}", 1))));
|
502 |
+
return list;
|
503 |
+
});
|
504 |
+
m.def("buffer_to_dtype", [](py::buffer& buf) { return py::dtype(buf.request()); });
|
505 |
+
|
506 |
+
// test_scalar_conversion
|
507 |
+
auto f_simple = [](SimpleStruct s) { return s.uint_ * 10; };
|
508 |
+
m.def("f_simple", f_simple);
|
509 |
+
m.def("f_packed", [](PackedStruct s) { return s.uint_ * 10; });
|
510 |
+
m.def("f_nested", [](NestedStruct s) { return s.a.uint_ * 10; });
|
511 |
+
|
512 |
+
// test_vectorize
|
513 |
+
m.def("f_simple_vectorized", py::vectorize(f_simple));
|
514 |
+
auto f_simple_pass_thru = [](SimpleStruct s) { return s; };
|
515 |
+
m.def("f_simple_pass_thru_vectorized", py::vectorize(f_simple_pass_thru));
|
516 |
+
|
517 |
+
// test_register_dtype
|
518 |
+
m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
|
519 |
+
|
520 |
+
// test_str_leak
|
521 |
+
m.def("dtype_wrapper", [](py::object d) { return py::dtype::from_args(std::move(d)); });
|
522 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_numpy_dtypes.py
ADDED
@@ -0,0 +1,434 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import re
|
3 |
+
|
4 |
+
import pytest
|
5 |
+
|
6 |
+
import env # noqa: F401
|
7 |
+
|
8 |
+
from pybind11_tests import numpy_dtypes as m
|
9 |
+
|
10 |
+
np = pytest.importorskip("numpy")
|
11 |
+
|
12 |
+
|
13 |
+
@pytest.fixture(scope="module")
|
14 |
+
def simple_dtype():
|
15 |
+
ld = np.dtype("longdouble")
|
16 |
+
return np.dtype(
|
17 |
+
{
|
18 |
+
"names": ["bool_", "uint_", "float_", "ldbl_"],
|
19 |
+
"formats": ["?", "u4", "f4", "f{}".format(ld.itemsize)],
|
20 |
+
"offsets": [0, 4, 8, (16 if ld.alignment > 4 else 12)],
|
21 |
+
}
|
22 |
+
)
|
23 |
+
|
24 |
+
|
25 |
+
@pytest.fixture(scope="module")
|
26 |
+
def packed_dtype():
|
27 |
+
return np.dtype([("bool_", "?"), ("uint_", "u4"), ("float_", "f4"), ("ldbl_", "g")])
|
28 |
+
|
29 |
+
|
30 |
+
def dt_fmt():
|
31 |
+
from sys import byteorder
|
32 |
+
|
33 |
+
e = "<" if byteorder == "little" else ">"
|
34 |
+
return (
|
35 |
+
"{{'names':['bool_','uint_','float_','ldbl_'],"
|
36 |
+
" 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}'],"
|
37 |
+
" 'offsets':[0,4,8,{}], 'itemsize':{}}}"
|
38 |
+
)
|
39 |
+
|
40 |
+
|
41 |
+
def simple_dtype_fmt():
|
42 |
+
ld = np.dtype("longdouble")
|
43 |
+
simple_ld_off = 12 + 4 * (ld.alignment > 4)
|
44 |
+
return dt_fmt().format(ld.itemsize, simple_ld_off, simple_ld_off + ld.itemsize)
|
45 |
+
|
46 |
+
|
47 |
+
def packed_dtype_fmt():
|
48 |
+
from sys import byteorder
|
49 |
+
|
50 |
+
return "[('bool_', '?'), ('uint_', '{e}u4'), ('float_', '{e}f4'), ('ldbl_', '{e}f{}')]".format(
|
51 |
+
np.dtype("longdouble").itemsize, e="<" if byteorder == "little" else ">"
|
52 |
+
)
|
53 |
+
|
54 |
+
|
55 |
+
def partial_ld_offset():
|
56 |
+
return (
|
57 |
+
12
|
58 |
+
+ 4 * (np.dtype("uint64").alignment > 4)
|
59 |
+
+ 8
|
60 |
+
+ 8 * (np.dtype("longdouble").alignment > 8)
|
61 |
+
)
|
62 |
+
|
63 |
+
|
64 |
+
def partial_dtype_fmt():
|
65 |
+
ld = np.dtype("longdouble")
|
66 |
+
partial_ld_off = partial_ld_offset()
|
67 |
+
return dt_fmt().format(ld.itemsize, partial_ld_off, partial_ld_off + ld.itemsize)
|
68 |
+
|
69 |
+
|
70 |
+
def partial_nested_fmt():
|
71 |
+
ld = np.dtype("longdouble")
|
72 |
+
partial_nested_off = 8 + 8 * (ld.alignment > 8)
|
73 |
+
partial_ld_off = partial_ld_offset()
|
74 |
+
partial_nested_size = partial_nested_off * 2 + partial_ld_off + ld.itemsize
|
75 |
+
return "{{'names':['a'], 'formats':[{}], 'offsets':[{}], 'itemsize':{}}}".format(
|
76 |
+
partial_dtype_fmt(), partial_nested_off, partial_nested_size
|
77 |
+
)
|
78 |
+
|
79 |
+
|
80 |
+
def assert_equal(actual, expected_data, expected_dtype):
|
81 |
+
np.testing.assert_equal(actual, np.array(expected_data, dtype=expected_dtype))
|
82 |
+
|
83 |
+
|
84 |
+
def test_format_descriptors():
|
85 |
+
with pytest.raises(RuntimeError) as excinfo:
|
86 |
+
m.get_format_unbound()
|
87 |
+
assert re.match(
|
88 |
+
"^NumPy type info missing for .*UnboundStruct.*$", str(excinfo.value)
|
89 |
+
)
|
90 |
+
|
91 |
+
ld = np.dtype("longdouble")
|
92 |
+
ldbl_fmt = ("4x" if ld.alignment > 4 else "") + ld.char
|
93 |
+
ss_fmt = "^T{?:bool_:3xI:uint_:f:float_:" + ldbl_fmt + ":ldbl_:}"
|
94 |
+
dbl = np.dtype("double")
|
95 |
+
partial_fmt = (
|
96 |
+
"^T{?:bool_:3xI:uint_:f:float_:"
|
97 |
+
+ str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8))
|
98 |
+
+ "xg:ldbl_:}"
|
99 |
+
)
|
100 |
+
nested_extra = str(max(8, ld.alignment))
|
101 |
+
assert m.print_format_descriptors() == [
|
102 |
+
ss_fmt,
|
103 |
+
"^T{?:bool_:I:uint_:f:float_:g:ldbl_:}",
|
104 |
+
"^T{" + ss_fmt + ":a:^T{?:bool_:I:uint_:f:float_:g:ldbl_:}:b:}",
|
105 |
+
partial_fmt,
|
106 |
+
"^T{" + nested_extra + "x" + partial_fmt + ":a:" + nested_extra + "x}",
|
107 |
+
"^T{3s:a:3s:b:}",
|
108 |
+
"^T{(3)4s:a:(2)i:b:(3)B:c:1x(4, 2)f:d:}",
|
109 |
+
"^T{q:e1:B:e2:}",
|
110 |
+
"^T{Zf:cflt:Zd:cdbl:}",
|
111 |
+
]
|
112 |
+
|
113 |
+
|
114 |
+
def test_dtype(simple_dtype):
|
115 |
+
from sys import byteorder
|
116 |
+
|
117 |
+
e = "<" if byteorder == "little" else ">"
|
118 |
+
|
119 |
+
assert m.print_dtypes() == [
|
120 |
+
simple_dtype_fmt(),
|
121 |
+
packed_dtype_fmt(),
|
122 |
+
"[('a', {}), ('b', {})]".format(simple_dtype_fmt(), packed_dtype_fmt()),
|
123 |
+
partial_dtype_fmt(),
|
124 |
+
partial_nested_fmt(),
|
125 |
+
"[('a', 'S3'), ('b', 'S3')]",
|
126 |
+
(
|
127 |
+
"{{'names':['a','b','c','d'], "
|
128 |
+
+ "'formats':[('S4', (3,)),('"
|
129 |
+
+ e
|
130 |
+
+ "i4', (2,)),('u1', (3,)),('"
|
131 |
+
+ e
|
132 |
+
+ "f4', (4, 2))], "
|
133 |
+
+ "'offsets':[0,12,20,24], 'itemsize':56}}"
|
134 |
+
).format(e=e),
|
135 |
+
"[('e1', '" + e + "i8'), ('e2', 'u1')]",
|
136 |
+
"[('x', 'i1'), ('y', '" + e + "u8')]",
|
137 |
+
"[('cflt', '" + e + "c8'), ('cdbl', '" + e + "c16')]",
|
138 |
+
]
|
139 |
+
|
140 |
+
d1 = np.dtype(
|
141 |
+
{
|
142 |
+
"names": ["a", "b"],
|
143 |
+
"formats": ["int32", "float64"],
|
144 |
+
"offsets": [1, 10],
|
145 |
+
"itemsize": 20,
|
146 |
+
}
|
147 |
+
)
|
148 |
+
d2 = np.dtype([("a", "i4"), ("b", "f4")])
|
149 |
+
assert m.test_dtype_ctors() == [
|
150 |
+
np.dtype("int32"),
|
151 |
+
np.dtype("float64"),
|
152 |
+
np.dtype("bool"),
|
153 |
+
d1,
|
154 |
+
d1,
|
155 |
+
np.dtype("uint32"),
|
156 |
+
d2,
|
157 |
+
]
|
158 |
+
|
159 |
+
assert m.test_dtype_methods() == [
|
160 |
+
np.dtype("int32"),
|
161 |
+
simple_dtype,
|
162 |
+
False,
|
163 |
+
True,
|
164 |
+
np.dtype("int32").itemsize,
|
165 |
+
simple_dtype.itemsize,
|
166 |
+
]
|
167 |
+
|
168 |
+
assert m.trailing_padding_dtype() == m.buffer_to_dtype(
|
169 |
+
np.zeros(1, m.trailing_padding_dtype())
|
170 |
+
)
|
171 |
+
|
172 |
+
assert m.test_dtype_kind() == list("iiiiiuuuuuffffcccbMmO")
|
173 |
+
assert m.test_dtype_char_() == list("bhilqBHILQefdgFDG?MmO")
|
174 |
+
|
175 |
+
|
176 |
+
def test_recarray(simple_dtype, packed_dtype):
|
177 |
+
elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)]
|
178 |
+
|
179 |
+
for func, dtype in [
|
180 |
+
(m.create_rec_simple, simple_dtype),
|
181 |
+
(m.create_rec_packed, packed_dtype),
|
182 |
+
]:
|
183 |
+
arr = func(0)
|
184 |
+
assert arr.dtype == dtype
|
185 |
+
assert_equal(arr, [], simple_dtype)
|
186 |
+
assert_equal(arr, [], packed_dtype)
|
187 |
+
|
188 |
+
arr = func(3)
|
189 |
+
assert arr.dtype == dtype
|
190 |
+
assert_equal(arr, elements, simple_dtype)
|
191 |
+
assert_equal(arr, elements, packed_dtype)
|
192 |
+
|
193 |
+
# Show what recarray's look like in NumPy.
|
194 |
+
assert type(arr[0]) == np.void
|
195 |
+
assert type(arr[0].item()) == tuple
|
196 |
+
|
197 |
+
if dtype == simple_dtype:
|
198 |
+
assert m.print_rec_simple(arr) == [
|
199 |
+
"s:0,0,0,-0",
|
200 |
+
"s:1,1,1.5,-2.5",
|
201 |
+
"s:0,2,3,-5",
|
202 |
+
]
|
203 |
+
else:
|
204 |
+
assert m.print_rec_packed(arr) == [
|
205 |
+
"p:0,0,0,-0",
|
206 |
+
"p:1,1,1.5,-2.5",
|
207 |
+
"p:0,2,3,-5",
|
208 |
+
]
|
209 |
+
|
210 |
+
nested_dtype = np.dtype([("a", simple_dtype), ("b", packed_dtype)])
|
211 |
+
|
212 |
+
arr = m.create_rec_nested(0)
|
213 |
+
assert arr.dtype == nested_dtype
|
214 |
+
assert_equal(arr, [], nested_dtype)
|
215 |
+
|
216 |
+
arr = m.create_rec_nested(3)
|
217 |
+
assert arr.dtype == nested_dtype
|
218 |
+
assert_equal(
|
219 |
+
arr,
|
220 |
+
[
|
221 |
+
((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)),
|
222 |
+
((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)),
|
223 |
+
((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5)),
|
224 |
+
],
|
225 |
+
nested_dtype,
|
226 |
+
)
|
227 |
+
assert m.print_rec_nested(arr) == [
|
228 |
+
"n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5",
|
229 |
+
"n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5",
|
230 |
+
"n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5",
|
231 |
+
]
|
232 |
+
|
233 |
+
arr = m.create_rec_partial(3)
|
234 |
+
assert str(arr.dtype) == partial_dtype_fmt()
|
235 |
+
partial_dtype = arr.dtype
|
236 |
+
assert "" not in arr.dtype.fields
|
237 |
+
assert partial_dtype.itemsize > simple_dtype.itemsize
|
238 |
+
assert_equal(arr, elements, simple_dtype)
|
239 |
+
assert_equal(arr, elements, packed_dtype)
|
240 |
+
|
241 |
+
arr = m.create_rec_partial_nested(3)
|
242 |
+
assert str(arr.dtype) == partial_nested_fmt()
|
243 |
+
assert "" not in arr.dtype.fields
|
244 |
+
assert "" not in arr.dtype.fields["a"][0].fields
|
245 |
+
assert arr.dtype.itemsize > partial_dtype.itemsize
|
246 |
+
np.testing.assert_equal(arr["a"], m.create_rec_partial(3))
|
247 |
+
|
248 |
+
|
249 |
+
def test_array_constructors():
|
250 |
+
data = np.arange(1, 7, dtype="int32")
|
251 |
+
for i in range(8):
|
252 |
+
np.testing.assert_array_equal(m.test_array_ctors(10 + i), data.reshape((3, 2)))
|
253 |
+
np.testing.assert_array_equal(m.test_array_ctors(20 + i), data.reshape((3, 2)))
|
254 |
+
for i in range(5):
|
255 |
+
np.testing.assert_array_equal(m.test_array_ctors(30 + i), data)
|
256 |
+
np.testing.assert_array_equal(m.test_array_ctors(40 + i), data)
|
257 |
+
|
258 |
+
|
259 |
+
def test_string_array():
|
260 |
+
arr = m.create_string_array(True)
|
261 |
+
assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]"
|
262 |
+
assert m.print_string_array(arr) == [
|
263 |
+
"a='',b=''",
|
264 |
+
"a='a',b='a'",
|
265 |
+
"a='ab',b='ab'",
|
266 |
+
"a='abc',b='abc'",
|
267 |
+
]
|
268 |
+
dtype = arr.dtype
|
269 |
+
assert arr["a"].tolist() == [b"", b"a", b"ab", b"abc"]
|
270 |
+
assert arr["b"].tolist() == [b"", b"a", b"ab", b"abc"]
|
271 |
+
arr = m.create_string_array(False)
|
272 |
+
assert dtype == arr.dtype
|
273 |
+
|
274 |
+
|
275 |
+
def test_array_array():
|
276 |
+
from sys import byteorder
|
277 |
+
|
278 |
+
e = "<" if byteorder == "little" else ">"
|
279 |
+
|
280 |
+
arr = m.create_array_array(3)
|
281 |
+
assert str(arr.dtype) == (
|
282 |
+
"{{'names':['a','b','c','d'], "
|
283 |
+
+ "'formats':[('S4', (3,)),('"
|
284 |
+
+ e
|
285 |
+
+ "i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], "
|
286 |
+
+ "'offsets':[0,12,20,24], 'itemsize':56}}"
|
287 |
+
).format(e=e)
|
288 |
+
assert m.print_array_array(arr) == [
|
289 |
+
"a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1},"
|
290 |
+
+ "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}",
|
291 |
+
"a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001},"
|
292 |
+
+ "c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}",
|
293 |
+
"a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001},"
|
294 |
+
+ "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}",
|
295 |
+
]
|
296 |
+
assert arr["a"].tolist() == [
|
297 |
+
[b"ABCD", b"KLMN", b"UVWX"],
|
298 |
+
[b"WXYZ", b"GHIJ", b"QRST"],
|
299 |
+
[b"STUV", b"CDEF", b"MNOP"],
|
300 |
+
]
|
301 |
+
assert arr["b"].tolist() == [[0, 1], [1000, 1001], [2000, 2001]]
|
302 |
+
assert m.create_array_array(0).dtype == arr.dtype
|
303 |
+
|
304 |
+
|
305 |
+
def test_enum_array():
|
306 |
+
from sys import byteorder
|
307 |
+
|
308 |
+
e = "<" if byteorder == "little" else ">"
|
309 |
+
|
310 |
+
arr = m.create_enum_array(3)
|
311 |
+
dtype = arr.dtype
|
312 |
+
assert dtype == np.dtype([("e1", e + "i8"), ("e2", "u1")])
|
313 |
+
assert m.print_enum_array(arr) == ["e1=A,e2=X", "e1=B,e2=Y", "e1=A,e2=X"]
|
314 |
+
assert arr["e1"].tolist() == [-1, 1, -1]
|
315 |
+
assert arr["e2"].tolist() == [1, 2, 1]
|
316 |
+
assert m.create_enum_array(0).dtype == dtype
|
317 |
+
|
318 |
+
|
319 |
+
def test_complex_array():
|
320 |
+
from sys import byteorder
|
321 |
+
|
322 |
+
e = "<" if byteorder == "little" else ">"
|
323 |
+
|
324 |
+
arr = m.create_complex_array(3)
|
325 |
+
dtype = arr.dtype
|
326 |
+
assert dtype == np.dtype([("cflt", e + "c8"), ("cdbl", e + "c16")])
|
327 |
+
assert m.print_complex_array(arr) == [
|
328 |
+
"c:(0,0.25),(0.5,0.75)",
|
329 |
+
"c:(1,1.25),(1.5,1.75)",
|
330 |
+
"c:(2,2.25),(2.5,2.75)",
|
331 |
+
]
|
332 |
+
assert arr["cflt"].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j]
|
333 |
+
assert arr["cdbl"].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j]
|
334 |
+
assert m.create_complex_array(0).dtype == dtype
|
335 |
+
|
336 |
+
|
337 |
+
def test_signature(doc):
|
338 |
+
assert (
|
339 |
+
doc(m.create_rec_nested)
|
340 |
+
== "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
|
341 |
+
)
|
342 |
+
|
343 |
+
|
344 |
+
def test_scalar_conversion():
|
345 |
+
n = 3
|
346 |
+
arrays = [
|
347 |
+
m.create_rec_simple(n),
|
348 |
+
m.create_rec_packed(n),
|
349 |
+
m.create_rec_nested(n),
|
350 |
+
m.create_enum_array(n),
|
351 |
+
]
|
352 |
+
funcs = [m.f_simple, m.f_packed, m.f_nested]
|
353 |
+
|
354 |
+
for i, func in enumerate(funcs):
|
355 |
+
for j, arr in enumerate(arrays):
|
356 |
+
if i == j and i < 2:
|
357 |
+
assert [func(arr[k]) for k in range(n)] == [k * 10 for k in range(n)]
|
358 |
+
else:
|
359 |
+
with pytest.raises(TypeError) as excinfo:
|
360 |
+
func(arr[0])
|
361 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
362 |
+
|
363 |
+
|
364 |
+
def test_vectorize():
|
365 |
+
n = 3
|
366 |
+
array = m.create_rec_simple(n)
|
367 |
+
values = m.f_simple_vectorized(array)
|
368 |
+
np.testing.assert_array_equal(values, [0, 10, 20])
|
369 |
+
array_2 = m.f_simple_pass_thru_vectorized(array)
|
370 |
+
np.testing.assert_array_equal(array, array_2)
|
371 |
+
|
372 |
+
|
373 |
+
def test_cls_and_dtype_conversion(simple_dtype):
|
374 |
+
s = m.SimpleStruct()
|
375 |
+
assert s.astuple() == (False, 0, 0.0, 0.0)
|
376 |
+
assert m.SimpleStruct.fromtuple(s.astuple()).astuple() == s.astuple()
|
377 |
+
|
378 |
+
s.uint_ = 2
|
379 |
+
assert m.f_simple(s) == 20
|
380 |
+
|
381 |
+
# Try as recarray of shape==(1,).
|
382 |
+
s_recarray = np.array([(False, 2, 0.0, 0.0)], dtype=simple_dtype)
|
383 |
+
# Show that this will work for vectorized case.
|
384 |
+
np.testing.assert_array_equal(m.f_simple_vectorized(s_recarray), [20])
|
385 |
+
|
386 |
+
# Show as a scalar that inherits from np.generic.
|
387 |
+
s_scalar = s_recarray[0]
|
388 |
+
assert isinstance(s_scalar, np.void)
|
389 |
+
assert m.f_simple(s_scalar) == 20
|
390 |
+
|
391 |
+
# Show that an *array* scalar (np.ndarray.shape == ()) does not convert.
|
392 |
+
# More specifically, conversion to SimpleStruct is not implicit.
|
393 |
+
s_recarray_scalar = s_recarray.reshape(())
|
394 |
+
assert isinstance(s_recarray_scalar, np.ndarray)
|
395 |
+
assert s_recarray_scalar.dtype == simple_dtype
|
396 |
+
with pytest.raises(TypeError) as excinfo:
|
397 |
+
m.f_simple(s_recarray_scalar)
|
398 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
399 |
+
# Explicitly convert to m.SimpleStruct.
|
400 |
+
assert m.f_simple(m.SimpleStruct.fromtuple(s_recarray_scalar.item())) == 20
|
401 |
+
|
402 |
+
# Show that an array of dtype=object does *not* convert.
|
403 |
+
s_array_object = np.array([s])
|
404 |
+
assert s_array_object.dtype == object
|
405 |
+
with pytest.raises(TypeError) as excinfo:
|
406 |
+
m.f_simple_vectorized(s_array_object)
|
407 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
408 |
+
# Explicitly convert to `np.array(..., dtype=simple_dtype)`
|
409 |
+
s_array = np.array([s.astuple()], dtype=simple_dtype)
|
410 |
+
np.testing.assert_array_equal(m.f_simple_vectorized(s_array), [20])
|
411 |
+
|
412 |
+
|
413 |
+
def test_register_dtype():
|
414 |
+
with pytest.raises(RuntimeError) as excinfo:
|
415 |
+
m.register_dtype()
|
416 |
+
assert "dtype is already registered" in str(excinfo.value)
|
417 |
+
|
418 |
+
|
419 |
+
@pytest.mark.xfail("env.PYPY")
|
420 |
+
def test_str_leak():
|
421 |
+
from sys import getrefcount
|
422 |
+
|
423 |
+
fmt = "f4"
|
424 |
+
pytest.gc_collect()
|
425 |
+
start = getrefcount(fmt)
|
426 |
+
d = m.dtype_wrapper(fmt)
|
427 |
+
assert d is np.dtype("f4")
|
428 |
+
del d
|
429 |
+
pytest.gc_collect()
|
430 |
+
assert getrefcount(fmt) == start
|
431 |
+
|
432 |
+
|
433 |
+
def test_compare_buffer_info():
|
434 |
+
assert all(m.compare_buffer_info())
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_numpy_vectorize.cpp
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_numpy_vectorize.cpp -- auto-vectorize functions over NumPy array
|
3 |
+
arguments
|
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 |
+
#include <pybind11/numpy.h>
|
13 |
+
|
14 |
+
#include <utility>
|
15 |
+
|
16 |
+
double my_func(int x, float y, double z) {
|
17 |
+
py::print("my_func(x:int={}, y:float={:.0f}, z:float={:.0f})"_s.format(x, y, z));
|
18 |
+
return (float) x*y*z;
|
19 |
+
}
|
20 |
+
|
21 |
+
TEST_SUBMODULE(numpy_vectorize, m) {
|
22 |
+
try { py::module_::import("numpy"); }
|
23 |
+
catch (...) { return; }
|
24 |
+
|
25 |
+
// test_vectorize, test_docs, test_array_collapse
|
26 |
+
// Vectorize all arguments of a function (though non-vector arguments are also allowed)
|
27 |
+
m.def("vectorized_func", py::vectorize(my_func));
|
28 |
+
|
29 |
+
// Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization)
|
30 |
+
m.def("vectorized_func2", [](py::array_t<int> x, py::array_t<float> y, float z) {
|
31 |
+
return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(std::move(x),
|
32 |
+
std::move(y));
|
33 |
+
});
|
34 |
+
|
35 |
+
// Vectorize a complex-valued function
|
36 |
+
m.def("vectorized_func3", py::vectorize(
|
37 |
+
[](std::complex<double> c) { return c * std::complex<double>(2.f); }
|
38 |
+
));
|
39 |
+
|
40 |
+
// test_type_selection
|
41 |
+
// NumPy function which only accepts specific data types
|
42 |
+
// A lot of these no lints could be replaced with const refs, and probably should at some point.
|
43 |
+
m.def("selective_func",
|
44 |
+
[](const py::array_t<int, py::array::c_style> &) { return "Int branch taken."; });
|
45 |
+
m.def("selective_func",
|
46 |
+
[](const py::array_t<float, py::array::c_style> &) { return "Float branch taken."; });
|
47 |
+
m.def("selective_func", [](const py::array_t<std::complex<float>, py::array::c_style> &) {
|
48 |
+
return "Complex float branch taken.";
|
49 |
+
});
|
50 |
+
|
51 |
+
// test_passthrough_arguments
|
52 |
+
// Passthrough test: references and non-pod types should be automatically passed through (in the
|
53 |
+
// function definition below, only `b`, `d`, and `g` are vectorized):
|
54 |
+
struct NonPODClass {
|
55 |
+
NonPODClass(int v) : value{v} {}
|
56 |
+
int value;
|
57 |
+
};
|
58 |
+
py::class_<NonPODClass>(m, "NonPODClass")
|
59 |
+
.def(py::init<int>())
|
60 |
+
.def_readwrite("value", &NonPODClass::value);
|
61 |
+
m.def("vec_passthrough",
|
62 |
+
py::vectorize([](const double *a,
|
63 |
+
double b,
|
64 |
+
// Changing this broke things
|
65 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
66 |
+
py::array_t<double> c,
|
67 |
+
const int &d,
|
68 |
+
int &e,
|
69 |
+
NonPODClass f,
|
70 |
+
const double g) { return *a + b + c.at(0) + d + e + f.value + g; }));
|
71 |
+
|
72 |
+
// test_method_vectorization
|
73 |
+
struct VectorizeTestClass {
|
74 |
+
VectorizeTestClass(int v) : value{v} {};
|
75 |
+
float method(int x, float y) const { return y + (float) (x + value); }
|
76 |
+
int value = 0;
|
77 |
+
};
|
78 |
+
py::class_<VectorizeTestClass> vtc(m, "VectorizeTestClass");
|
79 |
+
vtc .def(py::init<int>())
|
80 |
+
.def_readwrite("value", &VectorizeTestClass::value);
|
81 |
+
|
82 |
+
// Automatic vectorizing of methods
|
83 |
+
vtc.def("method", py::vectorize(&VectorizeTestClass::method));
|
84 |
+
|
85 |
+
// test_trivial_broadcasting
|
86 |
+
// Internal optimization test for whether the input is trivially broadcastable:
|
87 |
+
py::enum_<py::detail::broadcast_trivial>(m, "trivial")
|
88 |
+
.value("f_trivial", py::detail::broadcast_trivial::f_trivial)
|
89 |
+
.value("c_trivial", py::detail::broadcast_trivial::c_trivial)
|
90 |
+
.value("non_trivial", py::detail::broadcast_trivial::non_trivial);
|
91 |
+
m.def("vectorized_is_trivial",
|
92 |
+
[](const py::array_t<int, py::array::forcecast> &arg1,
|
93 |
+
const py::array_t<float, py::array::forcecast> &arg2,
|
94 |
+
const py::array_t<double, py::array::forcecast> &arg3) {
|
95 |
+
py::ssize_t ndim = 0;
|
96 |
+
std::vector<py::ssize_t> shape;
|
97 |
+
std::array<py::buffer_info, 3> buffers{
|
98 |
+
{arg1.request(), arg2.request(), arg3.request()}};
|
99 |
+
return py::detail::broadcast(buffers, ndim, shape);
|
100 |
+
});
|
101 |
+
|
102 |
+
m.def("add_to", py::vectorize([](NonPODClass& x, int a) { x.value += a; }));
|
103 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_numpy_vectorize.py
ADDED
@@ -0,0 +1,266 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
from pybind11_tests import numpy_vectorize as m
|
4 |
+
|
5 |
+
np = pytest.importorskip("numpy")
|
6 |
+
|
7 |
+
|
8 |
+
def test_vectorize(capture):
|
9 |
+
assert np.isclose(m.vectorized_func3(np.array(3 + 7j)), [6 + 14j])
|
10 |
+
|
11 |
+
for f in [m.vectorized_func, m.vectorized_func2]:
|
12 |
+
with capture:
|
13 |
+
assert np.isclose(f(1, 2, 3), 6)
|
14 |
+
assert capture == "my_func(x:int=1, y:float=2, z:float=3)"
|
15 |
+
with capture:
|
16 |
+
assert np.isclose(f(np.array(1), np.array(2), 3), 6)
|
17 |
+
assert capture == "my_func(x:int=1, y:float=2, z:float=3)"
|
18 |
+
with capture:
|
19 |
+
assert np.allclose(f(np.array([1, 3]), np.array([2, 4]), 3), [6, 36])
|
20 |
+
assert (
|
21 |
+
capture
|
22 |
+
== """
|
23 |
+
my_func(x:int=1, y:float=2, z:float=3)
|
24 |
+
my_func(x:int=3, y:float=4, z:float=3)
|
25 |
+
"""
|
26 |
+
)
|
27 |
+
with capture:
|
28 |
+
a = np.array([[1, 2], [3, 4]], order="F")
|
29 |
+
b = np.array([[10, 20], [30, 40]], order="F")
|
30 |
+
c = 3
|
31 |
+
result = f(a, b, c)
|
32 |
+
assert np.allclose(result, a * b * c)
|
33 |
+
assert result.flags.f_contiguous
|
34 |
+
# All inputs are F order and full or singletons, so we the result is in col-major order:
|
35 |
+
assert (
|
36 |
+
capture
|
37 |
+
== """
|
38 |
+
my_func(x:int=1, y:float=10, z:float=3)
|
39 |
+
my_func(x:int=3, y:float=30, z:float=3)
|
40 |
+
my_func(x:int=2, y:float=20, z:float=3)
|
41 |
+
my_func(x:int=4, y:float=40, z:float=3)
|
42 |
+
"""
|
43 |
+
)
|
44 |
+
with capture:
|
45 |
+
a, b, c = (
|
46 |
+
np.array([[1, 3, 5], [7, 9, 11]]),
|
47 |
+
np.array([[2, 4, 6], [8, 10, 12]]),
|
48 |
+
3,
|
49 |
+
)
|
50 |
+
assert np.allclose(f(a, b, c), a * b * c)
|
51 |
+
assert (
|
52 |
+
capture
|
53 |
+
== """
|
54 |
+
my_func(x:int=1, y:float=2, z:float=3)
|
55 |
+
my_func(x:int=3, y:float=4, z:float=3)
|
56 |
+
my_func(x:int=5, y:float=6, z:float=3)
|
57 |
+
my_func(x:int=7, y:float=8, z:float=3)
|
58 |
+
my_func(x:int=9, y:float=10, z:float=3)
|
59 |
+
my_func(x:int=11, y:float=12, z:float=3)
|
60 |
+
"""
|
61 |
+
)
|
62 |
+
with capture:
|
63 |
+
a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2
|
64 |
+
assert np.allclose(f(a, b, c), a * b * c)
|
65 |
+
assert (
|
66 |
+
capture
|
67 |
+
== """
|
68 |
+
my_func(x:int=1, y:float=2, z:float=2)
|
69 |
+
my_func(x:int=2, y:float=3, z:float=2)
|
70 |
+
my_func(x:int=3, y:float=4, z:float=2)
|
71 |
+
my_func(x:int=4, y:float=2, z:float=2)
|
72 |
+
my_func(x:int=5, y:float=3, z:float=2)
|
73 |
+
my_func(x:int=6, y:float=4, z:float=2)
|
74 |
+
"""
|
75 |
+
)
|
76 |
+
with capture:
|
77 |
+
a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2
|
78 |
+
assert np.allclose(f(a, b, c), a * b * c)
|
79 |
+
assert (
|
80 |
+
capture
|
81 |
+
== """
|
82 |
+
my_func(x:int=1, y:float=2, z:float=2)
|
83 |
+
my_func(x:int=2, y:float=2, z:float=2)
|
84 |
+
my_func(x:int=3, y:float=2, z:float=2)
|
85 |
+
my_func(x:int=4, y:float=3, z:float=2)
|
86 |
+
my_func(x:int=5, y:float=3, z:float=2)
|
87 |
+
my_func(x:int=6, y:float=3, z:float=2)
|
88 |
+
"""
|
89 |
+
)
|
90 |
+
with capture:
|
91 |
+
a, b, c = (
|
92 |
+
np.array([[1, 2, 3], [4, 5, 6]], order="F"),
|
93 |
+
np.array([[2], [3]]),
|
94 |
+
2,
|
95 |
+
)
|
96 |
+
assert np.allclose(f(a, b, c), a * b * c)
|
97 |
+
assert (
|
98 |
+
capture
|
99 |
+
== """
|
100 |
+
my_func(x:int=1, y:float=2, z:float=2)
|
101 |
+
my_func(x:int=2, y:float=2, z:float=2)
|
102 |
+
my_func(x:int=3, y:float=2, z:float=2)
|
103 |
+
my_func(x:int=4, y:float=3, z:float=2)
|
104 |
+
my_func(x:int=5, y:float=3, z:float=2)
|
105 |
+
my_func(x:int=6, y:float=3, z:float=2)
|
106 |
+
"""
|
107 |
+
)
|
108 |
+
with capture:
|
109 |
+
a, b, c = np.array([[1, 2, 3], [4, 5, 6]])[::, ::2], np.array([[2], [3]]), 2
|
110 |
+
assert np.allclose(f(a, b, c), a * b * c)
|
111 |
+
assert (
|
112 |
+
capture
|
113 |
+
== """
|
114 |
+
my_func(x:int=1, y:float=2, z:float=2)
|
115 |
+
my_func(x:int=3, y:float=2, z:float=2)
|
116 |
+
my_func(x:int=4, y:float=3, z:float=2)
|
117 |
+
my_func(x:int=6, y:float=3, z:float=2)
|
118 |
+
"""
|
119 |
+
)
|
120 |
+
with capture:
|
121 |
+
a, b, c = (
|
122 |
+
np.array([[1, 2, 3], [4, 5, 6]], order="F")[::, ::2],
|
123 |
+
np.array([[2], [3]]),
|
124 |
+
2,
|
125 |
+
)
|
126 |
+
assert np.allclose(f(a, b, c), a * b * c)
|
127 |
+
assert (
|
128 |
+
capture
|
129 |
+
== """
|
130 |
+
my_func(x:int=1, y:float=2, z:float=2)
|
131 |
+
my_func(x:int=3, y:float=2, z:float=2)
|
132 |
+
my_func(x:int=4, y:float=3, z:float=2)
|
133 |
+
my_func(x:int=6, y:float=3, z:float=2)
|
134 |
+
"""
|
135 |
+
)
|
136 |
+
|
137 |
+
|
138 |
+
def test_type_selection():
|
139 |
+
assert m.selective_func(np.array([1], dtype=np.int32)) == "Int branch taken."
|
140 |
+
assert m.selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken."
|
141 |
+
assert (
|
142 |
+
m.selective_func(np.array([1.0j], dtype=np.complex64))
|
143 |
+
== "Complex float branch taken."
|
144 |
+
)
|
145 |
+
|
146 |
+
|
147 |
+
def test_docs(doc):
|
148 |
+
assert (
|
149 |
+
doc(m.vectorized_func)
|
150 |
+
== """
|
151 |
+
vectorized_func(arg0: numpy.ndarray[numpy.int32], arg1: numpy.ndarray[numpy.float32], arg2: numpy.ndarray[numpy.float64]) -> object
|
152 |
+
""" # noqa: E501 line too long
|
153 |
+
)
|
154 |
+
|
155 |
+
|
156 |
+
def test_trivial_broadcasting():
|
157 |
+
trivial, vectorized_is_trivial = m.trivial, m.vectorized_is_trivial
|
158 |
+
|
159 |
+
assert vectorized_is_trivial(1, 2, 3) == trivial.c_trivial
|
160 |
+
assert vectorized_is_trivial(np.array(1), np.array(2), 3) == trivial.c_trivial
|
161 |
+
assert (
|
162 |
+
vectorized_is_trivial(np.array([1, 3]), np.array([2, 4]), 3)
|
163 |
+
== trivial.c_trivial
|
164 |
+
)
|
165 |
+
assert trivial.c_trivial == vectorized_is_trivial(
|
166 |
+
np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3
|
167 |
+
)
|
168 |
+
assert (
|
169 |
+
vectorized_is_trivial(np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2)
|
170 |
+
== trivial.non_trivial
|
171 |
+
)
|
172 |
+
assert (
|
173 |
+
vectorized_is_trivial(np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2)
|
174 |
+
== trivial.non_trivial
|
175 |
+
)
|
176 |
+
z1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype="int32")
|
177 |
+
z2 = np.array(z1, dtype="float32")
|
178 |
+
z3 = np.array(z1, dtype="float64")
|
179 |
+
assert vectorized_is_trivial(z1, z2, z3) == trivial.c_trivial
|
180 |
+
assert vectorized_is_trivial(1, z2, z3) == trivial.c_trivial
|
181 |
+
assert vectorized_is_trivial(z1, 1, z3) == trivial.c_trivial
|
182 |
+
assert vectorized_is_trivial(z1, z2, 1) == trivial.c_trivial
|
183 |
+
assert vectorized_is_trivial(z1[::2, ::2], 1, 1) == trivial.non_trivial
|
184 |
+
assert vectorized_is_trivial(1, 1, z1[::2, ::2]) == trivial.c_trivial
|
185 |
+
assert vectorized_is_trivial(1, 1, z3[::2, ::2]) == trivial.non_trivial
|
186 |
+
assert vectorized_is_trivial(z1, 1, z3[1::4, 1::4]) == trivial.c_trivial
|
187 |
+
|
188 |
+
y1 = np.array(z1, order="F")
|
189 |
+
y2 = np.array(y1)
|
190 |
+
y3 = np.array(y1)
|
191 |
+
assert vectorized_is_trivial(y1, y2, y3) == trivial.f_trivial
|
192 |
+
assert vectorized_is_trivial(y1, 1, 1) == trivial.f_trivial
|
193 |
+
assert vectorized_is_trivial(1, y2, 1) == trivial.f_trivial
|
194 |
+
assert vectorized_is_trivial(1, 1, y3) == trivial.f_trivial
|
195 |
+
assert vectorized_is_trivial(y1, z2, 1) == trivial.non_trivial
|
196 |
+
assert vectorized_is_trivial(z1[1::4, 1::4], y2, 1) == trivial.f_trivial
|
197 |
+
assert vectorized_is_trivial(y1[1::4, 1::4], z2, 1) == trivial.c_trivial
|
198 |
+
|
199 |
+
assert m.vectorized_func(z1, z2, z3).flags.c_contiguous
|
200 |
+
assert m.vectorized_func(y1, y2, y3).flags.f_contiguous
|
201 |
+
assert m.vectorized_func(z1, 1, 1).flags.c_contiguous
|
202 |
+
assert m.vectorized_func(1, y2, 1).flags.f_contiguous
|
203 |
+
assert m.vectorized_func(z1[1::4, 1::4], y2, 1).flags.f_contiguous
|
204 |
+
assert m.vectorized_func(y1[1::4, 1::4], z2, 1).flags.c_contiguous
|
205 |
+
|
206 |
+
|
207 |
+
def test_passthrough_arguments(doc):
|
208 |
+
assert doc(m.vec_passthrough) == (
|
209 |
+
"vec_passthrough("
|
210 |
+
+ ", ".join(
|
211 |
+
[
|
212 |
+
"arg0: float",
|
213 |
+
"arg1: numpy.ndarray[numpy.float64]",
|
214 |
+
"arg2: numpy.ndarray[numpy.float64]",
|
215 |
+
"arg3: numpy.ndarray[numpy.int32]",
|
216 |
+
"arg4: int",
|
217 |
+
"arg5: m.numpy_vectorize.NonPODClass",
|
218 |
+
"arg6: numpy.ndarray[numpy.float64]",
|
219 |
+
]
|
220 |
+
)
|
221 |
+
+ ") -> object"
|
222 |
+
)
|
223 |
+
|
224 |
+
b = np.array([[10, 20, 30]], dtype="float64")
|
225 |
+
c = np.array([100, 200]) # NOT a vectorized argument
|
226 |
+
d = np.array([[1000], [2000], [3000]], dtype="int")
|
227 |
+
g = np.array([[1000000, 2000000, 3000000]], dtype="int") # requires casting
|
228 |
+
assert np.all(
|
229 |
+
m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g)
|
230 |
+
== np.array(
|
231 |
+
[
|
232 |
+
[1111111, 2111121, 3111131],
|
233 |
+
[1112111, 2112121, 3112131],
|
234 |
+
[1113111, 2113121, 3113131],
|
235 |
+
]
|
236 |
+
)
|
237 |
+
)
|
238 |
+
|
239 |
+
|
240 |
+
def test_method_vectorization():
|
241 |
+
o = m.VectorizeTestClass(3)
|
242 |
+
x = np.array([1, 2], dtype="int")
|
243 |
+
y = np.array([[10], [20]], dtype="float32")
|
244 |
+
assert np.all(o.method(x, y) == [[14, 15], [24, 25]])
|
245 |
+
|
246 |
+
|
247 |
+
def test_array_collapse():
|
248 |
+
assert not isinstance(m.vectorized_func(1, 2, 3), np.ndarray)
|
249 |
+
assert not isinstance(m.vectorized_func(np.array(1), 2, 3), np.ndarray)
|
250 |
+
z = m.vectorized_func([1], 2, 3)
|
251 |
+
assert isinstance(z, np.ndarray)
|
252 |
+
assert z.shape == (1,)
|
253 |
+
z = m.vectorized_func(1, [[[2]]], 3)
|
254 |
+
assert isinstance(z, np.ndarray)
|
255 |
+
assert z.shape == (1, 1, 1)
|
256 |
+
|
257 |
+
|
258 |
+
def test_vectorized_noreturn():
|
259 |
+
x = m.NonPODClass(0)
|
260 |
+
assert x.value == 0
|
261 |
+
m.add_to(x, [1, 2, 3, 4])
|
262 |
+
assert x.value == 10
|
263 |
+
m.add_to(x, 1)
|
264 |
+
assert x.value == 11
|
265 |
+
m.add_to(x, [[1, 1], [2, 3]])
|
266 |
+
assert x.value == 18
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_opaque_types.cpp
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_opaque_types.cpp -- opaque types, passing void pointers
|
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 <pybind11/stl.h>
|
12 |
+
#include <vector>
|
13 |
+
|
14 |
+
// IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures
|
15 |
+
//
|
16 |
+
// This also deliberately doesn't use the below StringList type alias to test
|
17 |
+
// that MAKE_OPAQUE can handle a type containing a `,`. (The `std::allocator`
|
18 |
+
// bit is just the default `std::vector` allocator).
|
19 |
+
PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>);
|
20 |
+
|
21 |
+
using StringList = std::vector<std::string, std::allocator<std::string>>;
|
22 |
+
|
23 |
+
TEST_SUBMODULE(opaque_types, m) {
|
24 |
+
// test_string_list
|
25 |
+
py::class_<StringList>(m, "StringList")
|
26 |
+
.def(py::init<>())
|
27 |
+
.def("pop_back", &StringList::pop_back)
|
28 |
+
/* There are multiple versions of push_back(), etc. Select the right ones. */
|
29 |
+
.def("push_back", (void (StringList::*)(const std::string &)) &StringList::push_back)
|
30 |
+
.def("back", (std::string &(StringList::*)()) &StringList::back)
|
31 |
+
.def("__len__", [](const StringList &v) { return v.size(); })
|
32 |
+
.def("__iter__", [](StringList &v) {
|
33 |
+
return py::make_iterator(v.begin(), v.end());
|
34 |
+
}, py::keep_alive<0, 1>());
|
35 |
+
|
36 |
+
class ClassWithSTLVecProperty {
|
37 |
+
public:
|
38 |
+
StringList stringList;
|
39 |
+
};
|
40 |
+
py::class_<ClassWithSTLVecProperty>(m, "ClassWithSTLVecProperty")
|
41 |
+
.def(py::init<>())
|
42 |
+
.def_readwrite("stringList", &ClassWithSTLVecProperty::stringList);
|
43 |
+
|
44 |
+
m.def("print_opaque_list", [](const StringList &l) {
|
45 |
+
std::string ret = "Opaque list: [";
|
46 |
+
bool first = true;
|
47 |
+
for (const auto &entry : l) {
|
48 |
+
if (!first)
|
49 |
+
ret += ", ";
|
50 |
+
ret += entry;
|
51 |
+
first = false;
|
52 |
+
}
|
53 |
+
return ret + "]";
|
54 |
+
});
|
55 |
+
|
56 |
+
// test_pointers
|
57 |
+
m.def("return_void_ptr", []() { return (void *) 0x1234; });
|
58 |
+
m.def("get_void_ptr_value", [](void *ptr) { return reinterpret_cast<std::intptr_t>(ptr); });
|
59 |
+
m.def("return_null_str", []() { return (char *) nullptr; });
|
60 |
+
m.def("get_null_str_value", [](char *ptr) { return reinterpret_cast<std::intptr_t>(ptr); });
|
61 |
+
|
62 |
+
m.def("return_unique_ptr", []() -> std::unique_ptr<StringList> {
|
63 |
+
auto *result = new StringList();
|
64 |
+
result->push_back("some value");
|
65 |
+
return std::unique_ptr<StringList>(result);
|
66 |
+
});
|
67 |
+
|
68 |
+
// test unions
|
69 |
+
py::class_<IntFloat>(m, "IntFloat")
|
70 |
+
.def(py::init<>())
|
71 |
+
.def_readwrite("i", &IntFloat::i)
|
72 |
+
.def_readwrite("f", &IntFloat::f);
|
73 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_opaque_types.py
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
from pybind11_tests import opaque_types as m
|
4 |
+
from pybind11_tests import ConstructorStats, UserType
|
5 |
+
|
6 |
+
|
7 |
+
def test_string_list():
|
8 |
+
lst = m.StringList()
|
9 |
+
lst.push_back("Element 1")
|
10 |
+
lst.push_back("Element 2")
|
11 |
+
assert m.print_opaque_list(lst) == "Opaque list: [Element 1, Element 2]"
|
12 |
+
assert lst.back() == "Element 2"
|
13 |
+
|
14 |
+
for i, k in enumerate(lst, start=1):
|
15 |
+
assert k == "Element {}".format(i)
|
16 |
+
lst.pop_back()
|
17 |
+
assert m.print_opaque_list(lst) == "Opaque list: [Element 1]"
|
18 |
+
|
19 |
+
cvp = m.ClassWithSTLVecProperty()
|
20 |
+
assert m.print_opaque_list(cvp.stringList) == "Opaque list: []"
|
21 |
+
|
22 |
+
cvp.stringList = lst
|
23 |
+
cvp.stringList.push_back("Element 3")
|
24 |
+
assert m.print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]"
|
25 |
+
|
26 |
+
|
27 |
+
def test_pointers(msg):
|
28 |
+
living_before = ConstructorStats.get(UserType).alive()
|
29 |
+
assert m.get_void_ptr_value(m.return_void_ptr()) == 0x1234
|
30 |
+
assert m.get_void_ptr_value(UserType()) # Should also work for other C++ types
|
31 |
+
assert ConstructorStats.get(UserType).alive() == living_before
|
32 |
+
|
33 |
+
with pytest.raises(TypeError) as excinfo:
|
34 |
+
m.get_void_ptr_value([1, 2, 3]) # This should not work
|
35 |
+
assert (
|
36 |
+
msg(excinfo.value)
|
37 |
+
== """
|
38 |
+
get_void_ptr_value(): incompatible function arguments. The following argument types are supported:
|
39 |
+
1. (arg0: capsule) -> int
|
40 |
+
|
41 |
+
Invoked with: [1, 2, 3]
|
42 |
+
""" # noqa: E501 line too long
|
43 |
+
)
|
44 |
+
|
45 |
+
assert m.return_null_str() is None
|
46 |
+
assert m.get_null_str_value(m.return_null_str()) is not None
|
47 |
+
|
48 |
+
ptr = m.return_unique_ptr()
|
49 |
+
assert "StringList" in repr(ptr)
|
50 |
+
assert m.print_opaque_list(ptr) == "Opaque list: [some value]"
|
51 |
+
|
52 |
+
|
53 |
+
def test_unions():
|
54 |
+
int_float_union = m.IntFloat()
|
55 |
+
int_float_union.i = 42
|
56 |
+
assert int_float_union.i == 42
|
57 |
+
int_float_union.f = 3.0
|
58 |
+
assert int_float_union.f == 3.0
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_operator_overloading.cpp
ADDED
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_operator_overloading.cpp -- operator overloading
|
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/operators.h>
|
13 |
+
#include <functional>
|
14 |
+
|
15 |
+
class Vector2 {
|
16 |
+
public:
|
17 |
+
Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); }
|
18 |
+
Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); }
|
19 |
+
Vector2(Vector2 &&v) noexcept : x(v.x), y(v.y) {
|
20 |
+
print_move_created(this);
|
21 |
+
v.x = v.y = 0;
|
22 |
+
}
|
23 |
+
Vector2 &operator=(const Vector2 &v) { x = v.x; y = v.y; print_copy_assigned(this); return *this; }
|
24 |
+
Vector2 &operator=(Vector2 &&v) noexcept {
|
25 |
+
x = v.x;
|
26 |
+
y = v.y;
|
27 |
+
v.x = v.y = 0;
|
28 |
+
print_move_assigned(this);
|
29 |
+
return *this;
|
30 |
+
}
|
31 |
+
~Vector2() { print_destroyed(this); }
|
32 |
+
|
33 |
+
std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; }
|
34 |
+
|
35 |
+
Vector2 operator-() const { return Vector2(-x, -y); }
|
36 |
+
Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); }
|
37 |
+
Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); }
|
38 |
+
Vector2 operator-(float value) const { return Vector2(x - value, y - value); }
|
39 |
+
Vector2 operator+(float value) const { return Vector2(x + value, y + value); }
|
40 |
+
Vector2 operator*(float value) const { return Vector2(x * value, y * value); }
|
41 |
+
Vector2 operator/(float value) const { return Vector2(x / value, y / value); }
|
42 |
+
Vector2 operator*(const Vector2 &v) const { return Vector2(x * v.x, y * v.y); }
|
43 |
+
Vector2 operator/(const Vector2 &v) const { return Vector2(x / v.x, y / v.y); }
|
44 |
+
Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; }
|
45 |
+
Vector2& operator-=(const Vector2 &v) { x -= v.x; y -= v.y; return *this; }
|
46 |
+
Vector2& operator*=(float v) { x *= v; y *= v; return *this; }
|
47 |
+
Vector2& operator/=(float v) { x /= v; y /= v; return *this; }
|
48 |
+
Vector2& operator*=(const Vector2 &v) { x *= v.x; y *= v.y; return *this; }
|
49 |
+
Vector2& operator/=(const Vector2 &v) { x /= v.x; y /= v.y; return *this; }
|
50 |
+
|
51 |
+
friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); }
|
52 |
+
friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); }
|
53 |
+
friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); }
|
54 |
+
friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); }
|
55 |
+
|
56 |
+
bool operator==(const Vector2 &v) const {
|
57 |
+
return x == v.x && y == v.y;
|
58 |
+
}
|
59 |
+
bool operator!=(const Vector2 &v) const {
|
60 |
+
return x != v.x || y != v.y;
|
61 |
+
}
|
62 |
+
private:
|
63 |
+
float x, y;
|
64 |
+
};
|
65 |
+
|
66 |
+
class C1 { };
|
67 |
+
class C2 { };
|
68 |
+
|
69 |
+
int operator+(const C1 &, const C1 &) { return 11; }
|
70 |
+
int operator+(const C2 &, const C2 &) { return 22; }
|
71 |
+
int operator+(const C2 &, const C1 &) { return 21; }
|
72 |
+
int operator+(const C1 &, const C2 &) { return 12; }
|
73 |
+
|
74 |
+
// Note: Specializing explicit within `namespace std { ... }` is done due to a
|
75 |
+
// bug in GCC<7. If you are supporting compilers later than this, consider
|
76 |
+
// specializing `using template<> struct std::hash<...>` in the global
|
77 |
+
// namespace instead, per this recommendation:
|
78 |
+
// https://en.cppreference.com/w/cpp/language/extending_std#Adding_template_specializations
|
79 |
+
namespace std {
|
80 |
+
template<>
|
81 |
+
struct hash<Vector2> {
|
82 |
+
// Not a good hash function, but easy to test
|
83 |
+
size_t operator()(const Vector2 &) { return 4; }
|
84 |
+
};
|
85 |
+
} // namespace std
|
86 |
+
|
87 |
+
// Not a good abs function, but easy to test.
|
88 |
+
std::string abs(const Vector2&) {
|
89 |
+
return "abs(Vector2)";
|
90 |
+
}
|
91 |
+
|
92 |
+
// MSVC & Intel warns about unknown pragmas, and warnings are errors.
|
93 |
+
#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
|
94 |
+
#pragma GCC diagnostic push
|
95 |
+
// clang 7.0.0 and Apple LLVM 10.0.1 introduce `-Wself-assign-overloaded` to
|
96 |
+
// `-Wall`, which is used here for overloading (e.g. `py::self += py::self `).
|
97 |
+
// Here, we suppress the warning using `#pragma diagnostic`.
|
98 |
+
// Taken from: https://github.com/RobotLocomotion/drake/commit/aaf84b46
|
99 |
+
// TODO(eric): This could be resolved using a function / functor (e.g. `py::self()`).
|
100 |
+
#if defined(__APPLE__) && defined(__clang__)
|
101 |
+
#if (__clang_major__ >= 10)
|
102 |
+
#pragma GCC diagnostic ignored "-Wself-assign-overloaded"
|
103 |
+
#endif
|
104 |
+
#elif defined(__clang__)
|
105 |
+
#if (__clang_major__ >= 7)
|
106 |
+
#pragma GCC diagnostic ignored "-Wself-assign-overloaded"
|
107 |
+
#endif
|
108 |
+
#endif
|
109 |
+
#endif
|
110 |
+
|
111 |
+
TEST_SUBMODULE(operators, m) {
|
112 |
+
|
113 |
+
// test_operator_overloading
|
114 |
+
py::class_<Vector2>(m, "Vector2")
|
115 |
+
.def(py::init<float, float>())
|
116 |
+
.def(py::self + py::self)
|
117 |
+
.def(py::self + float())
|
118 |
+
.def(py::self - py::self)
|
119 |
+
.def(py::self - float())
|
120 |
+
.def(py::self * float())
|
121 |
+
.def(py::self / float())
|
122 |
+
.def(py::self * py::self)
|
123 |
+
.def(py::self / py::self)
|
124 |
+
.def(py::self += py::self)
|
125 |
+
.def(py::self -= py::self)
|
126 |
+
.def(py::self *= float())
|
127 |
+
.def(py::self /= float())
|
128 |
+
.def(py::self *= py::self)
|
129 |
+
.def(py::self /= py::self)
|
130 |
+
.def(float() + py::self)
|
131 |
+
.def(float() - py::self)
|
132 |
+
.def(float() * py::self)
|
133 |
+
.def(float() / py::self)
|
134 |
+
.def(-py::self)
|
135 |
+
.def("__str__", &Vector2::toString)
|
136 |
+
.def("__repr__", &Vector2::toString)
|
137 |
+
.def(py::self == py::self)
|
138 |
+
.def(py::self != py::self)
|
139 |
+
.def(py::hash(py::self))
|
140 |
+
// N.B. See warning about usage of `py::detail::abs(py::self)` in
|
141 |
+
// `operators.h`.
|
142 |
+
.def("__abs__", [](const Vector2& v) { return abs(v); })
|
143 |
+
;
|
144 |
+
|
145 |
+
m.attr("Vector") = m.attr("Vector2");
|
146 |
+
|
147 |
+
// test_operators_notimplemented
|
148 |
+
// #393: need to return NotSupported to ensure correct arithmetic operator behavior
|
149 |
+
py::class_<C1>(m, "C1")
|
150 |
+
.def(py::init<>())
|
151 |
+
.def(py::self + py::self);
|
152 |
+
|
153 |
+
py::class_<C2>(m, "C2")
|
154 |
+
.def(py::init<>())
|
155 |
+
.def(py::self + py::self)
|
156 |
+
.def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; })
|
157 |
+
.def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; });
|
158 |
+
|
159 |
+
// test_nested
|
160 |
+
// #328: first member in a class can't be used in operators
|
161 |
+
struct NestABase { int value = -2; };
|
162 |
+
py::class_<NestABase>(m, "NestABase")
|
163 |
+
.def(py::init<>())
|
164 |
+
.def_readwrite("value", &NestABase::value);
|
165 |
+
|
166 |
+
struct NestA : NestABase {
|
167 |
+
int value = 3;
|
168 |
+
NestA& operator+=(int i) { value += i; return *this; }
|
169 |
+
};
|
170 |
+
py::class_<NestA>(m, "NestA")
|
171 |
+
.def(py::init<>())
|
172 |
+
.def(py::self += int())
|
173 |
+
.def("as_base", [](NestA &a) -> NestABase& {
|
174 |
+
return (NestABase&) a;
|
175 |
+
}, py::return_value_policy::reference_internal);
|
176 |
+
m.def("get_NestA", [](const NestA &a) { return a.value; });
|
177 |
+
|
178 |
+
struct NestB {
|
179 |
+
NestA a;
|
180 |
+
int value = 4;
|
181 |
+
NestB& operator-=(int i) { value -= i; return *this; }
|
182 |
+
};
|
183 |
+
py::class_<NestB>(m, "NestB")
|
184 |
+
.def(py::init<>())
|
185 |
+
.def(py::self -= int())
|
186 |
+
.def_readwrite("a", &NestB::a);
|
187 |
+
m.def("get_NestB", [](const NestB &b) { return b.value; });
|
188 |
+
|
189 |
+
struct NestC {
|
190 |
+
NestB b;
|
191 |
+
int value = 5;
|
192 |
+
NestC& operator*=(int i) { value *= i; return *this; }
|
193 |
+
};
|
194 |
+
py::class_<NestC>(m, "NestC")
|
195 |
+
.def(py::init<>())
|
196 |
+
.def(py::self *= int())
|
197 |
+
.def_readwrite("b", &NestC::b);
|
198 |
+
m.def("get_NestC", [](const NestC &c) { return c.value; });
|
199 |
+
|
200 |
+
|
201 |
+
// test_overriding_eq_reset_hash
|
202 |
+
// #2191 Overriding __eq__ should set __hash__ to None
|
203 |
+
struct Comparable {
|
204 |
+
int value;
|
205 |
+
bool operator==(const Comparable& rhs) const {return value == rhs.value;}
|
206 |
+
};
|
207 |
+
|
208 |
+
struct Hashable : Comparable {
|
209 |
+
explicit Hashable(int value): Comparable{value}{};
|
210 |
+
size_t hash() const { return static_cast<size_t>(value); }
|
211 |
+
};
|
212 |
+
|
213 |
+
struct Hashable2 : Hashable {
|
214 |
+
using Hashable::Hashable;
|
215 |
+
};
|
216 |
+
|
217 |
+
py::class_<Comparable>(m, "Comparable")
|
218 |
+
.def(py::init<int>())
|
219 |
+
.def(py::self == py::self);
|
220 |
+
|
221 |
+
py::class_<Hashable>(m, "Hashable")
|
222 |
+
.def(py::init<int>())
|
223 |
+
.def(py::self == py::self)
|
224 |
+
.def("__hash__", &Hashable::hash);
|
225 |
+
|
226 |
+
// define __hash__ before __eq__
|
227 |
+
py::class_<Hashable2>(m, "Hashable2")
|
228 |
+
.def("__hash__", &Hashable::hash)
|
229 |
+
.def(py::init<int>())
|
230 |
+
.def(py::self == py::self);
|
231 |
+
}
|
232 |
+
|
233 |
+
#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
|
234 |
+
#pragma GCC diagnostic pop
|
235 |
+
#endif
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_operator_overloading.py
ADDED
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
from pybind11_tests import operators as m
|
4 |
+
from pybind11_tests import ConstructorStats
|
5 |
+
|
6 |
+
|
7 |
+
def test_operator_overloading():
|
8 |
+
v1 = m.Vector2(1, 2)
|
9 |
+
v2 = m.Vector(3, -1)
|
10 |
+
v3 = m.Vector2(1, 2) # Same value as v1, but different instance.
|
11 |
+
assert v1 is not v3
|
12 |
+
|
13 |
+
assert str(v1) == "[1.000000, 2.000000]"
|
14 |
+
assert str(v2) == "[3.000000, -1.000000]"
|
15 |
+
|
16 |
+
assert str(-v2) == "[-3.000000, 1.000000]"
|
17 |
+
|
18 |
+
assert str(v1 + v2) == "[4.000000, 1.000000]"
|
19 |
+
assert str(v1 - v2) == "[-2.000000, 3.000000]"
|
20 |
+
assert str(v1 - 8) == "[-7.000000, -6.000000]"
|
21 |
+
assert str(v1 + 8) == "[9.000000, 10.000000]"
|
22 |
+
assert str(v1 * 8) == "[8.000000, 16.000000]"
|
23 |
+
assert str(v1 / 8) == "[0.125000, 0.250000]"
|
24 |
+
assert str(8 - v1) == "[7.000000, 6.000000]"
|
25 |
+
assert str(8 + v1) == "[9.000000, 10.000000]"
|
26 |
+
assert str(8 * v1) == "[8.000000, 16.000000]"
|
27 |
+
assert str(8 / v1) == "[8.000000, 4.000000]"
|
28 |
+
assert str(v1 * v2) == "[3.000000, -2.000000]"
|
29 |
+
assert str(v2 / v1) == "[3.000000, -0.500000]"
|
30 |
+
|
31 |
+
assert v1 == v3
|
32 |
+
assert v1 != v2
|
33 |
+
assert hash(v1) == 4
|
34 |
+
# TODO(eric.cousineau): Make this work.
|
35 |
+
# assert abs(v1) == "abs(Vector2)"
|
36 |
+
|
37 |
+
v1 += 2 * v2
|
38 |
+
assert str(v1) == "[7.000000, 0.000000]"
|
39 |
+
v1 -= v2
|
40 |
+
assert str(v1) == "[4.000000, 1.000000]"
|
41 |
+
v1 *= 2
|
42 |
+
assert str(v1) == "[8.000000, 2.000000]"
|
43 |
+
v1 /= 16
|
44 |
+
assert str(v1) == "[0.500000, 0.125000]"
|
45 |
+
v1 *= v2
|
46 |
+
assert str(v1) == "[1.500000, -0.125000]"
|
47 |
+
v2 /= v1
|
48 |
+
assert str(v2) == "[2.000000, 8.000000]"
|
49 |
+
|
50 |
+
cstats = ConstructorStats.get(m.Vector2)
|
51 |
+
assert cstats.alive() == 3
|
52 |
+
del v1
|
53 |
+
assert cstats.alive() == 2
|
54 |
+
del v2
|
55 |
+
assert cstats.alive() == 1
|
56 |
+
del v3
|
57 |
+
assert cstats.alive() == 0
|
58 |
+
assert cstats.values() == [
|
59 |
+
"[1.000000, 2.000000]",
|
60 |
+
"[3.000000, -1.000000]",
|
61 |
+
"[1.000000, 2.000000]",
|
62 |
+
"[-3.000000, 1.000000]",
|
63 |
+
"[4.000000, 1.000000]",
|
64 |
+
"[-2.000000, 3.000000]",
|
65 |
+
"[-7.000000, -6.000000]",
|
66 |
+
"[9.000000, 10.000000]",
|
67 |
+
"[8.000000, 16.000000]",
|
68 |
+
"[0.125000, 0.250000]",
|
69 |
+
"[7.000000, 6.000000]",
|
70 |
+
"[9.000000, 10.000000]",
|
71 |
+
"[8.000000, 16.000000]",
|
72 |
+
"[8.000000, 4.000000]",
|
73 |
+
"[3.000000, -2.000000]",
|
74 |
+
"[3.000000, -0.500000]",
|
75 |
+
"[6.000000, -2.000000]",
|
76 |
+
]
|
77 |
+
assert cstats.default_constructions == 0
|
78 |
+
assert cstats.copy_constructions == 0
|
79 |
+
assert cstats.move_constructions >= 10
|
80 |
+
assert cstats.copy_assignments == 0
|
81 |
+
assert cstats.move_assignments == 0
|
82 |
+
|
83 |
+
|
84 |
+
def test_operators_notimplemented():
|
85 |
+
"""#393: need to return NotSupported to ensure correct arithmetic operator behavior"""
|
86 |
+
|
87 |
+
c1, c2 = m.C1(), m.C2()
|
88 |
+
assert c1 + c1 == 11
|
89 |
+
assert c2 + c2 == 22
|
90 |
+
assert c2 + c1 == 21
|
91 |
+
assert c1 + c2 == 12
|
92 |
+
|
93 |
+
|
94 |
+
def test_nested():
|
95 |
+
"""#328: first member in a class can't be used in operators"""
|
96 |
+
|
97 |
+
a = m.NestA()
|
98 |
+
b = m.NestB()
|
99 |
+
c = m.NestC()
|
100 |
+
|
101 |
+
a += 10
|
102 |
+
assert m.get_NestA(a) == 13
|
103 |
+
b.a += 100
|
104 |
+
assert m.get_NestA(b.a) == 103
|
105 |
+
c.b.a += 1000
|
106 |
+
assert m.get_NestA(c.b.a) == 1003
|
107 |
+
b -= 1
|
108 |
+
assert m.get_NestB(b) == 3
|
109 |
+
c.b -= 3
|
110 |
+
assert m.get_NestB(c.b) == 1
|
111 |
+
c *= 7
|
112 |
+
assert m.get_NestC(c) == 35
|
113 |
+
|
114 |
+
abase = a.as_base()
|
115 |
+
assert abase.value == -2
|
116 |
+
a.as_base().value += 44
|
117 |
+
assert abase.value == 42
|
118 |
+
assert c.b.a.as_base().value == -2
|
119 |
+
c.b.a.as_base().value += 44
|
120 |
+
assert c.b.a.as_base().value == 42
|
121 |
+
|
122 |
+
del c
|
123 |
+
pytest.gc_collect()
|
124 |
+
del a # Shouldn't delete while abase is still alive
|
125 |
+
pytest.gc_collect()
|
126 |
+
|
127 |
+
assert abase.value == 42
|
128 |
+
del abase, b
|
129 |
+
pytest.gc_collect()
|
130 |
+
|
131 |
+
|
132 |
+
def test_overriding_eq_reset_hash():
|
133 |
+
|
134 |
+
assert m.Comparable(15) is not m.Comparable(15)
|
135 |
+
assert m.Comparable(15) == m.Comparable(15)
|
136 |
+
|
137 |
+
with pytest.raises(TypeError):
|
138 |
+
hash(m.Comparable(15)) # TypeError: unhashable type: 'm.Comparable'
|
139 |
+
|
140 |
+
for hashable in (m.Hashable, m.Hashable2):
|
141 |
+
assert hashable(15) is not hashable(15)
|
142 |
+
assert hashable(15) == hashable(15)
|
143 |
+
|
144 |
+
assert hash(hashable(15)) == 15
|
145 |
+
assert hash(hashable(15)) == hash(hashable(15))
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_pickling.cpp
ADDED
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// clang-format off
|
2 |
+
/*
|
3 |
+
tests/test_pickling.cpp -- pickle support
|
4 |
+
|
5 |
+
Copyright (c) 2016 Wenzel Jakob <[email protected]>
|
6 |
+
Copyright (c) 2021 The Pybind Development Team.
|
7 |
+
|
8 |
+
All rights reserved. Use of this source code is governed by a
|
9 |
+
BSD-style license that can be found in the LICENSE file.
|
10 |
+
*/
|
11 |
+
|
12 |
+
#include "pybind11_tests.h"
|
13 |
+
|
14 |
+
// clang-format on
|
15 |
+
|
16 |
+
#include <memory>
|
17 |
+
#include <stdexcept>
|
18 |
+
#include <utility>
|
19 |
+
|
20 |
+
namespace exercise_trampoline {
|
21 |
+
|
22 |
+
struct SimpleBase {
|
23 |
+
int num = 0;
|
24 |
+
virtual ~SimpleBase() = default;
|
25 |
+
|
26 |
+
// For compatibility with old clang versions:
|
27 |
+
SimpleBase() = default;
|
28 |
+
SimpleBase(const SimpleBase &) = default;
|
29 |
+
};
|
30 |
+
|
31 |
+
struct SimpleBaseTrampoline : SimpleBase {};
|
32 |
+
|
33 |
+
struct SimpleCppDerived : SimpleBase {};
|
34 |
+
|
35 |
+
void wrap(py::module m) {
|
36 |
+
py::class_<SimpleBase, SimpleBaseTrampoline>(m, "SimpleBase")
|
37 |
+
.def(py::init<>())
|
38 |
+
.def_readwrite("num", &SimpleBase::num)
|
39 |
+
.def(py::pickle(
|
40 |
+
[](const py::object &self) {
|
41 |
+
py::dict d;
|
42 |
+
if (py::hasattr(self, "__dict__"))
|
43 |
+
d = self.attr("__dict__");
|
44 |
+
return py::make_tuple(self.attr("num"), d);
|
45 |
+
},
|
46 |
+
[](const py::tuple &t) {
|
47 |
+
if (t.size() != 2)
|
48 |
+
throw std::runtime_error("Invalid state!");
|
49 |
+
auto cpp_state = std::unique_ptr<SimpleBase>(new SimpleBaseTrampoline);
|
50 |
+
cpp_state->num = t[0].cast<int>();
|
51 |
+
auto py_state = t[1].cast<py::dict>();
|
52 |
+
return std::make_pair(std::move(cpp_state), py_state);
|
53 |
+
}));
|
54 |
+
|
55 |
+
m.def("make_SimpleCppDerivedAsBase",
|
56 |
+
[]() { return std::unique_ptr<SimpleBase>(new SimpleCppDerived); });
|
57 |
+
m.def("check_dynamic_cast_SimpleCppDerived", [](const SimpleBase *base_ptr) {
|
58 |
+
return dynamic_cast<const SimpleCppDerived *>(base_ptr) != nullptr;
|
59 |
+
});
|
60 |
+
}
|
61 |
+
|
62 |
+
} // namespace exercise_trampoline
|
63 |
+
|
64 |
+
// clang-format off
|
65 |
+
|
66 |
+
TEST_SUBMODULE(pickling, m) {
|
67 |
+
// test_roundtrip
|
68 |
+
class Pickleable {
|
69 |
+
public:
|
70 |
+
Pickleable(const std::string &value) : m_value(value) { }
|
71 |
+
const std::string &value() const { return m_value; }
|
72 |
+
|
73 |
+
void setExtra1(int extra1) { m_extra1 = extra1; }
|
74 |
+
void setExtra2(int extra2) { m_extra2 = extra2; }
|
75 |
+
int extra1() const { return m_extra1; }
|
76 |
+
int extra2() const { return m_extra2; }
|
77 |
+
private:
|
78 |
+
std::string m_value;
|
79 |
+
int m_extra1 = 0;
|
80 |
+
int m_extra2 = 0;
|
81 |
+
};
|
82 |
+
|
83 |
+
class PickleableNew : public Pickleable {
|
84 |
+
public:
|
85 |
+
using Pickleable::Pickleable;
|
86 |
+
};
|
87 |
+
|
88 |
+
py::class_<Pickleable> pyPickleable(m, "Pickleable");
|
89 |
+
pyPickleable
|
90 |
+
.def(py::init<std::string>())
|
91 |
+
.def("value", &Pickleable::value)
|
92 |
+
.def("extra1", &Pickleable::extra1)
|
93 |
+
.def("extra2", &Pickleable::extra2)
|
94 |
+
.def("setExtra1", &Pickleable::setExtra1)
|
95 |
+
.def("setExtra2", &Pickleable::setExtra2)
|
96 |
+
// For details on the methods below, refer to
|
97 |
+
// http://docs.python.org/3/library/pickle.html#pickling-class-instances
|
98 |
+
.def("__getstate__", [](const Pickleable &p) {
|
99 |
+
/* Return a tuple that fully encodes the state of the object */
|
100 |
+
return py::make_tuple(p.value(), p.extra1(), p.extra2());
|
101 |
+
});
|
102 |
+
ignoreOldStyleInitWarnings([&pyPickleable]() {
|
103 |
+
pyPickleable.def("__setstate__", [](Pickleable &p, const py::tuple &t) {
|
104 |
+
if (t.size() != 3)
|
105 |
+
throw std::runtime_error("Invalid state!");
|
106 |
+
/* Invoke the constructor (need to use in-place version) */
|
107 |
+
new (&p) Pickleable(t[0].cast<std::string>());
|
108 |
+
|
109 |
+
/* Assign any additional state */
|
110 |
+
p.setExtra1(t[1].cast<int>());
|
111 |
+
p.setExtra2(t[2].cast<int>());
|
112 |
+
});
|
113 |
+
});
|
114 |
+
|
115 |
+
py::class_<PickleableNew, Pickleable>(m, "PickleableNew")
|
116 |
+
.def(py::init<std::string>())
|
117 |
+
.def(py::pickle(
|
118 |
+
[](const PickleableNew &p) {
|
119 |
+
return py::make_tuple(p.value(), p.extra1(), p.extra2());
|
120 |
+
},
|
121 |
+
[](const py::tuple &t) {
|
122 |
+
if (t.size() != 3)
|
123 |
+
throw std::runtime_error("Invalid state!");
|
124 |
+
auto p = PickleableNew(t[0].cast<std::string>());
|
125 |
+
|
126 |
+
p.setExtra1(t[1].cast<int>());
|
127 |
+
p.setExtra2(t[2].cast<int>());
|
128 |
+
return p;
|
129 |
+
}));
|
130 |
+
|
131 |
+
#if !defined(PYPY_VERSION)
|
132 |
+
// test_roundtrip_with_dict
|
133 |
+
class PickleableWithDict {
|
134 |
+
public:
|
135 |
+
PickleableWithDict(const std::string &value) : value(value) { }
|
136 |
+
|
137 |
+
std::string value;
|
138 |
+
int extra;
|
139 |
+
};
|
140 |
+
|
141 |
+
class PickleableWithDictNew : public PickleableWithDict {
|
142 |
+
public:
|
143 |
+
using PickleableWithDict::PickleableWithDict;
|
144 |
+
};
|
145 |
+
|
146 |
+
py::class_<PickleableWithDict> pyPickleableWithDict(m, "PickleableWithDict", py::dynamic_attr());
|
147 |
+
pyPickleableWithDict.def(py::init<std::string>())
|
148 |
+
.def_readwrite("value", &PickleableWithDict::value)
|
149 |
+
.def_readwrite("extra", &PickleableWithDict::extra)
|
150 |
+
.def("__getstate__", [](const py::object &self) {
|
151 |
+
/* Also include __dict__ in state */
|
152 |
+
return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__"));
|
153 |
+
});
|
154 |
+
ignoreOldStyleInitWarnings([&pyPickleableWithDict]() {
|
155 |
+
pyPickleableWithDict.def("__setstate__", [](const py::object &self, const py::tuple &t) {
|
156 |
+
if (t.size() != 3)
|
157 |
+
throw std::runtime_error("Invalid state!");
|
158 |
+
/* Cast and construct */
|
159 |
+
auto &p = self.cast<PickleableWithDict &>();
|
160 |
+
new (&p) PickleableWithDict(t[0].cast<std::string>());
|
161 |
+
|
162 |
+
/* Assign C++ state */
|
163 |
+
p.extra = t[1].cast<int>();
|
164 |
+
|
165 |
+
/* Assign Python state */
|
166 |
+
self.attr("__dict__") = t[2];
|
167 |
+
});
|
168 |
+
});
|
169 |
+
|
170 |
+
py::class_<PickleableWithDictNew, PickleableWithDict>(m, "PickleableWithDictNew")
|
171 |
+
.def(py::init<std::string>())
|
172 |
+
.def(py::pickle(
|
173 |
+
[](const py::object &self) {
|
174 |
+
return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__"));
|
175 |
+
},
|
176 |
+
[](const py::tuple &t) {
|
177 |
+
if (t.size() != 3)
|
178 |
+
throw std::runtime_error("Invalid state!");
|
179 |
+
|
180 |
+
auto cpp_state = PickleableWithDictNew(t[0].cast<std::string>());
|
181 |
+
cpp_state.extra = t[1].cast<int>();
|
182 |
+
|
183 |
+
auto py_state = t[2].cast<py::dict>();
|
184 |
+
return std::make_pair(cpp_state, py_state);
|
185 |
+
}));
|
186 |
+
#endif
|
187 |
+
|
188 |
+
exercise_trampoline::wrap(m);
|
189 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_pickling.py
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
import env # noqa: F401
|
5 |
+
|
6 |
+
from pybind11_tests import pickling as m
|
7 |
+
|
8 |
+
try:
|
9 |
+
import cPickle as pickle # Use cPickle on Python 2.7
|
10 |
+
except ImportError:
|
11 |
+
import pickle
|
12 |
+
|
13 |
+
|
14 |
+
@pytest.mark.parametrize("cls_name", ["Pickleable", "PickleableNew"])
|
15 |
+
def test_roundtrip(cls_name):
|
16 |
+
cls = getattr(m, cls_name)
|
17 |
+
p = cls("test_value")
|
18 |
+
p.setExtra1(15)
|
19 |
+
p.setExtra2(48)
|
20 |
+
|
21 |
+
data = pickle.dumps(p, 2) # Must use pickle protocol >= 2
|
22 |
+
p2 = pickle.loads(data)
|
23 |
+
assert p2.value() == p.value()
|
24 |
+
assert p2.extra1() == p.extra1()
|
25 |
+
assert p2.extra2() == p.extra2()
|
26 |
+
|
27 |
+
|
28 |
+
@pytest.mark.xfail("env.PYPY")
|
29 |
+
@pytest.mark.parametrize("cls_name", ["PickleableWithDict", "PickleableWithDictNew"])
|
30 |
+
def test_roundtrip_with_dict(cls_name):
|
31 |
+
cls = getattr(m, cls_name)
|
32 |
+
p = cls("test_value")
|
33 |
+
p.extra = 15
|
34 |
+
p.dynamic = "Attribute"
|
35 |
+
|
36 |
+
data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL)
|
37 |
+
p2 = pickle.loads(data)
|
38 |
+
assert p2.value == p.value
|
39 |
+
assert p2.extra == p.extra
|
40 |
+
assert p2.dynamic == p.dynamic
|
41 |
+
|
42 |
+
|
43 |
+
def test_enum_pickle():
|
44 |
+
from pybind11_tests import enums as e
|
45 |
+
|
46 |
+
data = pickle.dumps(e.EOne, 2)
|
47 |
+
assert e.EOne == pickle.loads(data)
|
48 |
+
|
49 |
+
|
50 |
+
#
|
51 |
+
# exercise_trampoline
|
52 |
+
#
|
53 |
+
class SimplePyDerived(m.SimpleBase):
|
54 |
+
pass
|
55 |
+
|
56 |
+
|
57 |
+
def test_roundtrip_simple_py_derived():
|
58 |
+
p = SimplePyDerived()
|
59 |
+
p.num = 202
|
60 |
+
p.stored_in_dict = 303
|
61 |
+
data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL)
|
62 |
+
p2 = pickle.loads(data)
|
63 |
+
assert isinstance(p2, SimplePyDerived)
|
64 |
+
assert p2.num == 202
|
65 |
+
assert p2.stored_in_dict == 303
|
66 |
+
|
67 |
+
|
68 |
+
def test_roundtrip_simple_cpp_derived():
|
69 |
+
p = m.make_SimpleCppDerivedAsBase()
|
70 |
+
assert m.check_dynamic_cast_SimpleCppDerived(p)
|
71 |
+
p.num = 404
|
72 |
+
if not env.PYPY:
|
73 |
+
# To ensure that this unit test is not accidentally invalidated.
|
74 |
+
with pytest.raises(AttributeError):
|
75 |
+
# Mimics the `setstate` C++ implementation.
|
76 |
+
setattr(p, "__dict__", {}) # noqa: B010
|
77 |
+
data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL)
|
78 |
+
p2 = pickle.loads(data)
|
79 |
+
assert isinstance(p2, m.SimpleBase)
|
80 |
+
assert p2.num == 404
|
81 |
+
# Issue #3062: pickleable base C++ classes can incur object slicing
|
82 |
+
# if derived typeid is not registered with pybind11
|
83 |
+
assert not m.check_dynamic_cast_SimpleCppDerived(p2)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_pytypes.cpp
ADDED
@@ -0,0 +1,437 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_pytypes.cpp -- Python type casters
|
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 <utility>
|
11 |
+
|
12 |
+
#include "pybind11_tests.h"
|
13 |
+
|
14 |
+
|
15 |
+
TEST_SUBMODULE(pytypes, m) {
|
16 |
+
// test_int
|
17 |
+
m.def("get_int", []{return py::int_(0);});
|
18 |
+
// test_iterator
|
19 |
+
m.def("get_iterator", []{return py::iterator();});
|
20 |
+
// test_iterable
|
21 |
+
m.def("get_iterable", []{return py::iterable();});
|
22 |
+
// test_list
|
23 |
+
m.def("get_list", []() {
|
24 |
+
py::list list;
|
25 |
+
list.append("value");
|
26 |
+
py::print("Entry at position 0:", list[0]);
|
27 |
+
list[0] = py::str("overwritten");
|
28 |
+
list.insert(0, "inserted-0");
|
29 |
+
list.insert(2, "inserted-2");
|
30 |
+
return list;
|
31 |
+
});
|
32 |
+
m.def("print_list", [](const py::list &list) {
|
33 |
+
int index = 0;
|
34 |
+
for (auto item : list)
|
35 |
+
py::print("list item {}: {}"_s.format(index++, item));
|
36 |
+
});
|
37 |
+
// test_none
|
38 |
+
m.def("get_none", []{return py::none();});
|
39 |
+
m.def("print_none", [](const py::none &none) { py::print("none: {}"_s.format(none)); });
|
40 |
+
|
41 |
+
// test_set
|
42 |
+
m.def("get_set", []() {
|
43 |
+
py::set set;
|
44 |
+
set.add(py::str("key1"));
|
45 |
+
set.add("key2");
|
46 |
+
set.add(std::string("key3"));
|
47 |
+
return set;
|
48 |
+
});
|
49 |
+
m.def("print_set", [](const py::set &set) {
|
50 |
+
for (auto item : set)
|
51 |
+
py::print("key:", item);
|
52 |
+
});
|
53 |
+
m.def("set_contains",
|
54 |
+
[](const py::set &set, const py::object &key) { return set.contains(key); });
|
55 |
+
m.def("set_contains", [](const py::set &set, const char *key) { return set.contains(key); });
|
56 |
+
|
57 |
+
// test_dict
|
58 |
+
m.def("get_dict", []() { return py::dict("key"_a="value"); });
|
59 |
+
m.def("print_dict", [](const py::dict &dict) {
|
60 |
+
for (auto item : dict)
|
61 |
+
py::print("key: {}, value={}"_s.format(item.first, item.second));
|
62 |
+
});
|
63 |
+
m.def("dict_keyword_constructor", []() {
|
64 |
+
auto d1 = py::dict("x"_a=1, "y"_a=2);
|
65 |
+
auto d2 = py::dict("z"_a=3, **d1);
|
66 |
+
return d2;
|
67 |
+
});
|
68 |
+
m.def("dict_contains",
|
69 |
+
[](const py::dict &dict, py::object val) { return dict.contains(val); });
|
70 |
+
m.def("dict_contains",
|
71 |
+
[](const py::dict &dict, const char *val) { return dict.contains(val); });
|
72 |
+
|
73 |
+
// test_str
|
74 |
+
m.def("str_from_string", []() { return py::str(std::string("baz")); });
|
75 |
+
m.def("str_from_bytes", []() { return py::str(py::bytes("boo", 3)); });
|
76 |
+
m.def("str_from_object", [](const py::object& obj) { return py::str(obj); });
|
77 |
+
m.def("repr_from_object", [](const py::object& obj) { return py::repr(obj); });
|
78 |
+
m.def("str_from_handle", [](py::handle h) { return py::str(h); });
|
79 |
+
m.def("str_from_string_from_str", [](const py::str& obj) {
|
80 |
+
return py::str(static_cast<std::string>(obj));
|
81 |
+
});
|
82 |
+
|
83 |
+
m.def("str_format", []() {
|
84 |
+
auto s1 = "{} + {} = {}"_s.format(1, 2, 3);
|
85 |
+
auto s2 = "{a} + {b} = {c}"_s.format("a"_a=1, "b"_a=2, "c"_a=3);
|
86 |
+
return py::make_tuple(s1, s2);
|
87 |
+
});
|
88 |
+
|
89 |
+
// test_bytes
|
90 |
+
m.def("bytes_from_string", []() { return py::bytes(std::string("foo")); });
|
91 |
+
m.def("bytes_from_str", []() { return py::bytes(py::str("bar", 3)); });
|
92 |
+
|
93 |
+
// test bytearray
|
94 |
+
m.def("bytearray_from_string", []() { return py::bytearray(std::string("foo")); });
|
95 |
+
m.def("bytearray_size", []() { return py::bytearray("foo").size(); });
|
96 |
+
|
97 |
+
// test_capsule
|
98 |
+
m.def("return_capsule_with_destructor", []() {
|
99 |
+
py::print("creating capsule");
|
100 |
+
return py::capsule([]() {
|
101 |
+
py::print("destructing capsule");
|
102 |
+
});
|
103 |
+
});
|
104 |
+
|
105 |
+
m.def("return_capsule_with_destructor_2", []() {
|
106 |
+
py::print("creating capsule");
|
107 |
+
return py::capsule((void *) 1234, [](void *ptr) {
|
108 |
+
py::print("destructing capsule: {}"_s.format((size_t) ptr));
|
109 |
+
});
|
110 |
+
});
|
111 |
+
|
112 |
+
m.def("return_capsule_with_name_and_destructor", []() {
|
113 |
+
auto capsule = py::capsule((void *) 12345, "pointer type description", [](PyObject *ptr) {
|
114 |
+
if (ptr) {
|
115 |
+
auto name = PyCapsule_GetName(ptr);
|
116 |
+
py::print("destructing capsule ({}, '{}')"_s.format(
|
117 |
+
(size_t) PyCapsule_GetPointer(ptr, name), name
|
118 |
+
));
|
119 |
+
}
|
120 |
+
});
|
121 |
+
|
122 |
+
capsule.set_pointer((void *) 1234);
|
123 |
+
|
124 |
+
// Using get_pointer<T>()
|
125 |
+
void* contents1 = static_cast<void*>(capsule);
|
126 |
+
void* contents2 = capsule.get_pointer();
|
127 |
+
void* contents3 = capsule.get_pointer<void>();
|
128 |
+
|
129 |
+
auto result1 = reinterpret_cast<size_t>(contents1);
|
130 |
+
auto result2 = reinterpret_cast<size_t>(contents2);
|
131 |
+
auto result3 = reinterpret_cast<size_t>(contents3);
|
132 |
+
|
133 |
+
py::print("created capsule ({}, '{}')"_s.format(result1 & result2 & result3, capsule.name()));
|
134 |
+
return capsule;
|
135 |
+
});
|
136 |
+
|
137 |
+
// test_accessors
|
138 |
+
m.def("accessor_api", [](const py::object &o) {
|
139 |
+
auto d = py::dict();
|
140 |
+
|
141 |
+
d["basic_attr"] = o.attr("basic_attr");
|
142 |
+
|
143 |
+
auto l = py::list();
|
144 |
+
for (auto item : o.attr("begin_end")) {
|
145 |
+
l.append(item);
|
146 |
+
}
|
147 |
+
d["begin_end"] = l;
|
148 |
+
|
149 |
+
d["operator[object]"] = o.attr("d")["operator[object]"_s];
|
150 |
+
d["operator[char *]"] = o.attr("d")["operator[char *]"];
|
151 |
+
|
152 |
+
d["attr(object)"] = o.attr("sub").attr("attr_obj");
|
153 |
+
d["attr(char *)"] = o.attr("sub").attr("attr_char");
|
154 |
+
try {
|
155 |
+
o.attr("sub").attr("missing").ptr();
|
156 |
+
} catch (const py::error_already_set &) {
|
157 |
+
d["missing_attr_ptr"] = "raised"_s;
|
158 |
+
}
|
159 |
+
try {
|
160 |
+
o.attr("missing").attr("doesn't matter");
|
161 |
+
} catch (const py::error_already_set &) {
|
162 |
+
d["missing_attr_chain"] = "raised"_s;
|
163 |
+
}
|
164 |
+
|
165 |
+
d["is_none"] = o.attr("basic_attr").is_none();
|
166 |
+
|
167 |
+
d["operator()"] = o.attr("func")(1);
|
168 |
+
d["operator*"] = o.attr("func")(*o.attr("begin_end"));
|
169 |
+
|
170 |
+
// Test implicit conversion
|
171 |
+
py::list implicit_list = o.attr("begin_end");
|
172 |
+
d["implicit_list"] = implicit_list;
|
173 |
+
py::dict implicit_dict = o.attr("__dict__");
|
174 |
+
d["implicit_dict"] = implicit_dict;
|
175 |
+
|
176 |
+
return d;
|
177 |
+
});
|
178 |
+
|
179 |
+
m.def("tuple_accessor", [](const py::tuple &existing_t) {
|
180 |
+
try {
|
181 |
+
existing_t[0] = 1;
|
182 |
+
} catch (const py::error_already_set &) {
|
183 |
+
// --> Python system error
|
184 |
+
// Only new tuples (refcount == 1) are mutable
|
185 |
+
auto new_t = py::tuple(3);
|
186 |
+
for (size_t i = 0; i < new_t.size(); ++i) {
|
187 |
+
new_t[i] = i;
|
188 |
+
}
|
189 |
+
return new_t;
|
190 |
+
}
|
191 |
+
return py::tuple();
|
192 |
+
});
|
193 |
+
|
194 |
+
m.def("accessor_assignment", []() {
|
195 |
+
auto l = py::list(1);
|
196 |
+
l[0] = 0;
|
197 |
+
|
198 |
+
auto d = py::dict();
|
199 |
+
d["get"] = l[0];
|
200 |
+
auto var = l[0];
|
201 |
+
d["deferred_get"] = var;
|
202 |
+
l[0] = 1;
|
203 |
+
d["set"] = l[0];
|
204 |
+
var = 99; // this assignment should not overwrite l[0]
|
205 |
+
d["deferred_set"] = l[0];
|
206 |
+
d["var"] = var;
|
207 |
+
|
208 |
+
return d;
|
209 |
+
});
|
210 |
+
|
211 |
+
// test_constructors
|
212 |
+
m.def("default_constructors", []() {
|
213 |
+
return py::dict(
|
214 |
+
"bytes"_a=py::bytes(),
|
215 |
+
"bytearray"_a=py::bytearray(),
|
216 |
+
"str"_a=py::str(),
|
217 |
+
"bool"_a=py::bool_(),
|
218 |
+
"int"_a=py::int_(),
|
219 |
+
"float"_a=py::float_(),
|
220 |
+
"tuple"_a=py::tuple(),
|
221 |
+
"list"_a=py::list(),
|
222 |
+
"dict"_a=py::dict(),
|
223 |
+
"set"_a=py::set()
|
224 |
+
);
|
225 |
+
});
|
226 |
+
|
227 |
+
m.def("converting_constructors", [](const py::dict &d) {
|
228 |
+
return py::dict(
|
229 |
+
"bytes"_a=py::bytes(d["bytes"]),
|
230 |
+
"bytearray"_a=py::bytearray(d["bytearray"]),
|
231 |
+
"str"_a=py::str(d["str"]),
|
232 |
+
"bool"_a=py::bool_(d["bool"]),
|
233 |
+
"int"_a=py::int_(d["int"]),
|
234 |
+
"float"_a=py::float_(d["float"]),
|
235 |
+
"tuple"_a=py::tuple(d["tuple"]),
|
236 |
+
"list"_a=py::list(d["list"]),
|
237 |
+
"dict"_a=py::dict(d["dict"]),
|
238 |
+
"set"_a=py::set(d["set"]),
|
239 |
+
"memoryview"_a=py::memoryview(d["memoryview"])
|
240 |
+
);
|
241 |
+
});
|
242 |
+
|
243 |
+
m.def("cast_functions", [](const py::dict &d) {
|
244 |
+
// When converting between Python types, obj.cast<T>() should be the same as T(obj)
|
245 |
+
return py::dict(
|
246 |
+
"bytes"_a=d["bytes"].cast<py::bytes>(),
|
247 |
+
"bytearray"_a=d["bytearray"].cast<py::bytearray>(),
|
248 |
+
"str"_a=d["str"].cast<py::str>(),
|
249 |
+
"bool"_a=d["bool"].cast<py::bool_>(),
|
250 |
+
"int"_a=d["int"].cast<py::int_>(),
|
251 |
+
"float"_a=d["float"].cast<py::float_>(),
|
252 |
+
"tuple"_a=d["tuple"].cast<py::tuple>(),
|
253 |
+
"list"_a=d["list"].cast<py::list>(),
|
254 |
+
"dict"_a=d["dict"].cast<py::dict>(),
|
255 |
+
"set"_a=d["set"].cast<py::set>(),
|
256 |
+
"memoryview"_a=d["memoryview"].cast<py::memoryview>()
|
257 |
+
);
|
258 |
+
});
|
259 |
+
|
260 |
+
m.def("convert_to_pybind11_str", [](const py::object &o) { return py::str(o); });
|
261 |
+
|
262 |
+
m.def("nonconverting_constructor",
|
263 |
+
[](const std::string &type, py::object value, bool move) -> py::object {
|
264 |
+
if (type == "bytes") {
|
265 |
+
return move ? py::bytes(std::move(value)) : py::bytes(value);
|
266 |
+
}
|
267 |
+
if (type == "none") {
|
268 |
+
return move ? py::none(std::move(value)) : py::none(value);
|
269 |
+
}
|
270 |
+
if (type == "ellipsis") {
|
271 |
+
return move ? py::ellipsis(std::move(value)) : py::ellipsis(value);
|
272 |
+
}
|
273 |
+
if (type == "type") {
|
274 |
+
return move ? py::type(std::move(value)) : py::type(value);
|
275 |
+
}
|
276 |
+
throw std::runtime_error("Invalid type");
|
277 |
+
});
|
278 |
+
|
279 |
+
m.def("get_implicit_casting", []() {
|
280 |
+
py::dict d;
|
281 |
+
d["char*_i1"] = "abc";
|
282 |
+
const char *c2 = "abc";
|
283 |
+
d["char*_i2"] = c2;
|
284 |
+
d["char*_e"] = py::cast(c2);
|
285 |
+
d["char*_p"] = py::str(c2);
|
286 |
+
|
287 |
+
d["int_i1"] = 42;
|
288 |
+
int i = 42;
|
289 |
+
d["int_i2"] = i;
|
290 |
+
i++;
|
291 |
+
d["int_e"] = py::cast(i);
|
292 |
+
i++;
|
293 |
+
d["int_p"] = py::int_(i);
|
294 |
+
|
295 |
+
d["str_i1"] = std::string("str");
|
296 |
+
std::string s2("str1");
|
297 |
+
d["str_i2"] = s2;
|
298 |
+
s2[3] = '2';
|
299 |
+
d["str_e"] = py::cast(s2);
|
300 |
+
s2[3] = '3';
|
301 |
+
d["str_p"] = py::str(s2);
|
302 |
+
|
303 |
+
py::list l(2);
|
304 |
+
l[0] = 3;
|
305 |
+
l[1] = py::cast(6);
|
306 |
+
l.append(9);
|
307 |
+
l.append(py::cast(12));
|
308 |
+
l.append(py::int_(15));
|
309 |
+
|
310 |
+
return py::dict(
|
311 |
+
"d"_a=d,
|
312 |
+
"l"_a=l
|
313 |
+
);
|
314 |
+
});
|
315 |
+
|
316 |
+
// test_print
|
317 |
+
m.def("print_function", []() {
|
318 |
+
py::print("Hello, World!");
|
319 |
+
py::print(1, 2.0, "three", true, std::string("-- multiple args"));
|
320 |
+
auto args = py::make_tuple("and", "a", "custom", "separator");
|
321 |
+
py::print("*args", *args, "sep"_a="-");
|
322 |
+
py::print("no new line here", "end"_a=" -- ");
|
323 |
+
py::print("next print");
|
324 |
+
|
325 |
+
auto py_stderr = py::module_::import("sys").attr("stderr");
|
326 |
+
py::print("this goes to stderr", "file"_a=py_stderr);
|
327 |
+
|
328 |
+
py::print("flush", "flush"_a=true);
|
329 |
+
|
330 |
+
py::print("{a} + {b} = {c}"_s.format("a"_a="py::print", "b"_a="str.format", "c"_a="this"));
|
331 |
+
});
|
332 |
+
|
333 |
+
m.def("print_failure", []() { py::print(42, UnregisteredType()); });
|
334 |
+
|
335 |
+
m.def("hash_function", [](py::object obj) { return py::hash(std::move(obj)); });
|
336 |
+
|
337 |
+
m.def("test_number_protocol", [](const py::object &a, const py::object &b) {
|
338 |
+
py::list l;
|
339 |
+
l.append(a.equal(b));
|
340 |
+
l.append(a.not_equal(b));
|
341 |
+
l.append(a < b);
|
342 |
+
l.append(a <= b);
|
343 |
+
l.append(a > b);
|
344 |
+
l.append(a >= b);
|
345 |
+
l.append(a + b);
|
346 |
+
l.append(a - b);
|
347 |
+
l.append(a * b);
|
348 |
+
l.append(a / b);
|
349 |
+
l.append(a | b);
|
350 |
+
l.append(a & b);
|
351 |
+
l.append(a ^ b);
|
352 |
+
l.append(a >> b);
|
353 |
+
l.append(a << b);
|
354 |
+
return l;
|
355 |
+
});
|
356 |
+
|
357 |
+
m.def("test_list_slicing", [](const py::list &a) { return a[py::slice(0, -1, 2)]; });
|
358 |
+
|
359 |
+
// See #2361
|
360 |
+
m.def("issue2361_str_implicit_copy_none", []() {
|
361 |
+
py::str is_this_none = py::none();
|
362 |
+
return is_this_none;
|
363 |
+
});
|
364 |
+
m.def("issue2361_dict_implicit_copy_none", []() {
|
365 |
+
py::dict is_this_none = py::none();
|
366 |
+
return is_this_none;
|
367 |
+
});
|
368 |
+
|
369 |
+
m.def("test_memoryview_object", [](const py::buffer &b) { return py::memoryview(b); });
|
370 |
+
|
371 |
+
m.def("test_memoryview_buffer_info",
|
372 |
+
[](const py::buffer &b) { return py::memoryview(b.request()); });
|
373 |
+
|
374 |
+
m.def("test_memoryview_from_buffer", [](bool is_unsigned) {
|
375 |
+
static const int16_t si16[] = { 3, 1, 4, 1, 5 };
|
376 |
+
static const uint16_t ui16[] = { 2, 7, 1, 8 };
|
377 |
+
if (is_unsigned)
|
378 |
+
return py::memoryview::from_buffer(
|
379 |
+
ui16, { 4 }, { sizeof(uint16_t) });
|
380 |
+
return py::memoryview::from_buffer(si16, {5}, {sizeof(int16_t)});
|
381 |
+
});
|
382 |
+
|
383 |
+
m.def("test_memoryview_from_buffer_nativeformat", []() {
|
384 |
+
static const char* format = "@i";
|
385 |
+
static const int32_t arr[] = { 4, 7, 5 };
|
386 |
+
return py::memoryview::from_buffer(
|
387 |
+
arr, sizeof(int32_t), format, { 3 }, { sizeof(int32_t) });
|
388 |
+
});
|
389 |
+
|
390 |
+
m.def("test_memoryview_from_buffer_empty_shape", []() {
|
391 |
+
static const char* buf = "";
|
392 |
+
return py::memoryview::from_buffer(buf, 1, "B", { }, { });
|
393 |
+
});
|
394 |
+
|
395 |
+
m.def("test_memoryview_from_buffer_invalid_strides", []() {
|
396 |
+
static const char* buf = "\x02\x03\x04";
|
397 |
+
return py::memoryview::from_buffer(buf, 1, "B", { 3 }, { });
|
398 |
+
});
|
399 |
+
|
400 |
+
m.def("test_memoryview_from_buffer_nullptr", []() {
|
401 |
+
return py::memoryview::from_buffer(
|
402 |
+
static_cast<void*>(nullptr), 1, "B", { }, { });
|
403 |
+
});
|
404 |
+
|
405 |
+
#if PY_MAJOR_VERSION >= 3
|
406 |
+
m.def("test_memoryview_from_memory", []() {
|
407 |
+
const char* buf = "\xff\xe1\xab\x37";
|
408 |
+
return py::memoryview::from_memory(
|
409 |
+
buf, static_cast<py::ssize_t>(strlen(buf)));
|
410 |
+
});
|
411 |
+
#endif
|
412 |
+
|
413 |
+
// test_builtin_functions
|
414 |
+
m.def("get_len", [](py::handle h) { return py::len(h); });
|
415 |
+
|
416 |
+
#ifdef PYBIND11_STR_LEGACY_PERMISSIVE
|
417 |
+
m.attr("PYBIND11_STR_LEGACY_PERMISSIVE") = true;
|
418 |
+
#endif
|
419 |
+
|
420 |
+
m.def("isinstance_pybind11_bytes",
|
421 |
+
[](py::object o) { return py::isinstance<py::bytes>(std::move(o)); });
|
422 |
+
m.def("isinstance_pybind11_str",
|
423 |
+
[](py::object o) { return py::isinstance<py::str>(std::move(o)); });
|
424 |
+
|
425 |
+
m.def("pass_to_pybind11_bytes", [](py::bytes b) { return py::len(std::move(b)); });
|
426 |
+
m.def("pass_to_pybind11_str", [](py::str s) { return py::len(std::move(s)); });
|
427 |
+
m.def("pass_to_std_string", [](const std::string &s) { return s.size(); });
|
428 |
+
|
429 |
+
// test_weakref
|
430 |
+
m.def("weakref_from_handle",
|
431 |
+
[](py::handle h) { return py::weakref(h); });
|
432 |
+
m.def("weakref_from_handle_and_function",
|
433 |
+
[](py::handle h, py::function f) { return py::weakref(h, std::move(f)); });
|
434 |
+
m.def("weakref_from_object", [](const py::object &o) { return py::weakref(o); });
|
435 |
+
m.def("weakref_from_object_and_function",
|
436 |
+
[](py::object o, py::function f) { return py::weakref(std::move(o), std::move(f)); });
|
437 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_pytypes.py
ADDED
@@ -0,0 +1,591 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
from __future__ import division
|
3 |
+
import pytest
|
4 |
+
import sys
|
5 |
+
|
6 |
+
import env # noqa: F401
|
7 |
+
|
8 |
+
from pybind11_tests import pytypes as m
|
9 |
+
from pybind11_tests import debug_enabled
|
10 |
+
|
11 |
+
|
12 |
+
def test_int(doc):
|
13 |
+
assert doc(m.get_int) == "get_int() -> int"
|
14 |
+
|
15 |
+
|
16 |
+
def test_iterator(doc):
|
17 |
+
assert doc(m.get_iterator) == "get_iterator() -> Iterator"
|
18 |
+
|
19 |
+
|
20 |
+
def test_iterable(doc):
|
21 |
+
assert doc(m.get_iterable) == "get_iterable() -> Iterable"
|
22 |
+
|
23 |
+
|
24 |
+
def test_list(capture, doc):
|
25 |
+
with capture:
|
26 |
+
lst = m.get_list()
|
27 |
+
assert lst == ["inserted-0", "overwritten", "inserted-2"]
|
28 |
+
|
29 |
+
lst.append("value2")
|
30 |
+
m.print_list(lst)
|
31 |
+
assert (
|
32 |
+
capture.unordered
|
33 |
+
== """
|
34 |
+
Entry at position 0: value
|
35 |
+
list item 0: inserted-0
|
36 |
+
list item 1: overwritten
|
37 |
+
list item 2: inserted-2
|
38 |
+
list item 3: value2
|
39 |
+
"""
|
40 |
+
)
|
41 |
+
|
42 |
+
assert doc(m.get_list) == "get_list() -> list"
|
43 |
+
assert doc(m.print_list) == "print_list(arg0: list) -> None"
|
44 |
+
|
45 |
+
|
46 |
+
def test_none(capture, doc):
|
47 |
+
assert doc(m.get_none) == "get_none() -> None"
|
48 |
+
assert doc(m.print_none) == "print_none(arg0: None) -> None"
|
49 |
+
|
50 |
+
|
51 |
+
def test_set(capture, doc):
|
52 |
+
s = m.get_set()
|
53 |
+
assert s == {"key1", "key2", "key3"}
|
54 |
+
|
55 |
+
with capture:
|
56 |
+
s.add("key4")
|
57 |
+
m.print_set(s)
|
58 |
+
assert (
|
59 |
+
capture.unordered
|
60 |
+
== """
|
61 |
+
key: key1
|
62 |
+
key: key2
|
63 |
+
key: key3
|
64 |
+
key: key4
|
65 |
+
"""
|
66 |
+
)
|
67 |
+
|
68 |
+
assert not m.set_contains(set(), 42)
|
69 |
+
assert m.set_contains({42}, 42)
|
70 |
+
assert m.set_contains({"foo"}, "foo")
|
71 |
+
|
72 |
+
assert doc(m.get_list) == "get_list() -> list"
|
73 |
+
assert doc(m.print_list) == "print_list(arg0: list) -> None"
|
74 |
+
|
75 |
+
|
76 |
+
def test_dict(capture, doc):
|
77 |
+
d = m.get_dict()
|
78 |
+
assert d == {"key": "value"}
|
79 |
+
|
80 |
+
with capture:
|
81 |
+
d["key2"] = "value2"
|
82 |
+
m.print_dict(d)
|
83 |
+
assert (
|
84 |
+
capture.unordered
|
85 |
+
== """
|
86 |
+
key: key, value=value
|
87 |
+
key: key2, value=value2
|
88 |
+
"""
|
89 |
+
)
|
90 |
+
|
91 |
+
assert not m.dict_contains({}, 42)
|
92 |
+
assert m.dict_contains({42: None}, 42)
|
93 |
+
assert m.dict_contains({"foo": None}, "foo")
|
94 |
+
|
95 |
+
assert doc(m.get_dict) == "get_dict() -> dict"
|
96 |
+
assert doc(m.print_dict) == "print_dict(arg0: dict) -> None"
|
97 |
+
|
98 |
+
assert m.dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3}
|
99 |
+
|
100 |
+
|
101 |
+
def test_str(doc):
|
102 |
+
assert m.str_from_string().encode().decode() == "baz"
|
103 |
+
assert m.str_from_bytes().encode().decode() == "boo"
|
104 |
+
|
105 |
+
assert doc(m.str_from_bytes) == "str_from_bytes() -> str"
|
106 |
+
|
107 |
+
class A(object):
|
108 |
+
def __str__(self):
|
109 |
+
return "this is a str"
|
110 |
+
|
111 |
+
def __repr__(self):
|
112 |
+
return "this is a repr"
|
113 |
+
|
114 |
+
assert m.str_from_object(A()) == "this is a str"
|
115 |
+
assert m.repr_from_object(A()) == "this is a repr"
|
116 |
+
assert m.str_from_handle(A()) == "this is a str"
|
117 |
+
|
118 |
+
s1, s2 = m.str_format()
|
119 |
+
assert s1 == "1 + 2 = 3"
|
120 |
+
assert s1 == s2
|
121 |
+
|
122 |
+
malformed_utf8 = b"\x80"
|
123 |
+
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
124 |
+
assert m.str_from_object(malformed_utf8) is malformed_utf8
|
125 |
+
elif env.PY2:
|
126 |
+
with pytest.raises(UnicodeDecodeError):
|
127 |
+
m.str_from_object(malformed_utf8)
|
128 |
+
else:
|
129 |
+
assert m.str_from_object(malformed_utf8) == "b'\\x80'"
|
130 |
+
if env.PY2:
|
131 |
+
with pytest.raises(UnicodeDecodeError):
|
132 |
+
m.str_from_handle(malformed_utf8)
|
133 |
+
else:
|
134 |
+
assert m.str_from_handle(malformed_utf8) == "b'\\x80'"
|
135 |
+
|
136 |
+
assert m.str_from_string_from_str("this is a str") == "this is a str"
|
137 |
+
ucs_surrogates_str = u"\udcc3"
|
138 |
+
if env.PY2:
|
139 |
+
assert u"\udcc3" == m.str_from_string_from_str(ucs_surrogates_str)
|
140 |
+
else:
|
141 |
+
with pytest.raises(UnicodeEncodeError):
|
142 |
+
m.str_from_string_from_str(ucs_surrogates_str)
|
143 |
+
|
144 |
+
|
145 |
+
def test_bytes(doc):
|
146 |
+
assert m.bytes_from_string().decode() == "foo"
|
147 |
+
assert m.bytes_from_str().decode() == "bar"
|
148 |
+
|
149 |
+
assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format(
|
150 |
+
"str" if env.PY2 else "bytes"
|
151 |
+
)
|
152 |
+
|
153 |
+
|
154 |
+
def test_bytearray(doc):
|
155 |
+
assert m.bytearray_from_string().decode() == "foo"
|
156 |
+
assert m.bytearray_size() == len("foo")
|
157 |
+
|
158 |
+
|
159 |
+
def test_capsule(capture):
|
160 |
+
pytest.gc_collect()
|
161 |
+
with capture:
|
162 |
+
a = m.return_capsule_with_destructor()
|
163 |
+
del a
|
164 |
+
pytest.gc_collect()
|
165 |
+
assert (
|
166 |
+
capture.unordered
|
167 |
+
== """
|
168 |
+
creating capsule
|
169 |
+
destructing capsule
|
170 |
+
"""
|
171 |
+
)
|
172 |
+
|
173 |
+
with capture:
|
174 |
+
a = m.return_capsule_with_destructor_2()
|
175 |
+
del a
|
176 |
+
pytest.gc_collect()
|
177 |
+
assert (
|
178 |
+
capture.unordered
|
179 |
+
== """
|
180 |
+
creating capsule
|
181 |
+
destructing capsule: 1234
|
182 |
+
"""
|
183 |
+
)
|
184 |
+
|
185 |
+
with capture:
|
186 |
+
a = m.return_capsule_with_name_and_destructor()
|
187 |
+
del a
|
188 |
+
pytest.gc_collect()
|
189 |
+
assert (
|
190 |
+
capture.unordered
|
191 |
+
== """
|
192 |
+
created capsule (1234, 'pointer type description')
|
193 |
+
destructing capsule (1234, 'pointer type description')
|
194 |
+
"""
|
195 |
+
)
|
196 |
+
|
197 |
+
|
198 |
+
def test_accessors():
|
199 |
+
class SubTestObject:
|
200 |
+
attr_obj = 1
|
201 |
+
attr_char = 2
|
202 |
+
|
203 |
+
class TestObject:
|
204 |
+
basic_attr = 1
|
205 |
+
begin_end = [1, 2, 3]
|
206 |
+
d = {"operator[object]": 1, "operator[char *]": 2}
|
207 |
+
sub = SubTestObject()
|
208 |
+
|
209 |
+
def func(self, x, *args):
|
210 |
+
return self.basic_attr + x + sum(args)
|
211 |
+
|
212 |
+
d = m.accessor_api(TestObject())
|
213 |
+
assert d["basic_attr"] == 1
|
214 |
+
assert d["begin_end"] == [1, 2, 3]
|
215 |
+
assert d["operator[object]"] == 1
|
216 |
+
assert d["operator[char *]"] == 2
|
217 |
+
assert d["attr(object)"] == 1
|
218 |
+
assert d["attr(char *)"] == 2
|
219 |
+
assert d["missing_attr_ptr"] == "raised"
|
220 |
+
assert d["missing_attr_chain"] == "raised"
|
221 |
+
assert d["is_none"] is False
|
222 |
+
assert d["operator()"] == 2
|
223 |
+
assert d["operator*"] == 7
|
224 |
+
assert d["implicit_list"] == [1, 2, 3]
|
225 |
+
assert all(x in TestObject.__dict__ for x in d["implicit_dict"])
|
226 |
+
|
227 |
+
assert m.tuple_accessor(tuple()) == (0, 1, 2)
|
228 |
+
|
229 |
+
d = m.accessor_assignment()
|
230 |
+
assert d["get"] == 0
|
231 |
+
assert d["deferred_get"] == 0
|
232 |
+
assert d["set"] == 1
|
233 |
+
assert d["deferred_set"] == 1
|
234 |
+
assert d["var"] == 99
|
235 |
+
|
236 |
+
|
237 |
+
def test_constructors():
|
238 |
+
"""C++ default and converting constructors are equivalent to type calls in Python"""
|
239 |
+
types = [bytes, bytearray, str, bool, int, float, tuple, list, dict, set]
|
240 |
+
expected = {t.__name__: t() for t in types}
|
241 |
+
if env.PY2:
|
242 |
+
# Note that bytes.__name__ == 'str' in Python 2.
|
243 |
+
# pybind11::str is unicode even under Python 2.
|
244 |
+
expected["bytes"] = bytes()
|
245 |
+
expected["str"] = unicode() # noqa: F821
|
246 |
+
assert m.default_constructors() == expected
|
247 |
+
|
248 |
+
data = {
|
249 |
+
bytes: b"41", # Currently no supported or working conversions.
|
250 |
+
bytearray: bytearray(b"41"),
|
251 |
+
str: 42,
|
252 |
+
bool: "Not empty",
|
253 |
+
int: "42",
|
254 |
+
float: "+1e3",
|
255 |
+
tuple: range(3),
|
256 |
+
list: range(3),
|
257 |
+
dict: [("two", 2), ("one", 1), ("three", 3)],
|
258 |
+
set: [4, 4, 5, 6, 6, 6],
|
259 |
+
memoryview: b"abc",
|
260 |
+
}
|
261 |
+
inputs = {k.__name__: v for k, v in data.items()}
|
262 |
+
expected = {k.__name__: k(v) for k, v in data.items()}
|
263 |
+
if env.PY2: # Similar to the above. See comments above.
|
264 |
+
inputs["bytes"] = b"41"
|
265 |
+
inputs["str"] = 42
|
266 |
+
expected["bytes"] = b"41"
|
267 |
+
expected["str"] = u"42"
|
268 |
+
|
269 |
+
assert m.converting_constructors(inputs) == expected
|
270 |
+
assert m.cast_functions(inputs) == expected
|
271 |
+
|
272 |
+
# Converting constructors and cast functions should just reference rather
|
273 |
+
# than copy when no conversion is needed:
|
274 |
+
noconv1 = m.converting_constructors(expected)
|
275 |
+
for k in noconv1:
|
276 |
+
assert noconv1[k] is expected[k]
|
277 |
+
|
278 |
+
noconv2 = m.cast_functions(expected)
|
279 |
+
for k in noconv2:
|
280 |
+
assert noconv2[k] is expected[k]
|
281 |
+
|
282 |
+
|
283 |
+
def test_non_converting_constructors():
|
284 |
+
non_converting_test_cases = [
|
285 |
+
("bytes", range(10)),
|
286 |
+
("none", 42),
|
287 |
+
("ellipsis", 42),
|
288 |
+
("type", 42),
|
289 |
+
]
|
290 |
+
for t, v in non_converting_test_cases:
|
291 |
+
for move in [True, False]:
|
292 |
+
with pytest.raises(TypeError) as excinfo:
|
293 |
+
m.nonconverting_constructor(t, v, move)
|
294 |
+
expected_error = "Object of type '{}' is not an instance of '{}'".format(
|
295 |
+
type(v).__name__, t
|
296 |
+
)
|
297 |
+
assert str(excinfo.value) == expected_error
|
298 |
+
|
299 |
+
|
300 |
+
def test_pybind11_str_raw_str():
|
301 |
+
# specifically to exercise pybind11::str::raw_str
|
302 |
+
cvt = m.convert_to_pybind11_str
|
303 |
+
assert cvt(u"Str") == u"Str"
|
304 |
+
assert cvt(b"Bytes") == u"Bytes" if env.PY2 else "b'Bytes'"
|
305 |
+
assert cvt(None) == u"None"
|
306 |
+
assert cvt(False) == u"False"
|
307 |
+
assert cvt(True) == u"True"
|
308 |
+
assert cvt(42) == u"42"
|
309 |
+
assert cvt(2 ** 65) == u"36893488147419103232"
|
310 |
+
assert cvt(-1.50) == u"-1.5"
|
311 |
+
assert cvt(()) == u"()"
|
312 |
+
assert cvt((18,)) == u"(18,)"
|
313 |
+
assert cvt([]) == u"[]"
|
314 |
+
assert cvt([28]) == u"[28]"
|
315 |
+
assert cvt({}) == u"{}"
|
316 |
+
assert cvt({3: 4}) == u"{3: 4}"
|
317 |
+
assert cvt(set()) == u"set([])" if env.PY2 else "set()"
|
318 |
+
assert cvt({3, 3}) == u"set([3])" if env.PY2 else "{3}"
|
319 |
+
|
320 |
+
valid_orig = u"DZ"
|
321 |
+
valid_utf8 = valid_orig.encode("utf-8")
|
322 |
+
valid_cvt = cvt(valid_utf8)
|
323 |
+
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
324 |
+
assert valid_cvt is valid_utf8
|
325 |
+
else:
|
326 |
+
assert type(valid_cvt) is unicode if env.PY2 else str # noqa: F821
|
327 |
+
if env.PY2:
|
328 |
+
assert valid_cvt == valid_orig
|
329 |
+
else:
|
330 |
+
assert valid_cvt == "b'\\xc7\\xb1'"
|
331 |
+
|
332 |
+
malformed_utf8 = b"\x80"
|
333 |
+
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
334 |
+
assert cvt(malformed_utf8) is malformed_utf8
|
335 |
+
else:
|
336 |
+
if env.PY2:
|
337 |
+
with pytest.raises(UnicodeDecodeError):
|
338 |
+
cvt(malformed_utf8)
|
339 |
+
else:
|
340 |
+
malformed_cvt = cvt(malformed_utf8)
|
341 |
+
assert type(malformed_cvt) is str
|
342 |
+
assert malformed_cvt == "b'\\x80'"
|
343 |
+
|
344 |
+
|
345 |
+
def test_implicit_casting():
|
346 |
+
"""Tests implicit casting when assigning or appending to dicts and lists."""
|
347 |
+
z = m.get_implicit_casting()
|
348 |
+
assert z["d"] == {
|
349 |
+
"char*_i1": "abc",
|
350 |
+
"char*_i2": "abc",
|
351 |
+
"char*_e": "abc",
|
352 |
+
"char*_p": "abc",
|
353 |
+
"str_i1": "str",
|
354 |
+
"str_i2": "str1",
|
355 |
+
"str_e": "str2",
|
356 |
+
"str_p": "str3",
|
357 |
+
"int_i1": 42,
|
358 |
+
"int_i2": 42,
|
359 |
+
"int_e": 43,
|
360 |
+
"int_p": 44,
|
361 |
+
}
|
362 |
+
assert z["l"] == [3, 6, 9, 12, 15]
|
363 |
+
|
364 |
+
|
365 |
+
def test_print(capture):
|
366 |
+
with capture:
|
367 |
+
m.print_function()
|
368 |
+
assert (
|
369 |
+
capture
|
370 |
+
== """
|
371 |
+
Hello, World!
|
372 |
+
1 2.0 three True -- multiple args
|
373 |
+
*args-and-a-custom-separator
|
374 |
+
no new line here -- next print
|
375 |
+
flush
|
376 |
+
py::print + str.format = this
|
377 |
+
"""
|
378 |
+
)
|
379 |
+
assert capture.stderr == "this goes to stderr"
|
380 |
+
|
381 |
+
with pytest.raises(RuntimeError) as excinfo:
|
382 |
+
m.print_failure()
|
383 |
+
assert str(excinfo.value) == "Unable to convert call argument " + (
|
384 |
+
"'1' of type 'UnregisteredType' to Python object"
|
385 |
+
if debug_enabled
|
386 |
+
else "to Python object (compile in debug mode for details)"
|
387 |
+
)
|
388 |
+
|
389 |
+
|
390 |
+
def test_hash():
|
391 |
+
class Hashable(object):
|
392 |
+
def __init__(self, value):
|
393 |
+
self.value = value
|
394 |
+
|
395 |
+
def __hash__(self):
|
396 |
+
return self.value
|
397 |
+
|
398 |
+
class Unhashable(object):
|
399 |
+
__hash__ = None
|
400 |
+
|
401 |
+
assert m.hash_function(Hashable(42)) == 42
|
402 |
+
with pytest.raises(TypeError):
|
403 |
+
m.hash_function(Unhashable())
|
404 |
+
|
405 |
+
|
406 |
+
def test_number_protocol():
|
407 |
+
for a, b in [(1, 1), (3, 5)]:
|
408 |
+
li = [
|
409 |
+
a == b,
|
410 |
+
a != b,
|
411 |
+
a < b,
|
412 |
+
a <= b,
|
413 |
+
a > b,
|
414 |
+
a >= b,
|
415 |
+
a + b,
|
416 |
+
a - b,
|
417 |
+
a * b,
|
418 |
+
a / b,
|
419 |
+
a | b,
|
420 |
+
a & b,
|
421 |
+
a ^ b,
|
422 |
+
a >> b,
|
423 |
+
a << b,
|
424 |
+
]
|
425 |
+
assert m.test_number_protocol(a, b) == li
|
426 |
+
|
427 |
+
|
428 |
+
def test_list_slicing():
|
429 |
+
li = list(range(100))
|
430 |
+
assert li[::2] == m.test_list_slicing(li)
|
431 |
+
|
432 |
+
|
433 |
+
def test_issue2361():
|
434 |
+
# See issue #2361
|
435 |
+
assert m.issue2361_str_implicit_copy_none() == "None"
|
436 |
+
with pytest.raises(TypeError) as excinfo:
|
437 |
+
assert m.issue2361_dict_implicit_copy_none()
|
438 |
+
assert "'NoneType' object is not iterable" in str(excinfo.value)
|
439 |
+
|
440 |
+
|
441 |
+
@pytest.mark.parametrize(
|
442 |
+
"method, args, fmt, expected_view",
|
443 |
+
[
|
444 |
+
(m.test_memoryview_object, (b"red",), "B", b"red"),
|
445 |
+
(m.test_memoryview_buffer_info, (b"green",), "B", b"green"),
|
446 |
+
(m.test_memoryview_from_buffer, (False,), "h", [3, 1, 4, 1, 5]),
|
447 |
+
(m.test_memoryview_from_buffer, (True,), "H", [2, 7, 1, 8]),
|
448 |
+
(m.test_memoryview_from_buffer_nativeformat, (), "@i", [4, 7, 5]),
|
449 |
+
],
|
450 |
+
)
|
451 |
+
def test_memoryview(method, args, fmt, expected_view):
|
452 |
+
view = method(*args)
|
453 |
+
assert isinstance(view, memoryview)
|
454 |
+
assert view.format == fmt
|
455 |
+
if isinstance(expected_view, bytes) or not env.PY2:
|
456 |
+
view_as_list = list(view)
|
457 |
+
else:
|
458 |
+
# Using max to pick non-zero byte (big-endian vs little-endian).
|
459 |
+
view_as_list = [max(ord(c) for c in s) for s in view]
|
460 |
+
assert view_as_list == list(expected_view)
|
461 |
+
|
462 |
+
|
463 |
+
@pytest.mark.xfail("env.PYPY", reason="getrefcount is not available")
|
464 |
+
@pytest.mark.parametrize(
|
465 |
+
"method",
|
466 |
+
[
|
467 |
+
m.test_memoryview_object,
|
468 |
+
m.test_memoryview_buffer_info,
|
469 |
+
],
|
470 |
+
)
|
471 |
+
def test_memoryview_refcount(method):
|
472 |
+
buf = b"\x0a\x0b\x0c\x0d"
|
473 |
+
ref_before = sys.getrefcount(buf)
|
474 |
+
view = method(buf)
|
475 |
+
ref_after = sys.getrefcount(buf)
|
476 |
+
assert ref_before < ref_after
|
477 |
+
assert list(view) == list(buf)
|
478 |
+
|
479 |
+
|
480 |
+
def test_memoryview_from_buffer_empty_shape():
|
481 |
+
view = m.test_memoryview_from_buffer_empty_shape()
|
482 |
+
assert isinstance(view, memoryview)
|
483 |
+
assert view.format == "B"
|
484 |
+
if env.PY2:
|
485 |
+
# Python 2 behavior is weird, but Python 3 (the future) is fine.
|
486 |
+
# PyPy3 has <memoryview, while CPython 2 has <memory
|
487 |
+
assert bytes(view).startswith(b"<memory")
|
488 |
+
else:
|
489 |
+
assert bytes(view) == b""
|
490 |
+
|
491 |
+
|
492 |
+
def test_test_memoryview_from_buffer_invalid_strides():
|
493 |
+
with pytest.raises(RuntimeError):
|
494 |
+
m.test_memoryview_from_buffer_invalid_strides()
|
495 |
+
|
496 |
+
|
497 |
+
def test_test_memoryview_from_buffer_nullptr():
|
498 |
+
if env.PY2:
|
499 |
+
m.test_memoryview_from_buffer_nullptr()
|
500 |
+
else:
|
501 |
+
with pytest.raises(ValueError):
|
502 |
+
m.test_memoryview_from_buffer_nullptr()
|
503 |
+
|
504 |
+
|
505 |
+
@pytest.mark.skipif("env.PY2")
|
506 |
+
def test_memoryview_from_memory():
|
507 |
+
view = m.test_memoryview_from_memory()
|
508 |
+
assert isinstance(view, memoryview)
|
509 |
+
assert view.format == "B"
|
510 |
+
assert bytes(view) == b"\xff\xe1\xab\x37"
|
511 |
+
|
512 |
+
|
513 |
+
def test_builtin_functions():
|
514 |
+
assert m.get_len([i for i in range(42)]) == 42
|
515 |
+
with pytest.raises(TypeError) as exc_info:
|
516 |
+
m.get_len(i for i in range(42))
|
517 |
+
assert str(exc_info.value) in [
|
518 |
+
"object of type 'generator' has no len()",
|
519 |
+
"'generator' has no length",
|
520 |
+
] # PyPy
|
521 |
+
|
522 |
+
|
523 |
+
def test_isinstance_string_types():
|
524 |
+
assert m.isinstance_pybind11_bytes(b"")
|
525 |
+
assert not m.isinstance_pybind11_bytes(u"")
|
526 |
+
|
527 |
+
assert m.isinstance_pybind11_str(u"")
|
528 |
+
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
529 |
+
assert m.isinstance_pybind11_str(b"")
|
530 |
+
else:
|
531 |
+
assert not m.isinstance_pybind11_str(b"")
|
532 |
+
|
533 |
+
|
534 |
+
def test_pass_bytes_or_unicode_to_string_types():
|
535 |
+
assert m.pass_to_pybind11_bytes(b"Bytes") == 5
|
536 |
+
with pytest.raises(TypeError):
|
537 |
+
m.pass_to_pybind11_bytes(u"Str")
|
538 |
+
|
539 |
+
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE") or env.PY2:
|
540 |
+
assert m.pass_to_pybind11_str(b"Bytes") == 5
|
541 |
+
else:
|
542 |
+
with pytest.raises(TypeError):
|
543 |
+
m.pass_to_pybind11_str(b"Bytes")
|
544 |
+
assert m.pass_to_pybind11_str(u"Str") == 3
|
545 |
+
|
546 |
+
assert m.pass_to_std_string(b"Bytes") == 5
|
547 |
+
assert m.pass_to_std_string(u"Str") == 3
|
548 |
+
|
549 |
+
malformed_utf8 = b"\x80"
|
550 |
+
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
551 |
+
assert m.pass_to_pybind11_str(malformed_utf8) == 1
|
552 |
+
elif env.PY2:
|
553 |
+
with pytest.raises(UnicodeDecodeError):
|
554 |
+
m.pass_to_pybind11_str(malformed_utf8)
|
555 |
+
else:
|
556 |
+
with pytest.raises(TypeError):
|
557 |
+
m.pass_to_pybind11_str(malformed_utf8)
|
558 |
+
|
559 |
+
|
560 |
+
@pytest.mark.parametrize(
|
561 |
+
"create_weakref, create_weakref_with_callback",
|
562 |
+
[
|
563 |
+
(m.weakref_from_handle, m.weakref_from_handle_and_function),
|
564 |
+
(m.weakref_from_object, m.weakref_from_object_and_function),
|
565 |
+
],
|
566 |
+
)
|
567 |
+
def test_weakref(create_weakref, create_weakref_with_callback):
|
568 |
+
from weakref import getweakrefcount
|
569 |
+
|
570 |
+
# Apparently, you cannot weakly reference an object()
|
571 |
+
class WeaklyReferenced(object):
|
572 |
+
pass
|
573 |
+
|
574 |
+
def callback(wr):
|
575 |
+
# No `nonlocal` in Python 2
|
576 |
+
callback.called = True
|
577 |
+
|
578 |
+
obj = WeaklyReferenced()
|
579 |
+
assert getweakrefcount(obj) == 0
|
580 |
+
wr = create_weakref(obj) # noqa: F841
|
581 |
+
assert getweakrefcount(obj) == 1
|
582 |
+
|
583 |
+
obj = WeaklyReferenced()
|
584 |
+
assert getweakrefcount(obj) == 0
|
585 |
+
callback.called = False
|
586 |
+
wr = create_weakref_with_callback(obj, callback) # noqa: F841
|
587 |
+
assert getweakrefcount(obj) == 1
|
588 |
+
assert not callback.called
|
589 |
+
del obj
|
590 |
+
pytest.gc_collect()
|
591 |
+
assert callback.called
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_sequences_and_iterators.cpp
ADDED
@@ -0,0 +1,374 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_sequences_and_iterators.cpp -- supporting Pythons' sequence protocol, iterators,
|
3 |
+
etc.
|
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 |
+
#include "constructor_stats.h"
|
13 |
+
#include <pybind11/operators.h>
|
14 |
+
#include <pybind11/stl.h>
|
15 |
+
|
16 |
+
#include <algorithm>
|
17 |
+
#include <utility>
|
18 |
+
|
19 |
+
template<typename T>
|
20 |
+
class NonZeroIterator {
|
21 |
+
const T* ptr_;
|
22 |
+
public:
|
23 |
+
NonZeroIterator(const T* ptr) : ptr_(ptr) {}
|
24 |
+
const T& operator*() const { return *ptr_; }
|
25 |
+
NonZeroIterator& operator++() { ++ptr_; return *this; }
|
26 |
+
};
|
27 |
+
|
28 |
+
class NonZeroSentinel {};
|
29 |
+
|
30 |
+
template<typename A, typename B>
|
31 |
+
bool operator==(const NonZeroIterator<std::pair<A, B>>& it, const NonZeroSentinel&) {
|
32 |
+
return !(*it).first || !(*it).second;
|
33 |
+
}
|
34 |
+
|
35 |
+
template <typename PythonType>
|
36 |
+
py::list test_random_access_iterator(PythonType x) {
|
37 |
+
if (x.size() < 5)
|
38 |
+
throw py::value_error("Please provide at least 5 elements for testing.");
|
39 |
+
|
40 |
+
auto checks = py::list();
|
41 |
+
auto assert_equal = [&checks](py::handle a, py::handle b) {
|
42 |
+
auto result = PyObject_RichCompareBool(a.ptr(), b.ptr(), Py_EQ);
|
43 |
+
if (result == -1) { throw py::error_already_set(); }
|
44 |
+
checks.append(result != 0);
|
45 |
+
};
|
46 |
+
|
47 |
+
auto it = x.begin();
|
48 |
+
assert_equal(x[0], *it);
|
49 |
+
assert_equal(x[0], it[0]);
|
50 |
+
assert_equal(x[1], it[1]);
|
51 |
+
|
52 |
+
assert_equal(x[1], *(++it));
|
53 |
+
assert_equal(x[1], *(it++));
|
54 |
+
assert_equal(x[2], *it);
|
55 |
+
assert_equal(x[3], *(it += 1));
|
56 |
+
assert_equal(x[2], *(--it));
|
57 |
+
assert_equal(x[2], *(it--));
|
58 |
+
assert_equal(x[1], *it);
|
59 |
+
assert_equal(x[0], *(it -= 1));
|
60 |
+
|
61 |
+
assert_equal(it->attr("real"), x[0].attr("real"));
|
62 |
+
assert_equal((it + 1)->attr("real"), x[1].attr("real"));
|
63 |
+
|
64 |
+
assert_equal(x[1], *(it + 1));
|
65 |
+
assert_equal(x[1], *(1 + it));
|
66 |
+
it += 3;
|
67 |
+
assert_equal(x[1], *(it - 2));
|
68 |
+
|
69 |
+
checks.append(static_cast<std::size_t>(x.end() - x.begin()) == x.size());
|
70 |
+
checks.append((x.begin() + static_cast<std::ptrdiff_t>(x.size())) == x.end());
|
71 |
+
checks.append(x.begin() < x.end());
|
72 |
+
|
73 |
+
return checks;
|
74 |
+
}
|
75 |
+
|
76 |
+
TEST_SUBMODULE(sequences_and_iterators, m) {
|
77 |
+
// test_sliceable
|
78 |
+
class Sliceable{
|
79 |
+
public:
|
80 |
+
Sliceable(int n): size(n) {}
|
81 |
+
int start,stop,step;
|
82 |
+
int size;
|
83 |
+
};
|
84 |
+
py::class_<Sliceable>(m, "Sliceable")
|
85 |
+
.def(py::init<int>())
|
86 |
+
.def("__getitem__", [](const Sliceable &s, const py::slice &slice) {
|
87 |
+
py::ssize_t start = 0, stop = 0, step = 0, slicelength = 0;
|
88 |
+
if (!slice.compute(s.size, &start, &stop, &step, &slicelength))
|
89 |
+
throw py::error_already_set();
|
90 |
+
int istart = static_cast<int>(start);
|
91 |
+
int istop = static_cast<int>(stop);
|
92 |
+
int istep = static_cast<int>(step);
|
93 |
+
return std::make_tuple(istart, istop, istep);
|
94 |
+
});
|
95 |
+
|
96 |
+
// test_sequence
|
97 |
+
class Sequence {
|
98 |
+
public:
|
99 |
+
Sequence(size_t size) : m_size(size) {
|
100 |
+
print_created(this, "of size", m_size);
|
101 |
+
m_data = new float[size];
|
102 |
+
memset(m_data, 0, sizeof(float) * size);
|
103 |
+
}
|
104 |
+
Sequence(const std::vector<float> &value) : m_size(value.size()) {
|
105 |
+
print_created(this, "of size", m_size, "from std::vector");
|
106 |
+
m_data = new float[m_size];
|
107 |
+
memcpy(m_data, &value[0], sizeof(float) * m_size);
|
108 |
+
}
|
109 |
+
Sequence(const Sequence &s) : m_size(s.m_size) {
|
110 |
+
print_copy_created(this);
|
111 |
+
m_data = new float[m_size];
|
112 |
+
memcpy(m_data, s.m_data, sizeof(float)*m_size);
|
113 |
+
}
|
114 |
+
Sequence(Sequence &&s) noexcept : m_size(s.m_size), m_data(s.m_data) {
|
115 |
+
print_move_created(this);
|
116 |
+
s.m_size = 0;
|
117 |
+
s.m_data = nullptr;
|
118 |
+
}
|
119 |
+
|
120 |
+
~Sequence() { print_destroyed(this); delete[] m_data; }
|
121 |
+
|
122 |
+
Sequence &operator=(const Sequence &s) {
|
123 |
+
if (&s != this) {
|
124 |
+
delete[] m_data;
|
125 |
+
m_size = s.m_size;
|
126 |
+
m_data = new float[m_size];
|
127 |
+
memcpy(m_data, s.m_data, sizeof(float)*m_size);
|
128 |
+
}
|
129 |
+
print_copy_assigned(this);
|
130 |
+
return *this;
|
131 |
+
}
|
132 |
+
|
133 |
+
Sequence &operator=(Sequence &&s) noexcept {
|
134 |
+
if (&s != this) {
|
135 |
+
delete[] m_data;
|
136 |
+
m_size = s.m_size;
|
137 |
+
m_data = s.m_data;
|
138 |
+
s.m_size = 0;
|
139 |
+
s.m_data = nullptr;
|
140 |
+
}
|
141 |
+
print_move_assigned(this);
|
142 |
+
return *this;
|
143 |
+
}
|
144 |
+
|
145 |
+
bool operator==(const Sequence &s) const {
|
146 |
+
if (m_size != s.size()) return false;
|
147 |
+
for (size_t i = 0; i < m_size; ++i)
|
148 |
+
if (m_data[i] != s[i])
|
149 |
+
return false;
|
150 |
+
return true;
|
151 |
+
}
|
152 |
+
bool operator!=(const Sequence &s) const { return !operator==(s); }
|
153 |
+
|
154 |
+
float operator[](size_t index) const { return m_data[index]; }
|
155 |
+
float &operator[](size_t index) { return m_data[index]; }
|
156 |
+
|
157 |
+
bool contains(float v) const {
|
158 |
+
for (size_t i = 0; i < m_size; ++i)
|
159 |
+
if (v == m_data[i])
|
160 |
+
return true;
|
161 |
+
return false;
|
162 |
+
}
|
163 |
+
|
164 |
+
Sequence reversed() const {
|
165 |
+
Sequence result(m_size);
|
166 |
+
for (size_t i = 0; i < m_size; ++i)
|
167 |
+
result[m_size - i - 1] = m_data[i];
|
168 |
+
return result;
|
169 |
+
}
|
170 |
+
|
171 |
+
size_t size() const { return m_size; }
|
172 |
+
|
173 |
+
const float *begin() const { return m_data; }
|
174 |
+
const float *end() const { return m_data+m_size; }
|
175 |
+
|
176 |
+
private:
|
177 |
+
size_t m_size;
|
178 |
+
float *m_data;
|
179 |
+
};
|
180 |
+
py::class_<Sequence>(m, "Sequence")
|
181 |
+
.def(py::init<size_t>())
|
182 |
+
.def(py::init<const std::vector<float> &>())
|
183 |
+
/// Bare bones interface
|
184 |
+
.def("__getitem__",
|
185 |
+
[](const Sequence &s, size_t i) {
|
186 |
+
if (i >= s.size())
|
187 |
+
throw py::index_error();
|
188 |
+
return s[i];
|
189 |
+
})
|
190 |
+
.def("__setitem__",
|
191 |
+
[](Sequence &s, size_t i, float v) {
|
192 |
+
if (i >= s.size())
|
193 |
+
throw py::index_error();
|
194 |
+
s[i] = v;
|
195 |
+
})
|
196 |
+
.def("__len__", &Sequence::size)
|
197 |
+
/// Optional sequence protocol operations
|
198 |
+
.def(
|
199 |
+
"__iter__",
|
200 |
+
[](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); },
|
201 |
+
py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */)
|
202 |
+
.def("__contains__", [](const Sequence &s, float v) { return s.contains(v); })
|
203 |
+
.def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); })
|
204 |
+
/// Slicing protocol (optional)
|
205 |
+
.def("__getitem__",
|
206 |
+
[](const Sequence &s, const py::slice &slice) -> Sequence * {
|
207 |
+
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
208 |
+
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
|
209 |
+
throw py::error_already_set();
|
210 |
+
auto *seq = new Sequence(slicelength);
|
211 |
+
for (size_t i = 0; i < slicelength; ++i) {
|
212 |
+
(*seq)[i] = s[start];
|
213 |
+
start += step;
|
214 |
+
}
|
215 |
+
return seq;
|
216 |
+
})
|
217 |
+
.def("__setitem__",
|
218 |
+
[](Sequence &s, const py::slice &slice, const Sequence &value) {
|
219 |
+
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
220 |
+
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
|
221 |
+
throw py::error_already_set();
|
222 |
+
if (slicelength != value.size())
|
223 |
+
throw std::runtime_error(
|
224 |
+
"Left and right hand size of slice assignment have different sizes!");
|
225 |
+
for (size_t i = 0; i < slicelength; ++i) {
|
226 |
+
s[start] = value[i];
|
227 |
+
start += step;
|
228 |
+
}
|
229 |
+
})
|
230 |
+
/// Comparisons
|
231 |
+
.def(py::self == py::self)
|
232 |
+
.def(py::self != py::self)
|
233 |
+
// Could also define py::self + py::self for concatenation, etc.
|
234 |
+
;
|
235 |
+
|
236 |
+
// test_map_iterator
|
237 |
+
// Interface of a map-like object that isn't (directly) an unordered_map, but provides some basic
|
238 |
+
// map-like functionality.
|
239 |
+
class StringMap {
|
240 |
+
public:
|
241 |
+
StringMap() = default;
|
242 |
+
StringMap(std::unordered_map<std::string, std::string> init)
|
243 |
+
: map(std::move(init)) {}
|
244 |
+
|
245 |
+
void set(const std::string &key, std::string val) { map[key] = std::move(val); }
|
246 |
+
std::string get(const std::string &key) const { return map.at(key); }
|
247 |
+
size_t size() const { return map.size(); }
|
248 |
+
private:
|
249 |
+
std::unordered_map<std::string, std::string> map;
|
250 |
+
public:
|
251 |
+
decltype(map.cbegin()) begin() const { return map.cbegin(); }
|
252 |
+
decltype(map.cend()) end() const { return map.cend(); }
|
253 |
+
};
|
254 |
+
py::class_<StringMap>(m, "StringMap")
|
255 |
+
.def(py::init<>())
|
256 |
+
.def(py::init<std::unordered_map<std::string, std::string>>())
|
257 |
+
.def("__getitem__",
|
258 |
+
[](const StringMap &map, const std::string &key) {
|
259 |
+
try {
|
260 |
+
return map.get(key);
|
261 |
+
} catch (const std::out_of_range &) {
|
262 |
+
throw py::key_error("key '" + key + "' does not exist");
|
263 |
+
}
|
264 |
+
})
|
265 |
+
.def("__setitem__", &StringMap::set)
|
266 |
+
.def("__len__", &StringMap::size)
|
267 |
+
.def(
|
268 |
+
"__iter__",
|
269 |
+
[](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); },
|
270 |
+
py::keep_alive<0, 1>())
|
271 |
+
.def(
|
272 |
+
"items",
|
273 |
+
[](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); },
|
274 |
+
py::keep_alive<0, 1>());
|
275 |
+
|
276 |
+
// test_generalized_iterators
|
277 |
+
class IntPairs {
|
278 |
+
public:
|
279 |
+
IntPairs(std::vector<std::pair<int, int>> data) : data_(std::move(data)) {}
|
280 |
+
const std::pair<int, int>* begin() const { return data_.data(); }
|
281 |
+
private:
|
282 |
+
std::vector<std::pair<int, int>> data_;
|
283 |
+
};
|
284 |
+
py::class_<IntPairs>(m, "IntPairs")
|
285 |
+
.def(py::init<std::vector<std::pair<int, int>>>())
|
286 |
+
.def("nonzero", [](const IntPairs& s) {
|
287 |
+
return py::make_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel());
|
288 |
+
}, py::keep_alive<0, 1>())
|
289 |
+
.def("nonzero_keys", [](const IntPairs& s) {
|
290 |
+
return py::make_key_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel());
|
291 |
+
}, py::keep_alive<0, 1>())
|
292 |
+
;
|
293 |
+
|
294 |
+
|
295 |
+
#if 0
|
296 |
+
// Obsolete: special data structure for exposing custom iterator types to python
|
297 |
+
// kept here for illustrative purposes because there might be some use cases which
|
298 |
+
// are not covered by the much simpler py::make_iterator
|
299 |
+
|
300 |
+
struct PySequenceIterator {
|
301 |
+
PySequenceIterator(const Sequence &seq, py::object ref) : seq(seq), ref(ref) { }
|
302 |
+
|
303 |
+
float next() {
|
304 |
+
if (index == seq.size())
|
305 |
+
throw py::stop_iteration();
|
306 |
+
return seq[index++];
|
307 |
+
}
|
308 |
+
|
309 |
+
const Sequence &seq;
|
310 |
+
py::object ref; // keep a reference
|
311 |
+
size_t index = 0;
|
312 |
+
};
|
313 |
+
|
314 |
+
py::class_<PySequenceIterator>(seq, "Iterator")
|
315 |
+
.def("__iter__", [](PySequenceIterator &it) -> PySequenceIterator& { return it; })
|
316 |
+
.def("__next__", &PySequenceIterator::next);
|
317 |
+
|
318 |
+
On the actual Sequence object, the iterator would be constructed as follows:
|
319 |
+
.def("__iter__", [](py::object s) { return PySequenceIterator(s.cast<const Sequence &>(), s); })
|
320 |
+
#endif
|
321 |
+
|
322 |
+
// test_python_iterator_in_cpp
|
323 |
+
m.def("object_to_list", [](const py::object &o) {
|
324 |
+
auto l = py::list();
|
325 |
+
for (auto item : o) {
|
326 |
+
l.append(item);
|
327 |
+
}
|
328 |
+
return l;
|
329 |
+
});
|
330 |
+
|
331 |
+
m.def("iterator_to_list", [](py::iterator it) {
|
332 |
+
auto l = py::list();
|
333 |
+
while (it != py::iterator::sentinel()) {
|
334 |
+
l.append(*it);
|
335 |
+
++it;
|
336 |
+
}
|
337 |
+
return l;
|
338 |
+
});
|
339 |
+
|
340 |
+
// test_sequence_length: check that Python sequences can be converted to py::sequence.
|
341 |
+
m.def("sequence_length", [](const py::sequence &seq) { return seq.size(); });
|
342 |
+
|
343 |
+
// Make sure that py::iterator works with std algorithms
|
344 |
+
m.def("count_none", [](const py::object &o) {
|
345 |
+
return std::count_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); });
|
346 |
+
});
|
347 |
+
|
348 |
+
m.def("find_none", [](const py::object &o) {
|
349 |
+
auto it = std::find_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); });
|
350 |
+
return it->is_none();
|
351 |
+
});
|
352 |
+
|
353 |
+
m.def("count_nonzeros", [](const py::dict &d) {
|
354 |
+
return std::count_if(d.begin(), d.end(), [](std::pair<py::handle, py::handle> p) {
|
355 |
+
return p.second.cast<int>() != 0;
|
356 |
+
});
|
357 |
+
});
|
358 |
+
|
359 |
+
m.def("tuple_iterator", &test_random_access_iterator<py::tuple>);
|
360 |
+
m.def("list_iterator", &test_random_access_iterator<py::list>);
|
361 |
+
m.def("sequence_iterator", &test_random_access_iterator<py::sequence>);
|
362 |
+
|
363 |
+
// test_iterator_passthrough
|
364 |
+
// #181: iterator passthrough did not compile
|
365 |
+
m.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
|
366 |
+
return py::make_iterator(std::begin(s), std::end(s));
|
367 |
+
});
|
368 |
+
|
369 |
+
// test_iterator_rvp
|
370 |
+
// #388: Can't make iterators via make_iterator() with different r/v policies
|
371 |
+
static std::vector<int> list = { 1, 2, 3 };
|
372 |
+
m.def("make_iterator_1", []() { return py::make_iterator<py::return_value_policy::copy>(list); });
|
373 |
+
m.def("make_iterator_2", []() { return py::make_iterator<py::return_value_policy::automatic>(list); });
|
374 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_sequences_and_iterators.py
ADDED
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
from pybind11_tests import sequences_and_iterators as m
|
4 |
+
from pybind11_tests import ConstructorStats
|
5 |
+
|
6 |
+
|
7 |
+
def isclose(a, b, rel_tol=1e-05, abs_tol=0.0):
|
8 |
+
"""Like math.isclose() from Python 3.5"""
|
9 |
+
return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
|
10 |
+
|
11 |
+
|
12 |
+
def allclose(a_list, b_list, rel_tol=1e-05, abs_tol=0.0):
|
13 |
+
return all(
|
14 |
+
isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) for a, b in zip(a_list, b_list)
|
15 |
+
)
|
16 |
+
|
17 |
+
|
18 |
+
def test_generalized_iterators():
|
19 |
+
assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero()) == [(1, 2), (3, 4)]
|
20 |
+
assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero()) == [(1, 2)]
|
21 |
+
assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero()) == []
|
22 |
+
|
23 |
+
assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_keys()) == [1, 3]
|
24 |
+
assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_keys()) == [1]
|
25 |
+
assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_keys()) == []
|
26 |
+
|
27 |
+
# __next__ must continue to raise StopIteration
|
28 |
+
it = m.IntPairs([(0, 0)]).nonzero()
|
29 |
+
for _ in range(3):
|
30 |
+
with pytest.raises(StopIteration):
|
31 |
+
next(it)
|
32 |
+
|
33 |
+
it = m.IntPairs([(0, 0)]).nonzero_keys()
|
34 |
+
for _ in range(3):
|
35 |
+
with pytest.raises(StopIteration):
|
36 |
+
next(it)
|
37 |
+
|
38 |
+
|
39 |
+
def test_sliceable():
|
40 |
+
sliceable = m.Sliceable(100)
|
41 |
+
assert sliceable[::] == (0, 100, 1)
|
42 |
+
assert sliceable[10::] == (10, 100, 1)
|
43 |
+
assert sliceable[:10:] == (0, 10, 1)
|
44 |
+
assert sliceable[::10] == (0, 100, 10)
|
45 |
+
assert sliceable[-10::] == (90, 100, 1)
|
46 |
+
assert sliceable[:-10:] == (0, 90, 1)
|
47 |
+
assert sliceable[::-10] == (99, -1, -10)
|
48 |
+
assert sliceable[50:60:1] == (50, 60, 1)
|
49 |
+
assert sliceable[50:60:-1] == (50, 60, -1)
|
50 |
+
|
51 |
+
|
52 |
+
def test_sequence():
|
53 |
+
cstats = ConstructorStats.get(m.Sequence)
|
54 |
+
|
55 |
+
s = m.Sequence(5)
|
56 |
+
assert cstats.values() == ["of size", "5"]
|
57 |
+
|
58 |
+
assert "Sequence" in repr(s)
|
59 |
+
assert len(s) == 5
|
60 |
+
assert s[0] == 0 and s[3] == 0
|
61 |
+
assert 12.34 not in s
|
62 |
+
s[0], s[3] = 12.34, 56.78
|
63 |
+
assert 12.34 in s
|
64 |
+
assert isclose(s[0], 12.34) and isclose(s[3], 56.78)
|
65 |
+
|
66 |
+
rev = reversed(s)
|
67 |
+
assert cstats.values() == ["of size", "5"]
|
68 |
+
|
69 |
+
rev2 = s[::-1]
|
70 |
+
assert cstats.values() == ["of size", "5"]
|
71 |
+
|
72 |
+
it = iter(m.Sequence(0))
|
73 |
+
for _ in range(3): # __next__ must continue to raise StopIteration
|
74 |
+
with pytest.raises(StopIteration):
|
75 |
+
next(it)
|
76 |
+
assert cstats.values() == ["of size", "0"]
|
77 |
+
|
78 |
+
expected = [0, 56.78, 0, 0, 12.34]
|
79 |
+
assert allclose(rev, expected)
|
80 |
+
assert allclose(rev2, expected)
|
81 |
+
assert rev == rev2
|
82 |
+
|
83 |
+
rev[0::2] = m.Sequence([2.0, 2.0, 2.0])
|
84 |
+
assert cstats.values() == ["of size", "3", "from std::vector"]
|
85 |
+
|
86 |
+
assert allclose(rev, [2, 56.78, 2, 0, 2])
|
87 |
+
|
88 |
+
assert cstats.alive() == 4
|
89 |
+
del it
|
90 |
+
assert cstats.alive() == 3
|
91 |
+
del s
|
92 |
+
assert cstats.alive() == 2
|
93 |
+
del rev
|
94 |
+
assert cstats.alive() == 1
|
95 |
+
del rev2
|
96 |
+
assert cstats.alive() == 0
|
97 |
+
|
98 |
+
assert cstats.values() == []
|
99 |
+
assert cstats.default_constructions == 0
|
100 |
+
assert cstats.copy_constructions == 0
|
101 |
+
assert cstats.move_constructions >= 1
|
102 |
+
assert cstats.copy_assignments == 0
|
103 |
+
assert cstats.move_assignments == 0
|
104 |
+
|
105 |
+
|
106 |
+
def test_sequence_length():
|
107 |
+
"""#2076: Exception raised by len(arg) should be propagated"""
|
108 |
+
|
109 |
+
class BadLen(RuntimeError):
|
110 |
+
pass
|
111 |
+
|
112 |
+
class SequenceLike:
|
113 |
+
def __getitem__(self, i):
|
114 |
+
return None
|
115 |
+
|
116 |
+
def __len__(self):
|
117 |
+
raise BadLen()
|
118 |
+
|
119 |
+
with pytest.raises(BadLen):
|
120 |
+
m.sequence_length(SequenceLike())
|
121 |
+
|
122 |
+
assert m.sequence_length([1, 2, 3]) == 3
|
123 |
+
assert m.sequence_length("hello") == 5
|
124 |
+
|
125 |
+
|
126 |
+
def test_map_iterator():
|
127 |
+
sm = m.StringMap({"hi": "bye", "black": "white"})
|
128 |
+
assert sm["hi"] == "bye"
|
129 |
+
assert len(sm) == 2
|
130 |
+
assert sm["black"] == "white"
|
131 |
+
|
132 |
+
with pytest.raises(KeyError):
|
133 |
+
assert sm["orange"]
|
134 |
+
sm["orange"] = "banana"
|
135 |
+
assert sm["orange"] == "banana"
|
136 |
+
|
137 |
+
expected = {"hi": "bye", "black": "white", "orange": "banana"}
|
138 |
+
for k in sm:
|
139 |
+
assert sm[k] == expected[k]
|
140 |
+
for k, v in sm.items():
|
141 |
+
assert v == expected[k]
|
142 |
+
|
143 |
+
it = iter(m.StringMap({}))
|
144 |
+
for _ in range(3): # __next__ must continue to raise StopIteration
|
145 |
+
with pytest.raises(StopIteration):
|
146 |
+
next(it)
|
147 |
+
|
148 |
+
|
149 |
+
def test_python_iterator_in_cpp():
|
150 |
+
t = (1, 2, 3)
|
151 |
+
assert m.object_to_list(t) == [1, 2, 3]
|
152 |
+
assert m.object_to_list(iter(t)) == [1, 2, 3]
|
153 |
+
assert m.iterator_to_list(iter(t)) == [1, 2, 3]
|
154 |
+
|
155 |
+
with pytest.raises(TypeError) as excinfo:
|
156 |
+
m.object_to_list(1)
|
157 |
+
assert "object is not iterable" in str(excinfo.value)
|
158 |
+
|
159 |
+
with pytest.raises(TypeError) as excinfo:
|
160 |
+
m.iterator_to_list(1)
|
161 |
+
assert "incompatible function arguments" in str(excinfo.value)
|
162 |
+
|
163 |
+
def bad_next_call():
|
164 |
+
raise RuntimeError("py::iterator::advance() should propagate errors")
|
165 |
+
|
166 |
+
with pytest.raises(RuntimeError) as excinfo:
|
167 |
+
m.iterator_to_list(iter(bad_next_call, None))
|
168 |
+
assert str(excinfo.value) == "py::iterator::advance() should propagate errors"
|
169 |
+
|
170 |
+
lst = [1, None, 0, None]
|
171 |
+
assert m.count_none(lst) == 2
|
172 |
+
assert m.find_none(lst) is True
|
173 |
+
assert m.count_nonzeros({"a": 0, "b": 1, "c": 2}) == 2
|
174 |
+
|
175 |
+
r = range(5)
|
176 |
+
assert all(m.tuple_iterator(tuple(r)))
|
177 |
+
assert all(m.list_iterator(list(r)))
|
178 |
+
assert all(m.sequence_iterator(r))
|
179 |
+
|
180 |
+
|
181 |
+
def test_iterator_passthrough():
|
182 |
+
"""#181: iterator passthrough did not compile"""
|
183 |
+
from pybind11_tests.sequences_and_iterators import iterator_passthrough
|
184 |
+
|
185 |
+
values = [3, 5, 7, 9, 11, 13, 15]
|
186 |
+
assert list(iterator_passthrough(iter(values))) == values
|
187 |
+
|
188 |
+
|
189 |
+
def test_iterator_rvp():
|
190 |
+
"""#388: Can't make iterators via make_iterator() with different r/v policies"""
|
191 |
+
import pybind11_tests.sequences_and_iterators as m
|
192 |
+
|
193 |
+
assert list(m.make_iterator_1()) == [1, 2, 3]
|
194 |
+
assert list(m.make_iterator_2()) == [1, 2, 3]
|
195 |
+
assert not isinstance(m.make_iterator_1(), type(m.make_iterator_2()))
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_smart_ptr.cpp
ADDED
@@ -0,0 +1,451 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_smart_ptr.cpp -- binding classes with custom reference counting,
|
3 |
+
implicit conversions between types
|
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 |
+
#if defined(_MSC_VER) && _MSC_VER < 1910 // VS 2015's MSVC
|
12 |
+
# pragma warning(disable: 4702) // unreachable code in system header (xatomic.h(382))
|
13 |
+
#endif
|
14 |
+
|
15 |
+
#include "pybind11_tests.h"
|
16 |
+
#include "object.h"
|
17 |
+
|
18 |
+
namespace {
|
19 |
+
|
20 |
+
// This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the
|
21 |
+
// holder size to trigger the non-simple-layout internal instance layout for single inheritance with
|
22 |
+
// large holder type:
|
23 |
+
template <typename T> class huge_unique_ptr {
|
24 |
+
std::unique_ptr<T> ptr;
|
25 |
+
uint64_t padding[10];
|
26 |
+
public:
|
27 |
+
huge_unique_ptr(T *p) : ptr(p) {}
|
28 |
+
T *get() { return ptr.get(); }
|
29 |
+
};
|
30 |
+
|
31 |
+
// Simple custom holder that works like unique_ptr
|
32 |
+
template <typename T>
|
33 |
+
class custom_unique_ptr {
|
34 |
+
std::unique_ptr<T> impl;
|
35 |
+
public:
|
36 |
+
custom_unique_ptr(T* p) : impl(p) { }
|
37 |
+
T* get() const { return impl.get(); }
|
38 |
+
T* release_ptr() { return impl.release(); }
|
39 |
+
};
|
40 |
+
|
41 |
+
// Simple custom holder that works like shared_ptr and has operator& overload
|
42 |
+
// To obtain address of an instance of this holder pybind should use std::addressof
|
43 |
+
// Attempt to get address via operator& may leads to segmentation fault
|
44 |
+
template <typename T>
|
45 |
+
class shared_ptr_with_addressof_operator {
|
46 |
+
std::shared_ptr<T> impl;
|
47 |
+
public:
|
48 |
+
shared_ptr_with_addressof_operator( ) = default;
|
49 |
+
shared_ptr_with_addressof_operator(T* p) : impl(p) { }
|
50 |
+
T* get() const { return impl.get(); }
|
51 |
+
T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); }
|
52 |
+
};
|
53 |
+
|
54 |
+
// Simple custom holder that works like unique_ptr and has operator& overload
|
55 |
+
// To obtain address of an instance of this holder pybind should use std::addressof
|
56 |
+
// Attempt to get address via operator& may leads to segmentation fault
|
57 |
+
template <typename T>
|
58 |
+
class unique_ptr_with_addressof_operator {
|
59 |
+
std::unique_ptr<T> impl;
|
60 |
+
public:
|
61 |
+
unique_ptr_with_addressof_operator() = default;
|
62 |
+
unique_ptr_with_addressof_operator(T* p) : impl(p) { }
|
63 |
+
T* get() const { return impl.get(); }
|
64 |
+
T* release_ptr() { return impl.release(); }
|
65 |
+
T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); }
|
66 |
+
};
|
67 |
+
|
68 |
+
// Custom object with builtin reference counting (see 'object.h' for the implementation)
|
69 |
+
class MyObject1 : public Object {
|
70 |
+
public:
|
71 |
+
MyObject1(int value) : value(value) { print_created(this, toString()); }
|
72 |
+
std::string toString() const override { return "MyObject1[" + std::to_string(value) + "]"; }
|
73 |
+
protected:
|
74 |
+
~MyObject1() override { print_destroyed(this); }
|
75 |
+
private:
|
76 |
+
int value;
|
77 |
+
};
|
78 |
+
|
79 |
+
// Object managed by a std::shared_ptr<>
|
80 |
+
class MyObject2 {
|
81 |
+
public:
|
82 |
+
MyObject2(const MyObject2 &) = default;
|
83 |
+
MyObject2(int value) : value(value) { print_created(this, toString()); }
|
84 |
+
std::string toString() const { return "MyObject2[" + std::to_string(value) + "]"; }
|
85 |
+
virtual ~MyObject2() { print_destroyed(this); }
|
86 |
+
private:
|
87 |
+
int value;
|
88 |
+
};
|
89 |
+
|
90 |
+
// Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<>
|
91 |
+
class MyObject3 : public std::enable_shared_from_this<MyObject3> {
|
92 |
+
public:
|
93 |
+
MyObject3(const MyObject3 &) = default;
|
94 |
+
MyObject3(int value) : value(value) { print_created(this, toString()); }
|
95 |
+
std::string toString() const { return "MyObject3[" + std::to_string(value) + "]"; }
|
96 |
+
virtual ~MyObject3() { print_destroyed(this); }
|
97 |
+
private:
|
98 |
+
int value;
|
99 |
+
};
|
100 |
+
|
101 |
+
// test_unique_nodelete
|
102 |
+
// Object with a private destructor
|
103 |
+
class MyObject4;
|
104 |
+
std::unordered_set<MyObject4 *> myobject4_instances;
|
105 |
+
class MyObject4 {
|
106 |
+
public:
|
107 |
+
MyObject4(int value) : value{value} {
|
108 |
+
print_created(this);
|
109 |
+
myobject4_instances.insert(this);
|
110 |
+
}
|
111 |
+
int value;
|
112 |
+
|
113 |
+
static void cleanupAllInstances() {
|
114 |
+
auto tmp = std::move(myobject4_instances);
|
115 |
+
myobject4_instances.clear();
|
116 |
+
for (auto o : tmp)
|
117 |
+
delete o;
|
118 |
+
}
|
119 |
+
private:
|
120 |
+
~MyObject4() {
|
121 |
+
myobject4_instances.erase(this);
|
122 |
+
print_destroyed(this);
|
123 |
+
}
|
124 |
+
};
|
125 |
+
|
126 |
+
// test_unique_deleter
|
127 |
+
// Object with std::unique_ptr<T, D> where D is not matching the base class
|
128 |
+
// Object with a protected destructor
|
129 |
+
class MyObject4a;
|
130 |
+
std::unordered_set<MyObject4a *> myobject4a_instances;
|
131 |
+
class MyObject4a {
|
132 |
+
public:
|
133 |
+
MyObject4a(int i) {
|
134 |
+
value = i;
|
135 |
+
print_created(this);
|
136 |
+
myobject4a_instances.insert(this);
|
137 |
+
};
|
138 |
+
int value;
|
139 |
+
|
140 |
+
static void cleanupAllInstances() {
|
141 |
+
auto tmp = std::move(myobject4a_instances);
|
142 |
+
myobject4a_instances.clear();
|
143 |
+
for (auto o : tmp)
|
144 |
+
delete o;
|
145 |
+
}
|
146 |
+
protected:
|
147 |
+
virtual ~MyObject4a() {
|
148 |
+
myobject4a_instances.erase(this);
|
149 |
+
print_destroyed(this);
|
150 |
+
}
|
151 |
+
};
|
152 |
+
|
153 |
+
// Object derived but with public destructor and no Deleter in default holder
|
154 |
+
class MyObject4b : public MyObject4a {
|
155 |
+
public:
|
156 |
+
MyObject4b(int i) : MyObject4a(i) { print_created(this); }
|
157 |
+
~MyObject4b() override { print_destroyed(this); }
|
158 |
+
};
|
159 |
+
|
160 |
+
// test_large_holder
|
161 |
+
class MyObject5 { // managed by huge_unique_ptr
|
162 |
+
public:
|
163 |
+
MyObject5(int value) : value{value} { print_created(this); }
|
164 |
+
~MyObject5() { print_destroyed(this); }
|
165 |
+
int value;
|
166 |
+
};
|
167 |
+
|
168 |
+
// test_shared_ptr_and_references
|
169 |
+
struct SharedPtrRef {
|
170 |
+
struct A {
|
171 |
+
A() { print_created(this); }
|
172 |
+
A(const A &) { print_copy_created(this); }
|
173 |
+
A(A &&) noexcept { print_move_created(this); }
|
174 |
+
~A() { print_destroyed(this); }
|
175 |
+
};
|
176 |
+
|
177 |
+
A value = {};
|
178 |
+
std::shared_ptr<A> shared = std::make_shared<A>();
|
179 |
+
};
|
180 |
+
|
181 |
+
// test_shared_ptr_from_this_and_references
|
182 |
+
struct SharedFromThisRef {
|
183 |
+
struct B : std::enable_shared_from_this<B> {
|
184 |
+
B() { print_created(this); }
|
185 |
+
B(const B &) : std::enable_shared_from_this<B>() { print_copy_created(this); }
|
186 |
+
B(B &&) noexcept : std::enable_shared_from_this<B>() { print_move_created(this); }
|
187 |
+
~B() { print_destroyed(this); }
|
188 |
+
};
|
189 |
+
|
190 |
+
B value = {};
|
191 |
+
std::shared_ptr<B> shared = std::make_shared<B>();
|
192 |
+
};
|
193 |
+
|
194 |
+
// Issue #865: shared_from_this doesn't work with virtual inheritance
|
195 |
+
struct SharedFromThisVBase : std::enable_shared_from_this<SharedFromThisVBase> {
|
196 |
+
SharedFromThisVBase() = default;
|
197 |
+
SharedFromThisVBase(const SharedFromThisVBase &) = default;
|
198 |
+
virtual ~SharedFromThisVBase() = default;
|
199 |
+
};
|
200 |
+
struct SharedFromThisVirt : virtual SharedFromThisVBase {};
|
201 |
+
|
202 |
+
// test_move_only_holder
|
203 |
+
struct C {
|
204 |
+
C() { print_created(this); }
|
205 |
+
~C() { print_destroyed(this); }
|
206 |
+
};
|
207 |
+
|
208 |
+
// test_holder_with_addressof_operator
|
209 |
+
struct TypeForHolderWithAddressOf {
|
210 |
+
TypeForHolderWithAddressOf() { print_created(this); }
|
211 |
+
TypeForHolderWithAddressOf(const TypeForHolderWithAddressOf &) { print_copy_created(this); }
|
212 |
+
TypeForHolderWithAddressOf(TypeForHolderWithAddressOf &&) noexcept {
|
213 |
+
print_move_created(this);
|
214 |
+
}
|
215 |
+
~TypeForHolderWithAddressOf() { print_destroyed(this); }
|
216 |
+
std::string toString() const {
|
217 |
+
return "TypeForHolderWithAddressOf[" + std::to_string(value) + "]";
|
218 |
+
}
|
219 |
+
int value = 42;
|
220 |
+
};
|
221 |
+
|
222 |
+
// test_move_only_holder_with_addressof_operator
|
223 |
+
struct TypeForMoveOnlyHolderWithAddressOf {
|
224 |
+
TypeForMoveOnlyHolderWithAddressOf(int value) : value{value} { print_created(this); }
|
225 |
+
~TypeForMoveOnlyHolderWithAddressOf() { print_destroyed(this); }
|
226 |
+
std::string toString() const {
|
227 |
+
return "MoveOnlyHolderWithAddressOf[" + std::to_string(value) + "]";
|
228 |
+
}
|
229 |
+
int value;
|
230 |
+
};
|
231 |
+
|
232 |
+
// test_smart_ptr_from_default
|
233 |
+
struct HeldByDefaultHolder { };
|
234 |
+
|
235 |
+
// test_shared_ptr_gc
|
236 |
+
// #187: issue involving std::shared_ptr<> return value policy & garbage collection
|
237 |
+
struct ElementBase {
|
238 |
+
virtual ~ElementBase() = default; /* Force creation of virtual table */
|
239 |
+
ElementBase() = default;
|
240 |
+
ElementBase(const ElementBase&) = delete;
|
241 |
+
};
|
242 |
+
|
243 |
+
struct ElementA : ElementBase {
|
244 |
+
ElementA(int v) : v(v) { }
|
245 |
+
int value() const { return v; }
|
246 |
+
int v;
|
247 |
+
};
|
248 |
+
|
249 |
+
struct ElementList {
|
250 |
+
void add(const std::shared_ptr<ElementBase> &e) { l.push_back(e); }
|
251 |
+
std::vector<std::shared_ptr<ElementBase>> l;
|
252 |
+
};
|
253 |
+
|
254 |
+
} // namespace
|
255 |
+
|
256 |
+
// ref<T> is a wrapper for 'Object' which uses intrusive reference counting
|
257 |
+
// It is always possible to construct a ref<T> from an Object* pointer without
|
258 |
+
// possible inconsistencies, hence the 'true' argument at the end.
|
259 |
+
// Make pybind11 aware of the non-standard getter member function
|
260 |
+
namespace pybind11 { namespace detail {
|
261 |
+
template <typename T>
|
262 |
+
struct holder_helper<ref<T>> {
|
263 |
+
static const T *get(const ref<T> &p) { return p.get_ptr(); }
|
264 |
+
};
|
265 |
+
} // namespace detail
|
266 |
+
} // namespace pybind11
|
267 |
+
|
268 |
+
// Make pybind aware of the ref-counted wrapper type (s):
|
269 |
+
PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true);
|
270 |
+
// The following is not required anymore for std::shared_ptr, but it should compile without error:
|
271 |
+
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
272 |
+
PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>);
|
273 |
+
PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
|
274 |
+
PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>);
|
275 |
+
PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>);
|
276 |
+
|
277 |
+
TEST_SUBMODULE(smart_ptr, m) {
|
278 |
+
// Please do not interleave `struct` and `class` definitions with bindings code,
|
279 |
+
// but implement `struct`s and `class`es in the anonymous namespace above.
|
280 |
+
// This helps keeping the smart_holder branch in sync with master.
|
281 |
+
|
282 |
+
// test_smart_ptr
|
283 |
+
|
284 |
+
// Object implementation in `object.h`
|
285 |
+
py::class_<Object, ref<Object>> obj(m, "Object");
|
286 |
+
obj.def("getRefCount", &Object::getRefCount);
|
287 |
+
|
288 |
+
py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj)
|
289 |
+
.def(py::init<int>());
|
290 |
+
py::implicitly_convertible<py::int_, MyObject1>();
|
291 |
+
|
292 |
+
m.def("make_object_1", []() -> Object * { return new MyObject1(1); });
|
293 |
+
m.def("make_object_2", []() -> ref<Object> { return new MyObject1(2); });
|
294 |
+
m.def("make_myobject1_1", []() -> MyObject1 * { return new MyObject1(4); });
|
295 |
+
m.def("make_myobject1_2", []() -> ref<MyObject1> { return new MyObject1(5); });
|
296 |
+
m.def("print_object_1", [](const Object *obj) { py::print(obj->toString()); });
|
297 |
+
m.def("print_object_2", [](ref<Object> obj) { py::print(obj->toString()); });
|
298 |
+
m.def("print_object_3", [](const ref<Object> &obj) { py::print(obj->toString()); });
|
299 |
+
m.def("print_object_4", [](const ref<Object> *obj) { py::print((*obj)->toString()); });
|
300 |
+
m.def("print_myobject1_1", [](const MyObject1 *obj) { py::print(obj->toString()); });
|
301 |
+
m.def("print_myobject1_2", [](ref<MyObject1> obj) { py::print(obj->toString()); });
|
302 |
+
m.def("print_myobject1_3", [](const ref<MyObject1> &obj) { py::print(obj->toString()); });
|
303 |
+
m.def("print_myobject1_4", [](const ref<MyObject1> *obj) { py::print((*obj)->toString()); });
|
304 |
+
|
305 |
+
// Expose constructor stats for the ref type
|
306 |
+
m.def("cstats_ref", &ConstructorStats::get<ref_tag>);
|
307 |
+
|
308 |
+
py::class_<MyObject2, std::shared_ptr<MyObject2>>(m, "MyObject2")
|
309 |
+
.def(py::init<int>());
|
310 |
+
m.def("make_myobject2_1", []() { return new MyObject2(6); });
|
311 |
+
m.def("make_myobject2_2", []() { return std::make_shared<MyObject2>(7); });
|
312 |
+
m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); });
|
313 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
314 |
+
m.def("print_myobject2_2", [](std::shared_ptr<MyObject2> obj) { py::print(obj->toString()); });
|
315 |
+
m.def("print_myobject2_3", [](const std::shared_ptr<MyObject2> &obj) { py::print(obj->toString()); });
|
316 |
+
m.def("print_myobject2_4", [](const std::shared_ptr<MyObject2> *obj) { py::print((*obj)->toString()); });
|
317 |
+
|
318 |
+
py::class_<MyObject3, std::shared_ptr<MyObject3>>(m, "MyObject3")
|
319 |
+
.def(py::init<int>());
|
320 |
+
m.def("make_myobject3_1", []() { return new MyObject3(8); });
|
321 |
+
m.def("make_myobject3_2", []() { return std::make_shared<MyObject3>(9); });
|
322 |
+
m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); });
|
323 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
324 |
+
m.def("print_myobject3_2", [](std::shared_ptr<MyObject3> obj) { py::print(obj->toString()); });
|
325 |
+
m.def("print_myobject3_3", [](const std::shared_ptr<MyObject3> &obj) { py::print(obj->toString()); });
|
326 |
+
m.def("print_myobject3_4", [](const std::shared_ptr<MyObject3> *obj) { py::print((*obj)->toString()); });
|
327 |
+
|
328 |
+
// test_smart_ptr_refcounting
|
329 |
+
m.def("test_object1_refcounting", []() {
|
330 |
+
ref<MyObject1> o = new MyObject1(0);
|
331 |
+
bool good = o->getRefCount() == 1;
|
332 |
+
py::object o2 = py::cast(o, py::return_value_policy::reference);
|
333 |
+
// always request (partial) ownership for objects with intrusive
|
334 |
+
// reference counting even when using the 'reference' RVP
|
335 |
+
good &= o->getRefCount() == 2;
|
336 |
+
return good;
|
337 |
+
});
|
338 |
+
|
339 |
+
// test_unique_nodelete
|
340 |
+
py::class_<MyObject4, std::unique_ptr<MyObject4, py::nodelete>>(m, "MyObject4")
|
341 |
+
.def(py::init<int>())
|
342 |
+
.def_readwrite("value", &MyObject4::value)
|
343 |
+
.def_static("cleanup_all_instances", &MyObject4::cleanupAllInstances);
|
344 |
+
|
345 |
+
// test_unique_deleter
|
346 |
+
py::class_<MyObject4a, std::unique_ptr<MyObject4a, py::nodelete>>(m, "MyObject4a")
|
347 |
+
.def(py::init<int>())
|
348 |
+
.def_readwrite("value", &MyObject4a::value)
|
349 |
+
.def_static("cleanup_all_instances", &MyObject4a::cleanupAllInstances);
|
350 |
+
|
351 |
+
py::class_<MyObject4b, MyObject4a, std::unique_ptr<MyObject4b>>(m, "MyObject4b")
|
352 |
+
.def(py::init<int>());
|
353 |
+
|
354 |
+
// test_large_holder
|
355 |
+
py::class_<MyObject5, huge_unique_ptr<MyObject5>>(m, "MyObject5")
|
356 |
+
.def(py::init<int>())
|
357 |
+
.def_readwrite("value", &MyObject5::value);
|
358 |
+
|
359 |
+
// test_shared_ptr_and_references
|
360 |
+
using A = SharedPtrRef::A;
|
361 |
+
py::class_<A, std::shared_ptr<A>>(m, "A");
|
362 |
+
py::class_<SharedPtrRef, std::unique_ptr<SharedPtrRef>>(m, "SharedPtrRef")
|
363 |
+
.def(py::init<>())
|
364 |
+
.def_readonly("ref", &SharedPtrRef::value)
|
365 |
+
.def_property_readonly(
|
366 |
+
"copy", [](const SharedPtrRef &s) { return s.value; }, py::return_value_policy::copy)
|
367 |
+
.def_readonly("holder_ref", &SharedPtrRef::shared)
|
368 |
+
.def_property_readonly(
|
369 |
+
"holder_copy",
|
370 |
+
[](const SharedPtrRef &s) { return s.shared; },
|
371 |
+
py::return_value_policy::copy)
|
372 |
+
.def("set_ref", [](SharedPtrRef &, const A &) { return true; })
|
373 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
374 |
+
.def("set_holder", [](SharedPtrRef &, std::shared_ptr<A>) { return true; });
|
375 |
+
|
376 |
+
// test_shared_ptr_from_this_and_references
|
377 |
+
using B = SharedFromThisRef::B;
|
378 |
+
py::class_<B, std::shared_ptr<B>>(m, "B");
|
379 |
+
py::class_<SharedFromThisRef, std::unique_ptr<SharedFromThisRef>>(m, "SharedFromThisRef")
|
380 |
+
.def(py::init<>())
|
381 |
+
.def_readonly("bad_wp", &SharedFromThisRef::value)
|
382 |
+
.def_property_readonly("ref",
|
383 |
+
[](const SharedFromThisRef &s) -> const B & { return *s.shared; })
|
384 |
+
.def_property_readonly(
|
385 |
+
"copy",
|
386 |
+
[](const SharedFromThisRef &s) { return s.value; },
|
387 |
+
py::return_value_policy::copy)
|
388 |
+
.def_readonly("holder_ref", &SharedFromThisRef::shared)
|
389 |
+
.def_property_readonly(
|
390 |
+
"holder_copy",
|
391 |
+
[](const SharedFromThisRef &s) { return s.shared; },
|
392 |
+
py::return_value_policy::copy)
|
393 |
+
.def("set_ref", [](SharedFromThisRef &, const B &) { return true; })
|
394 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
395 |
+
.def("set_holder", [](SharedFromThisRef &, std::shared_ptr<B>) { return true; });
|
396 |
+
|
397 |
+
// Issue #865: shared_from_this doesn't work with virtual inheritance
|
398 |
+
static std::shared_ptr<SharedFromThisVirt> sft(new SharedFromThisVirt());
|
399 |
+
py::class_<SharedFromThisVirt, std::shared_ptr<SharedFromThisVirt>>(m, "SharedFromThisVirt")
|
400 |
+
.def_static("get", []() { return sft.get(); });
|
401 |
+
|
402 |
+
// test_move_only_holder
|
403 |
+
py::class_<C, custom_unique_ptr<C>>(m, "TypeWithMoveOnlyHolder")
|
404 |
+
.def_static("make", []() { return custom_unique_ptr<C>(new C); })
|
405 |
+
.def_static("make_as_object", []() { return py::cast(custom_unique_ptr<C>(new C)); });
|
406 |
+
|
407 |
+
// test_holder_with_addressof_operator
|
408 |
+
using HolderWithAddressOf = shared_ptr_with_addressof_operator<TypeForHolderWithAddressOf>;
|
409 |
+
py::class_<TypeForHolderWithAddressOf, HolderWithAddressOf>(m, "TypeForHolderWithAddressOf")
|
410 |
+
.def_static("make", []() { return HolderWithAddressOf(new TypeForHolderWithAddressOf); })
|
411 |
+
.def("get", [](const HolderWithAddressOf &self) { return self.get(); })
|
412 |
+
.def("print_object_1",
|
413 |
+
[](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); })
|
414 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
415 |
+
.def("print_object_2", [](HolderWithAddressOf obj) { py::print(obj.get()->toString()); })
|
416 |
+
.def("print_object_3",
|
417 |
+
[](const HolderWithAddressOf &obj) { py::print(obj.get()->toString()); })
|
418 |
+
.def("print_object_4",
|
419 |
+
[](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); });
|
420 |
+
|
421 |
+
// test_move_only_holder_with_addressof_operator
|
422 |
+
using MoveOnlyHolderWithAddressOf = unique_ptr_with_addressof_operator<TypeForMoveOnlyHolderWithAddressOf>;
|
423 |
+
py::class_<TypeForMoveOnlyHolderWithAddressOf, MoveOnlyHolderWithAddressOf>(m, "TypeForMoveOnlyHolderWithAddressOf")
|
424 |
+
.def_static("make", []() { return MoveOnlyHolderWithAddressOf(new TypeForMoveOnlyHolderWithAddressOf(0)); })
|
425 |
+
.def_readwrite("value", &TypeForMoveOnlyHolderWithAddressOf::value)
|
426 |
+
.def("print_object", [](const TypeForMoveOnlyHolderWithAddressOf *obj) { py::print(obj->toString()); });
|
427 |
+
|
428 |
+
// test_smart_ptr_from_default
|
429 |
+
py::class_<HeldByDefaultHolder, std::unique_ptr<HeldByDefaultHolder>>(m, "HeldByDefaultHolder")
|
430 |
+
.def(py::init<>())
|
431 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
432 |
+
.def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {});
|
433 |
+
|
434 |
+
// test_shared_ptr_gc
|
435 |
+
// #187: issue involving std::shared_ptr<> return value policy & garbage collection
|
436 |
+
py::class_<ElementBase, std::shared_ptr<ElementBase>>(m, "ElementBase");
|
437 |
+
|
438 |
+
py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m, "ElementA")
|
439 |
+
.def(py::init<int>())
|
440 |
+
.def("value", &ElementA::value);
|
441 |
+
|
442 |
+
py::class_<ElementList, std::shared_ptr<ElementList>>(m, "ElementList")
|
443 |
+
.def(py::init<>())
|
444 |
+
.def("add", &ElementList::add)
|
445 |
+
.def("get", [](ElementList &el) {
|
446 |
+
py::list list;
|
447 |
+
for (auto &e : el.l)
|
448 |
+
list.append(py::cast(e));
|
449 |
+
return list;
|
450 |
+
});
|
451 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_smart_ptr.py
ADDED
@@ -0,0 +1,318 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
m = pytest.importorskip("pybind11_tests.smart_ptr")
|
5 |
+
from pybind11_tests import ConstructorStats # noqa: E402
|
6 |
+
|
7 |
+
|
8 |
+
def test_smart_ptr(capture):
|
9 |
+
# Object1
|
10 |
+
for i, o in enumerate(
|
11 |
+
[m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1
|
12 |
+
):
|
13 |
+
assert o.getRefCount() == 1
|
14 |
+
with capture:
|
15 |
+
m.print_object_1(o)
|
16 |
+
m.print_object_2(o)
|
17 |
+
m.print_object_3(o)
|
18 |
+
m.print_object_4(o)
|
19 |
+
assert capture == "MyObject1[{i}]\n".format(i=i) * 4
|
20 |
+
|
21 |
+
for i, o in enumerate(
|
22 |
+
[m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], start=4
|
23 |
+
):
|
24 |
+
print(o)
|
25 |
+
with capture:
|
26 |
+
if not isinstance(o, int):
|
27 |
+
m.print_object_1(o)
|
28 |
+
m.print_object_2(o)
|
29 |
+
m.print_object_3(o)
|
30 |
+
m.print_object_4(o)
|
31 |
+
m.print_myobject1_1(o)
|
32 |
+
m.print_myobject1_2(o)
|
33 |
+
m.print_myobject1_3(o)
|
34 |
+
m.print_myobject1_4(o)
|
35 |
+
|
36 |
+
times = 4 if isinstance(o, int) else 8
|
37 |
+
assert capture == "MyObject1[{i}]\n".format(i=i) * times
|
38 |
+
|
39 |
+
cstats = ConstructorStats.get(m.MyObject1)
|
40 |
+
assert cstats.alive() == 0
|
41 |
+
expected_values = ["MyObject1[{}]".format(i) for i in range(1, 7)] + [
|
42 |
+
"MyObject1[7]"
|
43 |
+
] * 4
|
44 |
+
assert cstats.values() == expected_values
|
45 |
+
assert cstats.default_constructions == 0
|
46 |
+
assert cstats.copy_constructions == 0
|
47 |
+
# assert cstats.move_constructions >= 0 # Doesn't invoke any
|
48 |
+
assert cstats.copy_assignments == 0
|
49 |
+
assert cstats.move_assignments == 0
|
50 |
+
|
51 |
+
# Object2
|
52 |
+
for i, o in zip(
|
53 |
+
[8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]
|
54 |
+
):
|
55 |
+
print(o)
|
56 |
+
with capture:
|
57 |
+
m.print_myobject2_1(o)
|
58 |
+
m.print_myobject2_2(o)
|
59 |
+
m.print_myobject2_3(o)
|
60 |
+
m.print_myobject2_4(o)
|
61 |
+
assert capture == "MyObject2[{i}]\n".format(i=i) * 4
|
62 |
+
|
63 |
+
cstats = ConstructorStats.get(m.MyObject2)
|
64 |
+
assert cstats.alive() == 1
|
65 |
+
o = None
|
66 |
+
assert cstats.alive() == 0
|
67 |
+
assert cstats.values() == ["MyObject2[8]", "MyObject2[6]", "MyObject2[7]"]
|
68 |
+
assert cstats.default_constructions == 0
|
69 |
+
assert cstats.copy_constructions == 0
|
70 |
+
# assert cstats.move_constructions >= 0 # Doesn't invoke any
|
71 |
+
assert cstats.copy_assignments == 0
|
72 |
+
assert cstats.move_assignments == 0
|
73 |
+
|
74 |
+
# Object3
|
75 |
+
for i, o in zip(
|
76 |
+
[9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]
|
77 |
+
):
|
78 |
+
print(o)
|
79 |
+
with capture:
|
80 |
+
m.print_myobject3_1(o)
|
81 |
+
m.print_myobject3_2(o)
|
82 |
+
m.print_myobject3_3(o)
|
83 |
+
m.print_myobject3_4(o)
|
84 |
+
assert capture == "MyObject3[{i}]\n".format(i=i) * 4
|
85 |
+
|
86 |
+
cstats = ConstructorStats.get(m.MyObject3)
|
87 |
+
assert cstats.alive() == 1
|
88 |
+
o = None
|
89 |
+
assert cstats.alive() == 0
|
90 |
+
assert cstats.values() == ["MyObject3[9]", "MyObject3[8]", "MyObject3[9]"]
|
91 |
+
assert cstats.default_constructions == 0
|
92 |
+
assert cstats.copy_constructions == 0
|
93 |
+
# assert cstats.move_constructions >= 0 # Doesn't invoke any
|
94 |
+
assert cstats.copy_assignments == 0
|
95 |
+
assert cstats.move_assignments == 0
|
96 |
+
|
97 |
+
# Object
|
98 |
+
cstats = ConstructorStats.get(m.Object)
|
99 |
+
assert cstats.alive() == 0
|
100 |
+
assert cstats.values() == []
|
101 |
+
assert cstats.default_constructions == 10
|
102 |
+
assert cstats.copy_constructions == 0
|
103 |
+
# assert cstats.move_constructions >= 0 # Doesn't invoke any
|
104 |
+
assert cstats.copy_assignments == 0
|
105 |
+
assert cstats.move_assignments == 0
|
106 |
+
|
107 |
+
# ref<>
|
108 |
+
cstats = m.cstats_ref()
|
109 |
+
assert cstats.alive() == 0
|
110 |
+
assert cstats.values() == ["from pointer"] * 10
|
111 |
+
assert cstats.default_constructions == 30
|
112 |
+
assert cstats.copy_constructions == 12
|
113 |
+
# assert cstats.move_constructions >= 0 # Doesn't invoke any
|
114 |
+
assert cstats.copy_assignments == 30
|
115 |
+
assert cstats.move_assignments == 0
|
116 |
+
|
117 |
+
|
118 |
+
def test_smart_ptr_refcounting():
|
119 |
+
assert m.test_object1_refcounting()
|
120 |
+
|
121 |
+
|
122 |
+
def test_unique_nodelete():
|
123 |
+
o = m.MyObject4(23)
|
124 |
+
assert o.value == 23
|
125 |
+
cstats = ConstructorStats.get(m.MyObject4)
|
126 |
+
assert cstats.alive() == 1
|
127 |
+
del o
|
128 |
+
assert cstats.alive() == 1
|
129 |
+
m.MyObject4.cleanup_all_instances()
|
130 |
+
assert cstats.alive() == 0
|
131 |
+
|
132 |
+
|
133 |
+
def test_unique_nodelete4a():
|
134 |
+
o = m.MyObject4a(23)
|
135 |
+
assert o.value == 23
|
136 |
+
cstats = ConstructorStats.get(m.MyObject4a)
|
137 |
+
assert cstats.alive() == 1
|
138 |
+
del o
|
139 |
+
assert cstats.alive() == 1
|
140 |
+
m.MyObject4a.cleanup_all_instances()
|
141 |
+
assert cstats.alive() == 0
|
142 |
+
|
143 |
+
|
144 |
+
def test_unique_deleter():
|
145 |
+
m.MyObject4a(0)
|
146 |
+
o = m.MyObject4b(23)
|
147 |
+
assert o.value == 23
|
148 |
+
cstats4a = ConstructorStats.get(m.MyObject4a)
|
149 |
+
assert cstats4a.alive() == 2
|
150 |
+
cstats4b = ConstructorStats.get(m.MyObject4b)
|
151 |
+
assert cstats4b.alive() == 1
|
152 |
+
del o
|
153 |
+
assert cstats4a.alive() == 1 # Should now only be one leftover
|
154 |
+
assert cstats4b.alive() == 0 # Should be deleted
|
155 |
+
m.MyObject4a.cleanup_all_instances()
|
156 |
+
assert cstats4a.alive() == 0
|
157 |
+
assert cstats4b.alive() == 0
|
158 |
+
|
159 |
+
|
160 |
+
def test_large_holder():
|
161 |
+
o = m.MyObject5(5)
|
162 |
+
assert o.value == 5
|
163 |
+
cstats = ConstructorStats.get(m.MyObject5)
|
164 |
+
assert cstats.alive() == 1
|
165 |
+
del o
|
166 |
+
assert cstats.alive() == 0
|
167 |
+
|
168 |
+
|
169 |
+
def test_shared_ptr_and_references():
|
170 |
+
s = m.SharedPtrRef()
|
171 |
+
stats = ConstructorStats.get(m.A)
|
172 |
+
assert stats.alive() == 2
|
173 |
+
|
174 |
+
ref = s.ref # init_holder_helper(holder_ptr=false, owned=false)
|
175 |
+
assert stats.alive() == 2
|
176 |
+
assert s.set_ref(ref)
|
177 |
+
with pytest.raises(RuntimeError) as excinfo:
|
178 |
+
assert s.set_holder(ref)
|
179 |
+
assert "Unable to cast from non-held to held instance" in str(excinfo.value)
|
180 |
+
|
181 |
+
copy = s.copy # init_holder_helper(holder_ptr=false, owned=true)
|
182 |
+
assert stats.alive() == 3
|
183 |
+
assert s.set_ref(copy)
|
184 |
+
assert s.set_holder(copy)
|
185 |
+
|
186 |
+
holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false)
|
187 |
+
assert stats.alive() == 3
|
188 |
+
assert s.set_ref(holder_ref)
|
189 |
+
assert s.set_holder(holder_ref)
|
190 |
+
|
191 |
+
holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true)
|
192 |
+
assert stats.alive() == 3
|
193 |
+
assert s.set_ref(holder_copy)
|
194 |
+
assert s.set_holder(holder_copy)
|
195 |
+
|
196 |
+
del ref, copy, holder_ref, holder_copy, s
|
197 |
+
assert stats.alive() == 0
|
198 |
+
|
199 |
+
|
200 |
+
def test_shared_ptr_from_this_and_references():
|
201 |
+
s = m.SharedFromThisRef()
|
202 |
+
stats = ConstructorStats.get(m.B)
|
203 |
+
assert stats.alive() == 2
|
204 |
+
|
205 |
+
ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
|
206 |
+
assert stats.alive() == 2
|
207 |
+
assert s.set_ref(ref)
|
208 |
+
assert s.set_holder(
|
209 |
+
ref
|
210 |
+
) # std::enable_shared_from_this can create a holder from a reference
|
211 |
+
|
212 |
+
bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
|
213 |
+
assert stats.alive() == 2
|
214 |
+
assert s.set_ref(bad_wp)
|
215 |
+
with pytest.raises(RuntimeError) as excinfo:
|
216 |
+
assert s.set_holder(bad_wp)
|
217 |
+
assert "Unable to cast from non-held to held instance" in str(excinfo.value)
|
218 |
+
|
219 |
+
copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false)
|
220 |
+
assert stats.alive() == 3
|
221 |
+
assert s.set_ref(copy)
|
222 |
+
assert s.set_holder(copy)
|
223 |
+
|
224 |
+
holder_ref = (
|
225 |
+
s.holder_ref
|
226 |
+
) # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
|
227 |
+
assert stats.alive() == 3
|
228 |
+
assert s.set_ref(holder_ref)
|
229 |
+
assert s.set_holder(holder_ref)
|
230 |
+
|
231 |
+
holder_copy = (
|
232 |
+
s.holder_copy
|
233 |
+
) # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
|
234 |
+
assert stats.alive() == 3
|
235 |
+
assert s.set_ref(holder_copy)
|
236 |
+
assert s.set_holder(holder_copy)
|
237 |
+
|
238 |
+
del ref, bad_wp, copy, holder_ref, holder_copy, s
|
239 |
+
assert stats.alive() == 0
|
240 |
+
|
241 |
+
z = m.SharedFromThisVirt.get()
|
242 |
+
y = m.SharedFromThisVirt.get()
|
243 |
+
assert y is z
|
244 |
+
|
245 |
+
|
246 |
+
def test_move_only_holder():
|
247 |
+
a = m.TypeWithMoveOnlyHolder.make()
|
248 |
+
b = m.TypeWithMoveOnlyHolder.make_as_object()
|
249 |
+
stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder)
|
250 |
+
assert stats.alive() == 2
|
251 |
+
del b
|
252 |
+
assert stats.alive() == 1
|
253 |
+
del a
|
254 |
+
assert stats.alive() == 0
|
255 |
+
|
256 |
+
|
257 |
+
def test_holder_with_addressof_operator():
|
258 |
+
# this test must not throw exception from c++
|
259 |
+
a = m.TypeForHolderWithAddressOf.make()
|
260 |
+
a.print_object_1()
|
261 |
+
a.print_object_2()
|
262 |
+
a.print_object_3()
|
263 |
+
a.print_object_4()
|
264 |
+
|
265 |
+
stats = ConstructorStats.get(m.TypeForHolderWithAddressOf)
|
266 |
+
assert stats.alive() == 1
|
267 |
+
|
268 |
+
np = m.TypeForHolderWithAddressOf.make()
|
269 |
+
assert stats.alive() == 2
|
270 |
+
del a
|
271 |
+
assert stats.alive() == 1
|
272 |
+
del np
|
273 |
+
assert stats.alive() == 0
|
274 |
+
|
275 |
+
b = m.TypeForHolderWithAddressOf.make()
|
276 |
+
c = b
|
277 |
+
assert b.get() is c.get()
|
278 |
+
assert stats.alive() == 1
|
279 |
+
|
280 |
+
del b
|
281 |
+
assert stats.alive() == 1
|
282 |
+
|
283 |
+
del c
|
284 |
+
assert stats.alive() == 0
|
285 |
+
|
286 |
+
|
287 |
+
def test_move_only_holder_with_addressof_operator():
|
288 |
+
a = m.TypeForMoveOnlyHolderWithAddressOf.make()
|
289 |
+
a.print_object()
|
290 |
+
|
291 |
+
stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf)
|
292 |
+
assert stats.alive() == 1
|
293 |
+
|
294 |
+
a.value = 42
|
295 |
+
assert a.value == 42
|
296 |
+
|
297 |
+
del a
|
298 |
+
assert stats.alive() == 0
|
299 |
+
|
300 |
+
|
301 |
+
def test_smart_ptr_from_default():
|
302 |
+
instance = m.HeldByDefaultHolder()
|
303 |
+
with pytest.raises(RuntimeError) as excinfo:
|
304 |
+
m.HeldByDefaultHolder.load_shared_ptr(instance)
|
305 |
+
assert (
|
306 |
+
"Unable to load a custom holder type from a "
|
307 |
+
"default-holder instance" in str(excinfo.value)
|
308 |
+
)
|
309 |
+
|
310 |
+
|
311 |
+
def test_shared_ptr_gc():
|
312 |
+
"""#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
|
313 |
+
el = m.ElementList()
|
314 |
+
for i in range(10):
|
315 |
+
el.add(m.ElementA(i))
|
316 |
+
pytest.gc_collect()
|
317 |
+
for i, v in enumerate(el.get()):
|
318 |
+
assert i == v.value()
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_stl.cpp
ADDED
@@ -0,0 +1,341 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_stl.cpp -- STL type casters
|
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 "constructor_stats.h"
|
12 |
+
#include <pybind11/stl.h>
|
13 |
+
|
14 |
+
#ifndef PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL
|
15 |
+
#define PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL
|
16 |
+
#endif
|
17 |
+
#include <pybind11/stl/filesystem.h>
|
18 |
+
|
19 |
+
#include <vector>
|
20 |
+
#include <string>
|
21 |
+
|
22 |
+
// Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14
|
23 |
+
#if defined(PYBIND11_HAS_VARIANT)
|
24 |
+
using std::variant;
|
25 |
+
#elif defined(PYBIND11_TEST_BOOST) && (!defined(_MSC_VER) || _MSC_VER >= 1910)
|
26 |
+
# include <boost/variant.hpp>
|
27 |
+
# define PYBIND11_HAS_VARIANT 1
|
28 |
+
using boost::variant;
|
29 |
+
|
30 |
+
namespace pybind11 { namespace detail {
|
31 |
+
template <typename... Ts>
|
32 |
+
struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};
|
33 |
+
|
34 |
+
template <>
|
35 |
+
struct visit_helper<boost::variant> {
|
36 |
+
template <typename... Args>
|
37 |
+
static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) {
|
38 |
+
return boost::apply_visitor(args...);
|
39 |
+
}
|
40 |
+
};
|
41 |
+
}} // namespace pybind11::detail
|
42 |
+
#endif
|
43 |
+
|
44 |
+
PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>);
|
45 |
+
|
46 |
+
/// Issue #528: templated constructor
|
47 |
+
struct TplCtorClass {
|
48 |
+
template <typename T> TplCtorClass(const T &) { }
|
49 |
+
bool operator==(const TplCtorClass &) const { return true; }
|
50 |
+
};
|
51 |
+
|
52 |
+
namespace std {
|
53 |
+
template <>
|
54 |
+
struct hash<TplCtorClass> { size_t operator()(const TplCtorClass &) const { return 0; } };
|
55 |
+
} // namespace std
|
56 |
+
|
57 |
+
|
58 |
+
template <template <typename> class OptionalImpl, typename T>
|
59 |
+
struct OptionalHolder
|
60 |
+
{
|
61 |
+
OptionalHolder() = default;
|
62 |
+
bool member_initialized() const {
|
63 |
+
return member && member->initialized;
|
64 |
+
}
|
65 |
+
OptionalImpl<T> member = T{};
|
66 |
+
};
|
67 |
+
|
68 |
+
|
69 |
+
TEST_SUBMODULE(stl, m) {
|
70 |
+
// test_vector
|
71 |
+
m.def("cast_vector", []() { return std::vector<int>{1}; });
|
72 |
+
m.def("load_vector", [](const std::vector<int> &v) { return v.at(0) == 1 && v.at(1) == 2; });
|
73 |
+
// `std::vector<bool>` is special because it returns proxy objects instead of references
|
74 |
+
m.def("cast_bool_vector", []() { return std::vector<bool>{true, false}; });
|
75 |
+
m.def("load_bool_vector", [](const std::vector<bool> &v) {
|
76 |
+
return v.at(0) == true && v.at(1) == false;
|
77 |
+
});
|
78 |
+
// Unnumbered regression (caused by #936): pointers to stl containers aren't castable
|
79 |
+
static std::vector<RValueCaster> lvv{2};
|
80 |
+
m.def("cast_ptr_vector", []() { return &lvv; });
|
81 |
+
|
82 |
+
// test_deque
|
83 |
+
m.def("cast_deque", []() { return std::deque<int>{1}; });
|
84 |
+
m.def("load_deque", [](const std::deque<int> &v) { return v.at(0) == 1 && v.at(1) == 2; });
|
85 |
+
|
86 |
+
// test_array
|
87 |
+
m.def("cast_array", []() { return std::array<int, 2> {{1 , 2}}; });
|
88 |
+
m.def("load_array", [](const std::array<int, 2> &a) { return a[0] == 1 && a[1] == 2; });
|
89 |
+
|
90 |
+
// test_valarray
|
91 |
+
m.def("cast_valarray", []() { return std::valarray<int>{1, 4, 9}; });
|
92 |
+
m.def("load_valarray", [](const std::valarray<int>& v) {
|
93 |
+
return v.size() == 3 && v[0] == 1 && v[1] == 4 && v[2] == 9;
|
94 |
+
});
|
95 |
+
|
96 |
+
// test_map
|
97 |
+
m.def("cast_map", []() { return std::map<std::string, std::string>{{"key", "value"}}; });
|
98 |
+
m.def("load_map", [](const std::map<std::string, std::string> &map) {
|
99 |
+
return map.at("key") == "value" && map.at("key2") == "value2";
|
100 |
+
});
|
101 |
+
|
102 |
+
// test_set
|
103 |
+
m.def("cast_set", []() { return std::set<std::string>{"key1", "key2"}; });
|
104 |
+
m.def("load_set", [](const std::set<std::string> &set) {
|
105 |
+
return (set.count("key1") != 0u) && (set.count("key2") != 0u) && (set.count("key3") != 0u);
|
106 |
+
});
|
107 |
+
|
108 |
+
// test_recursive_casting
|
109 |
+
m.def("cast_rv_vector", []() { return std::vector<RValueCaster>{2}; });
|
110 |
+
m.def("cast_rv_array", []() { return std::array<RValueCaster, 3>(); });
|
111 |
+
// NB: map and set keys are `const`, so while we technically do move them (as `const Type &&`),
|
112 |
+
// casters don't typically do anything with that, which means they fall to the `const Type &`
|
113 |
+
// caster.
|
114 |
+
m.def("cast_rv_map", []() { return std::unordered_map<std::string, RValueCaster>{{"a", RValueCaster{}}}; });
|
115 |
+
m.def("cast_rv_nested", []() {
|
116 |
+
std::vector<std::array<std::list<std::unordered_map<std::string, RValueCaster>>, 2>> v;
|
117 |
+
v.emplace_back(); // add an array
|
118 |
+
v.back()[0].emplace_back(); // add a map to the array
|
119 |
+
v.back()[0].back().emplace("b", RValueCaster{});
|
120 |
+
v.back()[0].back().emplace("c", RValueCaster{});
|
121 |
+
v.back()[1].emplace_back(); // add a map to the array
|
122 |
+
v.back()[1].back().emplace("a", RValueCaster{});
|
123 |
+
return v;
|
124 |
+
});
|
125 |
+
static std::array<RValueCaster, 2> lva;
|
126 |
+
static std::unordered_map<std::string, RValueCaster> lvm{{"a", RValueCaster{}}, {"b", RValueCaster{}}};
|
127 |
+
static std::unordered_map<std::string, std::vector<std::list<std::array<RValueCaster, 2>>>> lvn;
|
128 |
+
lvn["a"].emplace_back(); // add a list
|
129 |
+
lvn["a"].back().emplace_back(); // add an array
|
130 |
+
lvn["a"].emplace_back(); // another list
|
131 |
+
lvn["a"].back().emplace_back(); // add an array
|
132 |
+
lvn["b"].emplace_back(); // add a list
|
133 |
+
lvn["b"].back().emplace_back(); // add an array
|
134 |
+
lvn["b"].back().emplace_back(); // add another array
|
135 |
+
m.def("cast_lv_vector", []() -> const decltype(lvv) & { return lvv; });
|
136 |
+
m.def("cast_lv_array", []() -> const decltype(lva) & { return lva; });
|
137 |
+
m.def("cast_lv_map", []() -> const decltype(lvm) & { return lvm; });
|
138 |
+
m.def("cast_lv_nested", []() -> const decltype(lvn) & { return lvn; });
|
139 |
+
// #853:
|
140 |
+
m.def("cast_unique_ptr_vector", []() {
|
141 |
+
std::vector<std::unique_ptr<UserType>> v;
|
142 |
+
v.emplace_back(new UserType{7});
|
143 |
+
v.emplace_back(new UserType{42});
|
144 |
+
return v;
|
145 |
+
});
|
146 |
+
|
147 |
+
// test_move_out_container
|
148 |
+
struct MoveOutContainer {
|
149 |
+
struct Value { int value; };
|
150 |
+
std::list<Value> move_list() const { return {{0}, {1}, {2}}; }
|
151 |
+
};
|
152 |
+
py::class_<MoveOutContainer::Value>(m, "MoveOutContainerValue")
|
153 |
+
.def_readonly("value", &MoveOutContainer::Value::value);
|
154 |
+
py::class_<MoveOutContainer>(m, "MoveOutContainer")
|
155 |
+
.def(py::init<>())
|
156 |
+
.def_property_readonly("move_list", &MoveOutContainer::move_list);
|
157 |
+
|
158 |
+
// Class that can be move- and copy-constructed, but not assigned
|
159 |
+
struct NoAssign {
|
160 |
+
int value;
|
161 |
+
|
162 |
+
explicit NoAssign(int value = 0) : value(value) { }
|
163 |
+
NoAssign(const NoAssign &) = default;
|
164 |
+
NoAssign(NoAssign &&) = default;
|
165 |
+
|
166 |
+
NoAssign &operator=(const NoAssign &) = delete;
|
167 |
+
NoAssign &operator=(NoAssign &&) = delete;
|
168 |
+
};
|
169 |
+
py::class_<NoAssign>(m, "NoAssign", "Class with no C++ assignment operators")
|
170 |
+
.def(py::init<>())
|
171 |
+
.def(py::init<int>());
|
172 |
+
|
173 |
+
|
174 |
+
struct MoveOutDetector
|
175 |
+
{
|
176 |
+
MoveOutDetector() = default;
|
177 |
+
MoveOutDetector(const MoveOutDetector&) = default;
|
178 |
+
MoveOutDetector(MoveOutDetector&& other) noexcept
|
179 |
+
: initialized(other.initialized) {
|
180 |
+
// steal underlying resource
|
181 |
+
other.initialized = false;
|
182 |
+
}
|
183 |
+
bool initialized = true;
|
184 |
+
};
|
185 |
+
py::class_<MoveOutDetector>(m, "MoveOutDetector", "Class with move tracking")
|
186 |
+
.def(py::init<>())
|
187 |
+
.def_readonly("initialized", &MoveOutDetector::initialized);
|
188 |
+
|
189 |
+
|
190 |
+
#ifdef PYBIND11_HAS_OPTIONAL
|
191 |
+
// test_optional
|
192 |
+
m.attr("has_optional") = true;
|
193 |
+
|
194 |
+
using opt_int = std::optional<int>;
|
195 |
+
using opt_no_assign = std::optional<NoAssign>;
|
196 |
+
m.def("double_or_zero", [](const opt_int& x) -> int {
|
197 |
+
return x.value_or(0) * 2;
|
198 |
+
});
|
199 |
+
m.def("half_or_none", [](int x) -> opt_int { return x != 0 ? opt_int(x / 2) : opt_int(); });
|
200 |
+
m.def("test_nullopt", [](opt_int x) {
|
201 |
+
return x.value_or(42);
|
202 |
+
}, py::arg_v("x", std::nullopt, "None"));
|
203 |
+
m.def("test_no_assign", [](const opt_no_assign &x) {
|
204 |
+
return x ? x->value : 42;
|
205 |
+
}, py::arg_v("x", std::nullopt, "None"));
|
206 |
+
|
207 |
+
m.def("nodefer_none_optional", [](std::optional<int>) { return true; });
|
208 |
+
m.def("nodefer_none_optional", [](const py::none &) { return false; });
|
209 |
+
|
210 |
+
using opt_holder = OptionalHolder<std::optional, MoveOutDetector>;
|
211 |
+
py::class_<opt_holder>(m, "OptionalHolder", "Class with optional member")
|
212 |
+
.def(py::init<>())
|
213 |
+
.def_readonly("member", &opt_holder::member)
|
214 |
+
.def("member_initialized", &opt_holder::member_initialized);
|
215 |
+
#endif
|
216 |
+
|
217 |
+
#ifdef PYBIND11_HAS_EXP_OPTIONAL
|
218 |
+
// test_exp_optional
|
219 |
+
m.attr("has_exp_optional") = true;
|
220 |
+
|
221 |
+
using exp_opt_int = std::experimental::optional<int>;
|
222 |
+
using exp_opt_no_assign = std::experimental::optional<NoAssign>;
|
223 |
+
m.def("double_or_zero_exp", [](const exp_opt_int& x) -> int {
|
224 |
+
return x.value_or(0) * 2;
|
225 |
+
});
|
226 |
+
m.def("half_or_none_exp", [](int x) -> exp_opt_int {
|
227 |
+
return x ? exp_opt_int(x / 2) : exp_opt_int();
|
228 |
+
});
|
229 |
+
m.def("test_nullopt_exp", [](exp_opt_int x) {
|
230 |
+
return x.value_or(42);
|
231 |
+
}, py::arg_v("x", std::experimental::nullopt, "None"));
|
232 |
+
m.def("test_no_assign_exp", [](const exp_opt_no_assign &x) {
|
233 |
+
return x ? x->value : 42;
|
234 |
+
}, py::arg_v("x", std::experimental::nullopt, "None"));
|
235 |
+
|
236 |
+
using opt_exp_holder = OptionalHolder<std::experimental::optional, MoveOutDetector>;
|
237 |
+
py::class_<opt_exp_holder>(m, "OptionalExpHolder", "Class with optional member")
|
238 |
+
.def(py::init<>())
|
239 |
+
.def_readonly("member", &opt_exp_holder::member)
|
240 |
+
.def("member_initialized", &opt_exp_holder::member_initialized);
|
241 |
+
#endif
|
242 |
+
|
243 |
+
#ifdef PYBIND11_HAS_FILESYSTEM
|
244 |
+
// test_fs_path
|
245 |
+
m.attr("has_filesystem") = true;
|
246 |
+
m.def("parent_path", [](const std::filesystem::path& p) { return p.parent_path(); });
|
247 |
+
#endif
|
248 |
+
|
249 |
+
#ifdef PYBIND11_HAS_VARIANT
|
250 |
+
static_assert(std::is_same<py::detail::variant_caster_visitor::result_type, py::handle>::value,
|
251 |
+
"visitor::result_type is required by boost::variant in C++11 mode");
|
252 |
+
|
253 |
+
struct visitor {
|
254 |
+
using result_type = const char *;
|
255 |
+
|
256 |
+
result_type operator()(int) { return "int"; }
|
257 |
+
result_type operator()(const std::string &) { return "std::string"; }
|
258 |
+
result_type operator()(double) { return "double"; }
|
259 |
+
result_type operator()(std::nullptr_t) { return "std::nullptr_t"; }
|
260 |
+
};
|
261 |
+
|
262 |
+
// test_variant
|
263 |
+
m.def("load_variant", [](const variant<int, std::string, double, std::nullptr_t> &v) {
|
264 |
+
return py::detail::visit_helper<variant>::call(visitor(), v);
|
265 |
+
});
|
266 |
+
m.def("load_variant_2pass", [](variant<double, int> v) {
|
267 |
+
return py::detail::visit_helper<variant>::call(visitor(), v);
|
268 |
+
});
|
269 |
+
m.def("cast_variant", []() {
|
270 |
+
using V = variant<int, std::string>;
|
271 |
+
return py::make_tuple(V(5), V("Hello"));
|
272 |
+
});
|
273 |
+
#endif
|
274 |
+
|
275 |
+
// #528: templated constructor
|
276 |
+
// (no python tests: the test here is that this compiles)
|
277 |
+
m.def("tpl_ctor_vector", [](std::vector<TplCtorClass> &) {});
|
278 |
+
m.def("tpl_ctor_map", [](std::unordered_map<TplCtorClass, TplCtorClass> &) {});
|
279 |
+
m.def("tpl_ctor_set", [](std::unordered_set<TplCtorClass> &) {});
|
280 |
+
#if defined(PYBIND11_HAS_OPTIONAL)
|
281 |
+
m.def("tpl_constr_optional", [](std::optional<TplCtorClass> &) {});
|
282 |
+
#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
|
283 |
+
m.def("tpl_constr_optional", [](std::experimental::optional<TplCtorClass> &) {});
|
284 |
+
#endif
|
285 |
+
|
286 |
+
// test_vec_of_reference_wrapper
|
287 |
+
// #171: Can't return STL structures containing reference wrapper
|
288 |
+
m.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<UserType> p4) {
|
289 |
+
static UserType p1{1}, p2{2}, p3{3};
|
290 |
+
return std::vector<std::reference_wrapper<UserType>> {
|
291 |
+
std::ref(p1), std::ref(p2), std::ref(p3), p4
|
292 |
+
};
|
293 |
+
});
|
294 |
+
|
295 |
+
// test_stl_pass_by_pointer
|
296 |
+
m.def("stl_pass_by_pointer", [](std::vector<int>* v) { return *v; }, "v"_a=nullptr);
|
297 |
+
|
298 |
+
// #1258: pybind11/stl.h converts string to vector<string>
|
299 |
+
m.def("func_with_string_or_vector_string_arg_overload",
|
300 |
+
[](const std::vector<std::string> &) { return 1; });
|
301 |
+
m.def("func_with_string_or_vector_string_arg_overload",
|
302 |
+
[](const std::list<std::string> &) { return 2; });
|
303 |
+
m.def("func_with_string_or_vector_string_arg_overload", [](const std::string &) { return 3; });
|
304 |
+
|
305 |
+
class Placeholder {
|
306 |
+
public:
|
307 |
+
Placeholder() { print_created(this); }
|
308 |
+
Placeholder(const Placeholder &) = delete;
|
309 |
+
~Placeholder() { print_destroyed(this); }
|
310 |
+
};
|
311 |
+
py::class_<Placeholder>(m, "Placeholder");
|
312 |
+
|
313 |
+
/// test_stl_vector_ownership
|
314 |
+
m.def("test_stl_ownership",
|
315 |
+
[]() {
|
316 |
+
std::vector<Placeholder *> result;
|
317 |
+
result.push_back(new Placeholder());
|
318 |
+
return result;
|
319 |
+
},
|
320 |
+
py::return_value_policy::take_ownership);
|
321 |
+
|
322 |
+
m.def("array_cast_sequence", [](std::array<int, 3> x) { return x; });
|
323 |
+
|
324 |
+
/// test_issue_1561
|
325 |
+
struct Issue1561Inner { std::string data; };
|
326 |
+
struct Issue1561Outer { std::vector<Issue1561Inner> list; };
|
327 |
+
|
328 |
+
py::class_<Issue1561Inner>(m, "Issue1561Inner")
|
329 |
+
.def(py::init<std::string>())
|
330 |
+
.def_readwrite("data", &Issue1561Inner::data);
|
331 |
+
|
332 |
+
py::class_<Issue1561Outer>(m, "Issue1561Outer")
|
333 |
+
.def(py::init<>())
|
334 |
+
.def_readwrite("list", &Issue1561Outer::list);
|
335 |
+
|
336 |
+
m.def(
|
337 |
+
"return_vector_bool_raw_ptr",
|
338 |
+
[]() { return new std::vector<bool>(4513); },
|
339 |
+
// Without explicitly specifying `take_ownership`, this function leaks.
|
340 |
+
py::return_value_policy::take_ownership);
|
341 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_stl.py
ADDED
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
from pybind11_tests import stl as m
|
5 |
+
from pybind11_tests import UserType
|
6 |
+
from pybind11_tests import ConstructorStats
|
7 |
+
|
8 |
+
|
9 |
+
def test_vector(doc):
|
10 |
+
"""std::vector <-> list"""
|
11 |
+
lst = m.cast_vector()
|
12 |
+
assert lst == [1]
|
13 |
+
lst.append(2)
|
14 |
+
assert m.load_vector(lst)
|
15 |
+
assert m.load_vector(tuple(lst))
|
16 |
+
|
17 |
+
assert m.cast_bool_vector() == [True, False]
|
18 |
+
assert m.load_bool_vector([True, False])
|
19 |
+
|
20 |
+
assert doc(m.cast_vector) == "cast_vector() -> List[int]"
|
21 |
+
assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool"
|
22 |
+
|
23 |
+
# Test regression caused by 936: pointers to stl containers weren't castable
|
24 |
+
assert m.cast_ptr_vector() == ["lvalue", "lvalue"]
|
25 |
+
|
26 |
+
|
27 |
+
def test_deque(doc):
|
28 |
+
"""std::deque <-> list"""
|
29 |
+
lst = m.cast_deque()
|
30 |
+
assert lst == [1]
|
31 |
+
lst.append(2)
|
32 |
+
assert m.load_deque(lst)
|
33 |
+
assert m.load_deque(tuple(lst))
|
34 |
+
|
35 |
+
|
36 |
+
def test_array(doc):
|
37 |
+
"""std::array <-> list"""
|
38 |
+
lst = m.cast_array()
|
39 |
+
assert lst == [1, 2]
|
40 |
+
assert m.load_array(lst)
|
41 |
+
|
42 |
+
assert doc(m.cast_array) == "cast_array() -> List[int[2]]"
|
43 |
+
assert doc(m.load_array) == "load_array(arg0: List[int[2]]) -> bool"
|
44 |
+
|
45 |
+
|
46 |
+
def test_valarray(doc):
|
47 |
+
"""std::valarray <-> list"""
|
48 |
+
lst = m.cast_valarray()
|
49 |
+
assert lst == [1, 4, 9]
|
50 |
+
assert m.load_valarray(lst)
|
51 |
+
|
52 |
+
assert doc(m.cast_valarray) == "cast_valarray() -> List[int]"
|
53 |
+
assert doc(m.load_valarray) == "load_valarray(arg0: List[int]) -> bool"
|
54 |
+
|
55 |
+
|
56 |
+
def test_map(doc):
|
57 |
+
"""std::map <-> dict"""
|
58 |
+
d = m.cast_map()
|
59 |
+
assert d == {"key": "value"}
|
60 |
+
assert "key" in d
|
61 |
+
d["key2"] = "value2"
|
62 |
+
assert "key2" in d
|
63 |
+
assert m.load_map(d)
|
64 |
+
|
65 |
+
assert doc(m.cast_map) == "cast_map() -> Dict[str, str]"
|
66 |
+
assert doc(m.load_map) == "load_map(arg0: Dict[str, str]) -> bool"
|
67 |
+
|
68 |
+
|
69 |
+
def test_set(doc):
|
70 |
+
"""std::set <-> set"""
|
71 |
+
s = m.cast_set()
|
72 |
+
assert s == {"key1", "key2"}
|
73 |
+
s.add("key3")
|
74 |
+
assert m.load_set(s)
|
75 |
+
|
76 |
+
assert doc(m.cast_set) == "cast_set() -> Set[str]"
|
77 |
+
assert doc(m.load_set) == "load_set(arg0: Set[str]) -> bool"
|
78 |
+
|
79 |
+
|
80 |
+
def test_recursive_casting():
|
81 |
+
"""Tests that stl casters preserve lvalue/rvalue context for container values"""
|
82 |
+
assert m.cast_rv_vector() == ["rvalue", "rvalue"]
|
83 |
+
assert m.cast_lv_vector() == ["lvalue", "lvalue"]
|
84 |
+
assert m.cast_rv_array() == ["rvalue", "rvalue", "rvalue"]
|
85 |
+
assert m.cast_lv_array() == ["lvalue", "lvalue"]
|
86 |
+
assert m.cast_rv_map() == {"a": "rvalue"}
|
87 |
+
assert m.cast_lv_map() == {"a": "lvalue", "b": "lvalue"}
|
88 |
+
assert m.cast_rv_nested() == [[[{"b": "rvalue", "c": "rvalue"}], [{"a": "rvalue"}]]]
|
89 |
+
assert m.cast_lv_nested() == {
|
90 |
+
"a": [[["lvalue", "lvalue"]], [["lvalue", "lvalue"]]],
|
91 |
+
"b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]],
|
92 |
+
}
|
93 |
+
|
94 |
+
# Issue #853 test case:
|
95 |
+
z = m.cast_unique_ptr_vector()
|
96 |
+
assert z[0].value == 7 and z[1].value == 42
|
97 |
+
|
98 |
+
|
99 |
+
def test_move_out_container():
|
100 |
+
"""Properties use the `reference_internal` policy by default. If the underlying function
|
101 |
+
returns an rvalue, the policy is automatically changed to `move` to avoid referencing
|
102 |
+
a temporary. In case the return value is a container of user-defined types, the policy
|
103 |
+
also needs to be applied to the elements, not just the container."""
|
104 |
+
c = m.MoveOutContainer()
|
105 |
+
moved_out_list = c.move_list
|
106 |
+
assert [x.value for x in moved_out_list] == [0, 1, 2]
|
107 |
+
|
108 |
+
|
109 |
+
@pytest.mark.skipif(not hasattr(m, "has_optional"), reason="no <optional>")
|
110 |
+
def test_optional():
|
111 |
+
assert m.double_or_zero(None) == 0
|
112 |
+
assert m.double_or_zero(42) == 84
|
113 |
+
pytest.raises(TypeError, m.double_or_zero, "foo")
|
114 |
+
|
115 |
+
assert m.half_or_none(0) is None
|
116 |
+
assert m.half_or_none(42) == 21
|
117 |
+
pytest.raises(TypeError, m.half_or_none, "foo")
|
118 |
+
|
119 |
+
assert m.test_nullopt() == 42
|
120 |
+
assert m.test_nullopt(None) == 42
|
121 |
+
assert m.test_nullopt(42) == 42
|
122 |
+
assert m.test_nullopt(43) == 43
|
123 |
+
|
124 |
+
assert m.test_no_assign() == 42
|
125 |
+
assert m.test_no_assign(None) == 42
|
126 |
+
assert m.test_no_assign(m.NoAssign(43)) == 43
|
127 |
+
pytest.raises(TypeError, m.test_no_assign, 43)
|
128 |
+
|
129 |
+
assert m.nodefer_none_optional(None)
|
130 |
+
|
131 |
+
holder = m.OptionalHolder()
|
132 |
+
mvalue = holder.member
|
133 |
+
assert mvalue.initialized
|
134 |
+
assert holder.member_initialized()
|
135 |
+
|
136 |
+
|
137 |
+
@pytest.mark.skipif(
|
138 |
+
not hasattr(m, "has_exp_optional"), reason="no <experimental/optional>"
|
139 |
+
)
|
140 |
+
def test_exp_optional():
|
141 |
+
assert m.double_or_zero_exp(None) == 0
|
142 |
+
assert m.double_or_zero_exp(42) == 84
|
143 |
+
pytest.raises(TypeError, m.double_or_zero_exp, "foo")
|
144 |
+
|
145 |
+
assert m.half_or_none_exp(0) is None
|
146 |
+
assert m.half_or_none_exp(42) == 21
|
147 |
+
pytest.raises(TypeError, m.half_or_none_exp, "foo")
|
148 |
+
|
149 |
+
assert m.test_nullopt_exp() == 42
|
150 |
+
assert m.test_nullopt_exp(None) == 42
|
151 |
+
assert m.test_nullopt_exp(42) == 42
|
152 |
+
assert m.test_nullopt_exp(43) == 43
|
153 |
+
|
154 |
+
assert m.test_no_assign_exp() == 42
|
155 |
+
assert m.test_no_assign_exp(None) == 42
|
156 |
+
assert m.test_no_assign_exp(m.NoAssign(43)) == 43
|
157 |
+
pytest.raises(TypeError, m.test_no_assign_exp, 43)
|
158 |
+
|
159 |
+
holder = m.OptionalExpHolder()
|
160 |
+
mvalue = holder.member
|
161 |
+
assert mvalue.initialized
|
162 |
+
assert holder.member_initialized()
|
163 |
+
|
164 |
+
|
165 |
+
@pytest.mark.skipif(not hasattr(m, "has_filesystem"), reason="no <filesystem>")
|
166 |
+
def test_fs_path():
|
167 |
+
from pathlib import Path
|
168 |
+
|
169 |
+
class PseudoStrPath:
|
170 |
+
def __fspath__(self):
|
171 |
+
return "foo/bar"
|
172 |
+
|
173 |
+
class PseudoBytesPath:
|
174 |
+
def __fspath__(self):
|
175 |
+
return b"foo/bar"
|
176 |
+
|
177 |
+
assert m.parent_path(Path("foo/bar")) == Path("foo")
|
178 |
+
assert m.parent_path("foo/bar") == Path("foo")
|
179 |
+
assert m.parent_path(b"foo/bar") == Path("foo")
|
180 |
+
assert m.parent_path(PseudoStrPath()) == Path("foo")
|
181 |
+
assert m.parent_path(PseudoBytesPath()) == Path("foo")
|
182 |
+
|
183 |
+
|
184 |
+
@pytest.mark.skipif(not hasattr(m, "load_variant"), reason="no <variant>")
|
185 |
+
def test_variant(doc):
|
186 |
+
assert m.load_variant(1) == "int"
|
187 |
+
assert m.load_variant("1") == "std::string"
|
188 |
+
assert m.load_variant(1.0) == "double"
|
189 |
+
assert m.load_variant(None) == "std::nullptr_t"
|
190 |
+
|
191 |
+
assert m.load_variant_2pass(1) == "int"
|
192 |
+
assert m.load_variant_2pass(1.0) == "double"
|
193 |
+
|
194 |
+
assert m.cast_variant() == (5, "Hello")
|
195 |
+
|
196 |
+
assert (
|
197 |
+
doc(m.load_variant) == "load_variant(arg0: Union[int, str, float, None]) -> str"
|
198 |
+
)
|
199 |
+
|
200 |
+
|
201 |
+
def test_vec_of_reference_wrapper():
|
202 |
+
"""#171: Can't return reference wrappers (or STL structures containing them)"""
|
203 |
+
assert (
|
204 |
+
str(m.return_vec_of_reference_wrapper(UserType(4)))
|
205 |
+
== "[UserType(1), UserType(2), UserType(3), UserType(4)]"
|
206 |
+
)
|
207 |
+
|
208 |
+
|
209 |
+
def test_stl_pass_by_pointer(msg):
|
210 |
+
"""Passing nullptr or None to an STL container pointer is not expected to work"""
|
211 |
+
with pytest.raises(TypeError) as excinfo:
|
212 |
+
m.stl_pass_by_pointer() # default value is `nullptr`
|
213 |
+
assert (
|
214 |
+
msg(excinfo.value)
|
215 |
+
== """
|
216 |
+
stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:
|
217 |
+
1. (v: List[int] = None) -> List[int]
|
218 |
+
|
219 |
+
Invoked with:
|
220 |
+
""" # noqa: E501 line too long
|
221 |
+
)
|
222 |
+
|
223 |
+
with pytest.raises(TypeError) as excinfo:
|
224 |
+
m.stl_pass_by_pointer(None)
|
225 |
+
assert (
|
226 |
+
msg(excinfo.value)
|
227 |
+
== """
|
228 |
+
stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:
|
229 |
+
1. (v: List[int] = None) -> List[int]
|
230 |
+
|
231 |
+
Invoked with: None
|
232 |
+
""" # noqa: E501 line too long
|
233 |
+
)
|
234 |
+
|
235 |
+
assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3]
|
236 |
+
|
237 |
+
|
238 |
+
def test_missing_header_message():
|
239 |
+
"""Trying convert `list` to a `std::vector`, or vice versa, without including
|
240 |
+
<pybind11/stl.h> should result in a helpful suggestion in the error message"""
|
241 |
+
import pybind11_cross_module_tests as cm
|
242 |
+
|
243 |
+
expected_message = (
|
244 |
+
"Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,\n"
|
245 |
+
"<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic\n"
|
246 |
+
"conversions are optional and require extra headers to be included\n"
|
247 |
+
"when compiling your pybind11 module."
|
248 |
+
)
|
249 |
+
|
250 |
+
with pytest.raises(TypeError) as excinfo:
|
251 |
+
cm.missing_header_arg([1.0, 2.0, 3.0])
|
252 |
+
assert expected_message in str(excinfo.value)
|
253 |
+
|
254 |
+
with pytest.raises(TypeError) as excinfo:
|
255 |
+
cm.missing_header_return()
|
256 |
+
assert expected_message in str(excinfo.value)
|
257 |
+
|
258 |
+
|
259 |
+
def test_function_with_string_and_vector_string_arg():
|
260 |
+
"""Check if a string is NOT implicitly converted to a list, which was the
|
261 |
+
behavior before fix of issue #1258"""
|
262 |
+
assert m.func_with_string_or_vector_string_arg_overload(("A", "B")) == 2
|
263 |
+
assert m.func_with_string_or_vector_string_arg_overload(["A", "B"]) == 2
|
264 |
+
assert m.func_with_string_or_vector_string_arg_overload("A") == 3
|
265 |
+
|
266 |
+
|
267 |
+
def test_stl_ownership():
|
268 |
+
cstats = ConstructorStats.get(m.Placeholder)
|
269 |
+
assert cstats.alive() == 0
|
270 |
+
r = m.test_stl_ownership()
|
271 |
+
assert len(r) == 1
|
272 |
+
del r
|
273 |
+
assert cstats.alive() == 0
|
274 |
+
|
275 |
+
|
276 |
+
def test_array_cast_sequence():
|
277 |
+
assert m.array_cast_sequence((1, 2, 3)) == [1, 2, 3]
|
278 |
+
|
279 |
+
|
280 |
+
def test_issue_1561():
|
281 |
+
"""check fix for issue #1561"""
|
282 |
+
bar = m.Issue1561Outer()
|
283 |
+
bar.list = [m.Issue1561Inner("bar")]
|
284 |
+
bar.list
|
285 |
+
assert bar.list[0].data == "bar"
|
286 |
+
|
287 |
+
|
288 |
+
def test_return_vector_bool_raw_ptr():
|
289 |
+
# Add `while True:` for manual leak checking.
|
290 |
+
v = m.return_vector_bool_raw_ptr()
|
291 |
+
assert isinstance(v, list)
|
292 |
+
assert len(v) == 4513
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_stl_binders.cpp
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_stl_binders.cpp -- Usage of stl_binders functions
|
3 |
+
|
4 |
+
Copyright (c) 2016 Sergey Lyskov
|
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 |
+
#include <pybind11/stl_bind.h>
|
13 |
+
#include <pybind11/numpy.h>
|
14 |
+
#include <map>
|
15 |
+
#include <deque>
|
16 |
+
#include <unordered_map>
|
17 |
+
|
18 |
+
class El {
|
19 |
+
public:
|
20 |
+
El() = delete;
|
21 |
+
El(int v) : a(v) { }
|
22 |
+
|
23 |
+
int a;
|
24 |
+
};
|
25 |
+
|
26 |
+
std::ostream & operator<<(std::ostream &s, El const&v) {
|
27 |
+
s << "El{" << v.a << '}';
|
28 |
+
return s;
|
29 |
+
}
|
30 |
+
|
31 |
+
/// Issue #487: binding std::vector<E> with E non-copyable
|
32 |
+
class E_nc {
|
33 |
+
public:
|
34 |
+
explicit E_nc(int i) : value{i} {}
|
35 |
+
E_nc(const E_nc &) = delete;
|
36 |
+
E_nc &operator=(const E_nc &) = delete;
|
37 |
+
E_nc(E_nc &&) = default;
|
38 |
+
E_nc &operator=(E_nc &&) = default;
|
39 |
+
|
40 |
+
int value;
|
41 |
+
};
|
42 |
+
|
43 |
+
template <class Container> Container *one_to_n(int n) {
|
44 |
+
auto v = new Container();
|
45 |
+
for (int i = 1; i <= n; i++)
|
46 |
+
v->emplace_back(i);
|
47 |
+
return v;
|
48 |
+
}
|
49 |
+
|
50 |
+
template <class Map> Map *times_ten(int n) {
|
51 |
+
auto m = new Map();
|
52 |
+
for (int i = 1; i <= n; i++)
|
53 |
+
m->emplace(int(i), E_nc(10*i));
|
54 |
+
return m;
|
55 |
+
}
|
56 |
+
|
57 |
+
template <class NestMap> NestMap *times_hundred(int n) {
|
58 |
+
auto m = new NestMap();
|
59 |
+
for (int i = 1; i <= n; i++)
|
60 |
+
for (int j = 1; j <= n; j++)
|
61 |
+
(*m)[i].emplace(int(j*10), E_nc(100*j));
|
62 |
+
return m;
|
63 |
+
}
|
64 |
+
|
65 |
+
TEST_SUBMODULE(stl_binders, m) {
|
66 |
+
// test_vector_int
|
67 |
+
py::bind_vector<std::vector<unsigned int>>(m, "VectorInt", py::buffer_protocol());
|
68 |
+
|
69 |
+
// test_vector_custom
|
70 |
+
py::class_<El>(m, "El")
|
71 |
+
.def(py::init<int>());
|
72 |
+
py::bind_vector<std::vector<El>>(m, "VectorEl");
|
73 |
+
py::bind_vector<std::vector<std::vector<El>>>(m, "VectorVectorEl");
|
74 |
+
|
75 |
+
// test_map_string_double
|
76 |
+
py::bind_map<std::map<std::string, double>>(m, "MapStringDouble");
|
77 |
+
py::bind_map<std::unordered_map<std::string, double>>(m, "UnorderedMapStringDouble");
|
78 |
+
|
79 |
+
// test_map_string_double_const
|
80 |
+
py::bind_map<std::map<std::string, double const>>(m, "MapStringDoubleConst");
|
81 |
+
py::bind_map<std::unordered_map<std::string, double const>>(m, "UnorderedMapStringDoubleConst");
|
82 |
+
|
83 |
+
py::class_<E_nc>(m, "ENC")
|
84 |
+
.def(py::init<int>())
|
85 |
+
.def_readwrite("value", &E_nc::value);
|
86 |
+
|
87 |
+
// test_noncopyable_containers
|
88 |
+
py::bind_vector<std::vector<E_nc>>(m, "VectorENC");
|
89 |
+
m.def("get_vnc", &one_to_n<std::vector<E_nc>>);
|
90 |
+
py::bind_vector<std::deque<E_nc>>(m, "DequeENC");
|
91 |
+
m.def("get_dnc", &one_to_n<std::deque<E_nc>>);
|
92 |
+
py::bind_map<std::map<int, E_nc>>(m, "MapENC");
|
93 |
+
m.def("get_mnc", ×_ten<std::map<int, E_nc>>);
|
94 |
+
py::bind_map<std::unordered_map<int, E_nc>>(m, "UmapENC");
|
95 |
+
m.def("get_umnc", ×_ten<std::unordered_map<int, E_nc>>);
|
96 |
+
// Issue #1885: binding nested std::map<X, Container<E>> with E non-copyable
|
97 |
+
py::bind_map<std::map<int, std::vector<E_nc>>>(m, "MapVecENC");
|
98 |
+
m.def("get_nvnc", [](int n)
|
99 |
+
{
|
100 |
+
auto m = new std::map<int, std::vector<E_nc>>();
|
101 |
+
for (int i = 1; i <= n; i++)
|
102 |
+
for (int j = 1; j <= n; j++)
|
103 |
+
(*m)[i].emplace_back(j);
|
104 |
+
return m;
|
105 |
+
});
|
106 |
+
py::bind_map<std::map<int, std::map<int, E_nc>>>(m, "MapMapENC");
|
107 |
+
m.def("get_nmnc", ×_hundred<std::map<int, std::map<int, E_nc>>>);
|
108 |
+
py::bind_map<std::unordered_map<int, std::unordered_map<int, E_nc>>>(m, "UmapUmapENC");
|
109 |
+
m.def("get_numnc", ×_hundred<std::unordered_map<int, std::unordered_map<int, E_nc>>>);
|
110 |
+
|
111 |
+
// test_vector_buffer
|
112 |
+
py::bind_vector<std::vector<unsigned char>>(m, "VectorUChar", py::buffer_protocol());
|
113 |
+
// no dtype declared for this version:
|
114 |
+
struct VUndeclStruct { bool w; uint32_t x; double y; bool z; };
|
115 |
+
m.def("create_undeclstruct", [m] () mutable {
|
116 |
+
py::bind_vector<std::vector<VUndeclStruct>>(m, "VectorUndeclStruct", py::buffer_protocol());
|
117 |
+
});
|
118 |
+
|
119 |
+
// The rest depends on numpy:
|
120 |
+
try { py::module_::import("numpy"); }
|
121 |
+
catch (...) { return; }
|
122 |
+
|
123 |
+
// test_vector_buffer_numpy
|
124 |
+
struct VStruct { bool w; uint32_t x; double y; bool z; };
|
125 |
+
PYBIND11_NUMPY_DTYPE(VStruct, w, x, y, z);
|
126 |
+
py::class_<VStruct>(m, "VStruct").def_readwrite("x", &VStruct::x);
|
127 |
+
py::bind_vector<std::vector<VStruct>>(m, "VectorStruct", py::buffer_protocol());
|
128 |
+
m.def("get_vectorstruct", [] {
|
129 |
+
return std::vector<VStruct>{{false, 5, 3.0, true}, {true, 30, -1e4, false}};
|
130 |
+
});
|
131 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_stl_binders.py
ADDED
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
import env # noqa: F401
|
5 |
+
|
6 |
+
from pybind11_tests import stl_binders as m
|
7 |
+
|
8 |
+
|
9 |
+
def test_vector_int():
|
10 |
+
v_int = m.VectorInt([0, 0])
|
11 |
+
assert len(v_int) == 2
|
12 |
+
assert bool(v_int) is True
|
13 |
+
|
14 |
+
# test construction from a generator
|
15 |
+
v_int1 = m.VectorInt(x for x in range(5))
|
16 |
+
assert v_int1 == m.VectorInt([0, 1, 2, 3, 4])
|
17 |
+
|
18 |
+
v_int2 = m.VectorInt([0, 0])
|
19 |
+
assert v_int == v_int2
|
20 |
+
v_int2[1] = 1
|
21 |
+
assert v_int != v_int2
|
22 |
+
|
23 |
+
v_int2.append(2)
|
24 |
+
v_int2.insert(0, 1)
|
25 |
+
v_int2.insert(0, 2)
|
26 |
+
v_int2.insert(0, 3)
|
27 |
+
v_int2.insert(6, 3)
|
28 |
+
assert str(v_int2) == "VectorInt[3, 2, 1, 0, 1, 2, 3]"
|
29 |
+
with pytest.raises(IndexError):
|
30 |
+
v_int2.insert(8, 4)
|
31 |
+
|
32 |
+
v_int.append(99)
|
33 |
+
v_int2[2:-2] = v_int
|
34 |
+
assert v_int2 == m.VectorInt([3, 2, 0, 0, 99, 2, 3])
|
35 |
+
del v_int2[1:3]
|
36 |
+
assert v_int2 == m.VectorInt([3, 0, 99, 2, 3])
|
37 |
+
del v_int2[0]
|
38 |
+
assert v_int2 == m.VectorInt([0, 99, 2, 3])
|
39 |
+
|
40 |
+
v_int2.extend(m.VectorInt([4, 5]))
|
41 |
+
assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5])
|
42 |
+
|
43 |
+
v_int2.extend([6, 7])
|
44 |
+
assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7])
|
45 |
+
|
46 |
+
# test error handling, and that the vector is unchanged
|
47 |
+
with pytest.raises(RuntimeError):
|
48 |
+
v_int2.extend([8, "a"])
|
49 |
+
|
50 |
+
assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7])
|
51 |
+
|
52 |
+
# test extending from a generator
|
53 |
+
v_int2.extend(x for x in range(5))
|
54 |
+
assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4])
|
55 |
+
|
56 |
+
# test negative indexing
|
57 |
+
assert v_int2[-1] == 4
|
58 |
+
|
59 |
+
# insert with negative index
|
60 |
+
v_int2.insert(-1, 88)
|
61 |
+
assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 88, 4])
|
62 |
+
|
63 |
+
# delete negative index
|
64 |
+
del v_int2[-1]
|
65 |
+
assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 88])
|
66 |
+
|
67 |
+
v_int2.clear()
|
68 |
+
assert len(v_int2) == 0
|
69 |
+
|
70 |
+
|
71 |
+
# Older PyPy's failed here, related to the PyPy's buffer protocol.
|
72 |
+
def test_vector_buffer():
|
73 |
+
b = bytearray([1, 2, 3, 4])
|
74 |
+
v = m.VectorUChar(b)
|
75 |
+
assert v[1] == 2
|
76 |
+
v[2] = 5
|
77 |
+
mv = memoryview(v) # We expose the buffer interface
|
78 |
+
if not env.PY2:
|
79 |
+
assert mv[2] == 5
|
80 |
+
mv[2] = 6
|
81 |
+
else:
|
82 |
+
assert mv[2] == "\x05"
|
83 |
+
mv[2] = "\x06"
|
84 |
+
assert v[2] == 6
|
85 |
+
|
86 |
+
if not env.PY2:
|
87 |
+
mv = memoryview(b)
|
88 |
+
v = m.VectorUChar(mv[::2])
|
89 |
+
assert v[1] == 3
|
90 |
+
|
91 |
+
with pytest.raises(RuntimeError) as excinfo:
|
92 |
+
m.create_undeclstruct() # Undeclared struct contents, no buffer interface
|
93 |
+
assert "NumPy type info missing for " in str(excinfo.value)
|
94 |
+
|
95 |
+
|
96 |
+
def test_vector_buffer_numpy():
|
97 |
+
np = pytest.importorskip("numpy")
|
98 |
+
a = np.array([1, 2, 3, 4], dtype=np.int32)
|
99 |
+
with pytest.raises(TypeError):
|
100 |
+
m.VectorInt(a)
|
101 |
+
|
102 |
+
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], dtype=np.uintc)
|
103 |
+
v = m.VectorInt(a[0, :])
|
104 |
+
assert len(v) == 4
|
105 |
+
assert v[2] == 3
|
106 |
+
ma = np.asarray(v)
|
107 |
+
ma[2] = 5
|
108 |
+
assert v[2] == 5
|
109 |
+
|
110 |
+
v = m.VectorInt(a[:, 1])
|
111 |
+
assert len(v) == 3
|
112 |
+
assert v[2] == 10
|
113 |
+
|
114 |
+
v = m.get_vectorstruct()
|
115 |
+
assert v[0].x == 5
|
116 |
+
ma = np.asarray(v)
|
117 |
+
ma[1]["x"] = 99
|
118 |
+
assert v[1].x == 99
|
119 |
+
|
120 |
+
v = m.VectorStruct(
|
121 |
+
np.zeros(
|
122 |
+
3,
|
123 |
+
dtype=np.dtype(
|
124 |
+
[("w", "bool"), ("x", "I"), ("y", "float64"), ("z", "bool")], align=True
|
125 |
+
),
|
126 |
+
)
|
127 |
+
)
|
128 |
+
assert len(v) == 3
|
129 |
+
|
130 |
+
b = np.array([1, 2, 3, 4], dtype=np.uint8)
|
131 |
+
v = m.VectorUChar(b[::2])
|
132 |
+
assert v[1] == 3
|
133 |
+
|
134 |
+
|
135 |
+
def test_vector_bool():
|
136 |
+
import pybind11_cross_module_tests as cm
|
137 |
+
|
138 |
+
vv_c = cm.VectorBool()
|
139 |
+
for i in range(10):
|
140 |
+
vv_c.append(i % 2 == 0)
|
141 |
+
for i in range(10):
|
142 |
+
assert vv_c[i] == (i % 2 == 0)
|
143 |
+
assert str(vv_c) == "VectorBool[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]"
|
144 |
+
|
145 |
+
|
146 |
+
def test_vector_custom():
|
147 |
+
v_a = m.VectorEl()
|
148 |
+
v_a.append(m.El(1))
|
149 |
+
v_a.append(m.El(2))
|
150 |
+
assert str(v_a) == "VectorEl[El{1}, El{2}]"
|
151 |
+
|
152 |
+
vv_a = m.VectorVectorEl()
|
153 |
+
vv_a.append(v_a)
|
154 |
+
vv_b = vv_a[0]
|
155 |
+
assert str(vv_b) == "VectorEl[El{1}, El{2}]"
|
156 |
+
|
157 |
+
|
158 |
+
def test_map_string_double():
|
159 |
+
mm = m.MapStringDouble()
|
160 |
+
mm["a"] = 1
|
161 |
+
mm["b"] = 2.5
|
162 |
+
|
163 |
+
assert list(mm) == ["a", "b"]
|
164 |
+
assert list(mm.items()) == [("a", 1), ("b", 2.5)]
|
165 |
+
assert str(mm) == "MapStringDouble{a: 1, b: 2.5}"
|
166 |
+
|
167 |
+
um = m.UnorderedMapStringDouble()
|
168 |
+
um["ua"] = 1.1
|
169 |
+
um["ub"] = 2.6
|
170 |
+
|
171 |
+
assert sorted(list(um)) == ["ua", "ub"]
|
172 |
+
assert sorted(list(um.items())) == [("ua", 1.1), ("ub", 2.6)]
|
173 |
+
assert "UnorderedMapStringDouble" in str(um)
|
174 |
+
|
175 |
+
|
176 |
+
def test_map_string_double_const():
|
177 |
+
mc = m.MapStringDoubleConst()
|
178 |
+
mc["a"] = 10
|
179 |
+
mc["b"] = 20.5
|
180 |
+
assert str(mc) == "MapStringDoubleConst{a: 10, b: 20.5}"
|
181 |
+
|
182 |
+
umc = m.UnorderedMapStringDoubleConst()
|
183 |
+
umc["a"] = 11
|
184 |
+
umc["b"] = 21.5
|
185 |
+
|
186 |
+
str(umc)
|
187 |
+
|
188 |
+
|
189 |
+
def test_noncopyable_containers():
|
190 |
+
# std::vector
|
191 |
+
vnc = m.get_vnc(5)
|
192 |
+
for i in range(0, 5):
|
193 |
+
assert vnc[i].value == i + 1
|
194 |
+
|
195 |
+
for i, j in enumerate(vnc, start=1):
|
196 |
+
assert j.value == i
|
197 |
+
|
198 |
+
# std::deque
|
199 |
+
dnc = m.get_dnc(5)
|
200 |
+
for i in range(0, 5):
|
201 |
+
assert dnc[i].value == i + 1
|
202 |
+
|
203 |
+
i = 1
|
204 |
+
for j in dnc:
|
205 |
+
assert j.value == i
|
206 |
+
i += 1
|
207 |
+
|
208 |
+
# std::map
|
209 |
+
mnc = m.get_mnc(5)
|
210 |
+
for i in range(1, 6):
|
211 |
+
assert mnc[i].value == 10 * i
|
212 |
+
|
213 |
+
vsum = 0
|
214 |
+
for k, v in mnc.items():
|
215 |
+
assert v.value == 10 * k
|
216 |
+
vsum += v.value
|
217 |
+
|
218 |
+
assert vsum == 150
|
219 |
+
|
220 |
+
# std::unordered_map
|
221 |
+
mnc = m.get_umnc(5)
|
222 |
+
for i in range(1, 6):
|
223 |
+
assert mnc[i].value == 10 * i
|
224 |
+
|
225 |
+
vsum = 0
|
226 |
+
for k, v in mnc.items():
|
227 |
+
assert v.value == 10 * k
|
228 |
+
vsum += v.value
|
229 |
+
|
230 |
+
assert vsum == 150
|
231 |
+
|
232 |
+
# nested std::map<std::vector>
|
233 |
+
nvnc = m.get_nvnc(5)
|
234 |
+
for i in range(1, 6):
|
235 |
+
for j in range(0, 5):
|
236 |
+
assert nvnc[i][j].value == j + 1
|
237 |
+
|
238 |
+
# Note: maps do not have .values()
|
239 |
+
for _, v in nvnc.items():
|
240 |
+
for i, j in enumerate(v, start=1):
|
241 |
+
assert j.value == i
|
242 |
+
|
243 |
+
# nested std::map<std::map>
|
244 |
+
nmnc = m.get_nmnc(5)
|
245 |
+
for i in range(1, 6):
|
246 |
+
for j in range(10, 60, 10):
|
247 |
+
assert nmnc[i][j].value == 10 * j
|
248 |
+
|
249 |
+
vsum = 0
|
250 |
+
for _, v_o in nmnc.items():
|
251 |
+
for k_i, v_i in v_o.items():
|
252 |
+
assert v_i.value == 10 * k_i
|
253 |
+
vsum += v_i.value
|
254 |
+
|
255 |
+
assert vsum == 7500
|
256 |
+
|
257 |
+
# nested std::unordered_map<std::unordered_map>
|
258 |
+
numnc = m.get_numnc(5)
|
259 |
+
for i in range(1, 6):
|
260 |
+
for j in range(10, 60, 10):
|
261 |
+
assert numnc[i][j].value == 10 * j
|
262 |
+
|
263 |
+
vsum = 0
|
264 |
+
for _, v_o in numnc.items():
|
265 |
+
for k_i, v_i in v_o.items():
|
266 |
+
assert v_i.value == 10 * k_i
|
267 |
+
vsum += v_i.value
|
268 |
+
|
269 |
+
assert vsum == 7500
|
270 |
+
|
271 |
+
|
272 |
+
def test_map_delitem():
|
273 |
+
mm = m.MapStringDouble()
|
274 |
+
mm["a"] = 1
|
275 |
+
mm["b"] = 2.5
|
276 |
+
|
277 |
+
assert list(mm) == ["a", "b"]
|
278 |
+
assert list(mm.items()) == [("a", 1), ("b", 2.5)]
|
279 |
+
del mm["a"]
|
280 |
+
assert list(mm) == ["b"]
|
281 |
+
assert list(mm.items()) == [("b", 2.5)]
|
282 |
+
|
283 |
+
um = m.UnorderedMapStringDouble()
|
284 |
+
um["ua"] = 1.1
|
285 |
+
um["ub"] = 2.6
|
286 |
+
|
287 |
+
assert sorted(list(um)) == ["ua", "ub"]
|
288 |
+
assert sorted(list(um.items())) == [("ua", 1.1), ("ub", 2.6)]
|
289 |
+
del um["ua"]
|
290 |
+
assert sorted(list(um)) == ["ub"]
|
291 |
+
assert sorted(list(um.items())) == [("ub", 2.6)]
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_tagbased_polymorphic.cpp
ADDED
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_tagbased_polymorphic.cpp -- test of polymorphic_type_hook
|
3 |
+
|
4 |
+
Copyright (c) 2018 Hudson River Trading 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/stl.h>
|
12 |
+
|
13 |
+
struct Animal
|
14 |
+
{
|
15 |
+
// Make this type also a "standard" polymorphic type, to confirm that
|
16 |
+
// specializing polymorphic_type_hook using enable_if_t still works
|
17 |
+
// (https://github.com/pybind/pybind11/pull/2016/).
|
18 |
+
virtual ~Animal() = default;
|
19 |
+
|
20 |
+
// Enum for tag-based polymorphism.
|
21 |
+
enum class Kind {
|
22 |
+
Unknown = 0,
|
23 |
+
Dog = 100, Labrador, Chihuahua, LastDog = 199,
|
24 |
+
Cat = 200, Panther, LastCat = 299
|
25 |
+
};
|
26 |
+
static const std::type_info* type_of_kind(Kind kind);
|
27 |
+
static std::string name_of_kind(Kind kind);
|
28 |
+
|
29 |
+
const Kind kind;
|
30 |
+
const std::string name;
|
31 |
+
|
32 |
+
protected:
|
33 |
+
Animal(const std::string& _name, Kind _kind)
|
34 |
+
: kind(_kind), name(_name)
|
35 |
+
{}
|
36 |
+
};
|
37 |
+
|
38 |
+
struct Dog : Animal
|
39 |
+
{
|
40 |
+
Dog(const std::string& _name, Kind _kind = Kind::Dog) : Animal(_name, _kind) {}
|
41 |
+
std::string bark() const { return name_of_kind(kind) + " " + name + " goes " + sound; }
|
42 |
+
std::string sound = "WOOF!";
|
43 |
+
};
|
44 |
+
|
45 |
+
struct Labrador : Dog
|
46 |
+
{
|
47 |
+
Labrador(const std::string& _name, int _excitement = 9001)
|
48 |
+
: Dog(_name, Kind::Labrador), excitement(_excitement) {}
|
49 |
+
int excitement;
|
50 |
+
};
|
51 |
+
|
52 |
+
struct Chihuahua : Dog
|
53 |
+
{
|
54 |
+
Chihuahua(const std::string& _name) : Dog(_name, Kind::Chihuahua) { sound = "iyiyiyiyiyi"; }
|
55 |
+
std::string bark() const { return Dog::bark() + " and runs in circles"; }
|
56 |
+
};
|
57 |
+
|
58 |
+
struct Cat : Animal
|
59 |
+
{
|
60 |
+
Cat(const std::string& _name, Kind _kind = Kind::Cat) : Animal(_name, _kind) {}
|
61 |
+
std::string purr() const { return "mrowr"; }
|
62 |
+
};
|
63 |
+
|
64 |
+
struct Panther : Cat
|
65 |
+
{
|
66 |
+
Panther(const std::string& _name) : Cat(_name, Kind::Panther) {}
|
67 |
+
std::string purr() const { return "mrrrRRRRRR"; }
|
68 |
+
};
|
69 |
+
|
70 |
+
std::vector<std::unique_ptr<Animal>> create_zoo()
|
71 |
+
{
|
72 |
+
std::vector<std::unique_ptr<Animal>> ret;
|
73 |
+
ret.emplace_back(new Labrador("Fido", 15000));
|
74 |
+
|
75 |
+
// simulate some new type of Dog that the Python bindings
|
76 |
+
// haven't been updated for; it should still be considered
|
77 |
+
// a Dog, not just an Animal.
|
78 |
+
ret.emplace_back(new Dog("Ginger", Dog::Kind(150)));
|
79 |
+
|
80 |
+
ret.emplace_back(new Chihuahua("Hertzl"));
|
81 |
+
ret.emplace_back(new Cat("Tiger", Cat::Kind::Cat));
|
82 |
+
ret.emplace_back(new Panther("Leo"));
|
83 |
+
return ret;
|
84 |
+
}
|
85 |
+
|
86 |
+
const std::type_info* Animal::type_of_kind(Kind kind)
|
87 |
+
{
|
88 |
+
switch (kind) {
|
89 |
+
case Kind::Unknown: break;
|
90 |
+
|
91 |
+
case Kind::Dog: break;
|
92 |
+
case Kind::Labrador: return &typeid(Labrador);
|
93 |
+
case Kind::Chihuahua: return &typeid(Chihuahua);
|
94 |
+
case Kind::LastDog: break;
|
95 |
+
|
96 |
+
case Kind::Cat: break;
|
97 |
+
case Kind::Panther: return &typeid(Panther);
|
98 |
+
case Kind::LastCat: break;
|
99 |
+
}
|
100 |
+
|
101 |
+
if (kind >= Kind::Dog && kind <= Kind::LastDog) return &typeid(Dog);
|
102 |
+
if (kind >= Kind::Cat && kind <= Kind::LastCat) return &typeid(Cat);
|
103 |
+
return nullptr;
|
104 |
+
}
|
105 |
+
|
106 |
+
std::string Animal::name_of_kind(Kind kind)
|
107 |
+
{
|
108 |
+
std::string raw_name = type_of_kind(kind)->name();
|
109 |
+
py::detail::clean_type_id(raw_name);
|
110 |
+
return raw_name;
|
111 |
+
}
|
112 |
+
|
113 |
+
namespace pybind11 {
|
114 |
+
template <typename itype>
|
115 |
+
struct polymorphic_type_hook<itype, detail::enable_if_t<std::is_base_of<Animal, itype>::value>>
|
116 |
+
{
|
117 |
+
static const void *get(const itype *src, const std::type_info*& type)
|
118 |
+
{ type = src ? Animal::type_of_kind(src->kind) : nullptr; return src; }
|
119 |
+
};
|
120 |
+
} // namespace pybind11
|
121 |
+
|
122 |
+
TEST_SUBMODULE(tagbased_polymorphic, m) {
|
123 |
+
py::class_<Animal>(m, "Animal")
|
124 |
+
.def_readonly("name", &Animal::name);
|
125 |
+
py::class_<Dog, Animal>(m, "Dog")
|
126 |
+
.def(py::init<std::string>())
|
127 |
+
.def_readwrite("sound", &Dog::sound)
|
128 |
+
.def("bark", &Dog::bark);
|
129 |
+
py::class_<Labrador, Dog>(m, "Labrador")
|
130 |
+
.def(py::init<std::string, int>(), "name"_a, "excitement"_a = 9001)
|
131 |
+
.def_readwrite("excitement", &Labrador::excitement);
|
132 |
+
py::class_<Chihuahua, Dog>(m, "Chihuahua")
|
133 |
+
.def(py::init<std::string>())
|
134 |
+
.def("bark", &Chihuahua::bark);
|
135 |
+
py::class_<Cat, Animal>(m, "Cat")
|
136 |
+
.def(py::init<std::string>())
|
137 |
+
.def("purr", &Cat::purr);
|
138 |
+
py::class_<Panther, Cat>(m, "Panther")
|
139 |
+
.def(py::init<std::string>())
|
140 |
+
.def("purr", &Panther::purr);
|
141 |
+
m.def("create_zoo", &create_zoo);
|
142 |
+
};
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_tagbased_polymorphic.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
from pybind11_tests import tagbased_polymorphic as m
|
3 |
+
|
4 |
+
|
5 |
+
def test_downcast():
|
6 |
+
zoo = m.create_zoo()
|
7 |
+
assert [type(animal) for animal in zoo] == [
|
8 |
+
m.Labrador,
|
9 |
+
m.Dog,
|
10 |
+
m.Chihuahua,
|
11 |
+
m.Cat,
|
12 |
+
m.Panther,
|
13 |
+
]
|
14 |
+
assert [animal.name for animal in zoo] == [
|
15 |
+
"Fido",
|
16 |
+
"Ginger",
|
17 |
+
"Hertzl",
|
18 |
+
"Tiger",
|
19 |
+
"Leo",
|
20 |
+
]
|
21 |
+
zoo[1].sound = "woooooo"
|
22 |
+
assert [dog.bark() for dog in zoo[:3]] == [
|
23 |
+
"Labrador Fido goes WOOF!",
|
24 |
+
"Dog Ginger goes woooooo",
|
25 |
+
"Chihuahua Hertzl goes iyiyiyiyiyi and runs in circles",
|
26 |
+
]
|
27 |
+
assert [cat.purr() for cat in zoo[3:]] == ["mrowr", "mrrrRRRRRR"]
|
28 |
+
zoo[0].excitement -= 1000
|
29 |
+
assert zoo[0].excitement == 14000
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_union.cpp
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_class.cpp -- test py::class_ definitions and basic functionality
|
3 |
+
|
4 |
+
Copyright (c) 2019 Roland Dreier <[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(union_, m) {
|
13 |
+
union TestUnion {
|
14 |
+
int value_int;
|
15 |
+
unsigned value_uint;
|
16 |
+
};
|
17 |
+
|
18 |
+
py::class_<TestUnion>(m, "TestUnion")
|
19 |
+
.def(py::init<>())
|
20 |
+
.def_readonly("as_int", &TestUnion::value_int)
|
21 |
+
.def_readwrite("as_uint", &TestUnion::value_uint);
|
22 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_union.py
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
from pybind11_tests import union_ as m
|
3 |
+
|
4 |
+
|
5 |
+
def test_union():
|
6 |
+
instance = m.TestUnion()
|
7 |
+
|
8 |
+
instance.as_uint = 10
|
9 |
+
assert instance.as_int == 10
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_virtual_functions.cpp
ADDED
@@ -0,0 +1,509 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
tests/test_virtual_functions.cpp -- overriding virtual functions from Python
|
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 |
+
/* This is an example class that we'll want to be able to extend from Python */
|
16 |
+
class ExampleVirt {
|
17 |
+
public:
|
18 |
+
ExampleVirt(int state) : state(state) { print_created(this, state); }
|
19 |
+
ExampleVirt(const ExampleVirt &e) : state(e.state) { print_copy_created(this); }
|
20 |
+
ExampleVirt(ExampleVirt &&e) noexcept : state(e.state) {
|
21 |
+
print_move_created(this);
|
22 |
+
e.state = 0;
|
23 |
+
}
|
24 |
+
virtual ~ExampleVirt() { print_destroyed(this); }
|
25 |
+
|
26 |
+
virtual int run(int value) {
|
27 |
+
py::print("Original implementation of "
|
28 |
+
"ExampleVirt::run(state={}, value={}, str1={}, str2={})"_s.format(state, value, get_string1(), *get_string2()));
|
29 |
+
return state + value;
|
30 |
+
}
|
31 |
+
|
32 |
+
virtual bool run_bool() = 0;
|
33 |
+
virtual void pure_virtual() = 0;
|
34 |
+
|
35 |
+
// Returning a reference/pointer to a type converted from python (numbers, strings, etc.) is a
|
36 |
+
// bit trickier, because the actual int& or std::string& or whatever only exists temporarily, so
|
37 |
+
// we have to handle it specially in the trampoline class (see below).
|
38 |
+
virtual const std::string &get_string1() { return str1; }
|
39 |
+
virtual const std::string *get_string2() { return &str2; }
|
40 |
+
|
41 |
+
private:
|
42 |
+
int state;
|
43 |
+
const std::string str1{"default1"}, str2{"default2"};
|
44 |
+
};
|
45 |
+
|
46 |
+
/* This is a wrapper class that must be generated */
|
47 |
+
class PyExampleVirt : public ExampleVirt {
|
48 |
+
public:
|
49 |
+
using ExampleVirt::ExampleVirt; /* Inherit constructors */
|
50 |
+
|
51 |
+
int run(int value) override {
|
52 |
+
/* Generate wrapping code that enables native function overloading */
|
53 |
+
PYBIND11_OVERRIDE(
|
54 |
+
int, /* Return type */
|
55 |
+
ExampleVirt, /* Parent class */
|
56 |
+
run, /* Name of function */
|
57 |
+
value /* Argument(s) */
|
58 |
+
);
|
59 |
+
}
|
60 |
+
|
61 |
+
bool run_bool() override {
|
62 |
+
PYBIND11_OVERRIDE_PURE(
|
63 |
+
bool, /* Return type */
|
64 |
+
ExampleVirt, /* Parent class */
|
65 |
+
run_bool, /* Name of function */
|
66 |
+
/* This function has no arguments. The trailing comma
|
67 |
+
in the previous line is needed for some compilers */
|
68 |
+
);
|
69 |
+
}
|
70 |
+
|
71 |
+
void pure_virtual() override {
|
72 |
+
PYBIND11_OVERRIDE_PURE(
|
73 |
+
void, /* Return type */
|
74 |
+
ExampleVirt, /* Parent class */
|
75 |
+
pure_virtual, /* Name of function */
|
76 |
+
/* This function has no arguments. The trailing comma
|
77 |
+
in the previous line is needed for some compilers */
|
78 |
+
);
|
79 |
+
}
|
80 |
+
|
81 |
+
// We can return reference types for compatibility with C++ virtual interfaces that do so, but
|
82 |
+
// note they have some significant limitations (see the documentation).
|
83 |
+
const std::string &get_string1() override {
|
84 |
+
PYBIND11_OVERRIDE(
|
85 |
+
const std::string &, /* Return type */
|
86 |
+
ExampleVirt, /* Parent class */
|
87 |
+
get_string1, /* Name of function */
|
88 |
+
/* (no arguments) */
|
89 |
+
);
|
90 |
+
}
|
91 |
+
|
92 |
+
const std::string *get_string2() override {
|
93 |
+
PYBIND11_OVERRIDE(
|
94 |
+
const std::string *, /* Return type */
|
95 |
+
ExampleVirt, /* Parent class */
|
96 |
+
get_string2, /* Name of function */
|
97 |
+
/* (no arguments) */
|
98 |
+
);
|
99 |
+
}
|
100 |
+
|
101 |
+
};
|
102 |
+
|
103 |
+
class NonCopyable {
|
104 |
+
public:
|
105 |
+
NonCopyable(int a, int b) : value{new int(a*b)} { print_created(this, a, b); }
|
106 |
+
NonCopyable(NonCopyable &&o) noexcept {
|
107 |
+
value = std::move(o.value);
|
108 |
+
print_move_created(this);
|
109 |
+
}
|
110 |
+
NonCopyable(const NonCopyable &) = delete;
|
111 |
+
NonCopyable() = delete;
|
112 |
+
void operator=(const NonCopyable &) = delete;
|
113 |
+
void operator=(NonCopyable &&) = delete;
|
114 |
+
std::string get_value() const {
|
115 |
+
if (value)
|
116 |
+
return std::to_string(*value);
|
117 |
+
return "(null)";
|
118 |
+
}
|
119 |
+
~NonCopyable() { print_destroyed(this); }
|
120 |
+
|
121 |
+
private:
|
122 |
+
std::unique_ptr<int> value;
|
123 |
+
};
|
124 |
+
|
125 |
+
// This is like the above, but is both copy and movable. In effect this means it should get moved
|
126 |
+
// when it is not referenced elsewhere, but copied if it is still referenced.
|
127 |
+
class Movable {
|
128 |
+
public:
|
129 |
+
Movable(int a, int b) : value{a+b} { print_created(this, a, b); }
|
130 |
+
Movable(const Movable &m) { value = m.value; print_copy_created(this); }
|
131 |
+
Movable(Movable &&m) noexcept {
|
132 |
+
value = m.value;
|
133 |
+
print_move_created(this);
|
134 |
+
}
|
135 |
+
std::string get_value() const { return std::to_string(value); }
|
136 |
+
~Movable() { print_destroyed(this); }
|
137 |
+
private:
|
138 |
+
int value;
|
139 |
+
};
|
140 |
+
|
141 |
+
class NCVirt {
|
142 |
+
public:
|
143 |
+
virtual ~NCVirt() = default;
|
144 |
+
NCVirt() = default;
|
145 |
+
NCVirt(const NCVirt&) = delete;
|
146 |
+
virtual NonCopyable get_noncopyable(int a, int b) { return NonCopyable(a, b); }
|
147 |
+
virtual Movable get_movable(int a, int b) = 0;
|
148 |
+
|
149 |
+
std::string print_nc(int a, int b) { return get_noncopyable(a, b).get_value(); }
|
150 |
+
std::string print_movable(int a, int b) { return get_movable(a, b).get_value(); }
|
151 |
+
};
|
152 |
+
class NCVirtTrampoline : public NCVirt {
|
153 |
+
#if !defined(__INTEL_COMPILER) && !defined(__CUDACC__) && !defined(__PGIC__)
|
154 |
+
NonCopyable get_noncopyable(int a, int b) override {
|
155 |
+
PYBIND11_OVERRIDE(NonCopyable, NCVirt, get_noncopyable, a, b);
|
156 |
+
}
|
157 |
+
#endif
|
158 |
+
Movable get_movable(int a, int b) override {
|
159 |
+
PYBIND11_OVERRIDE_PURE(Movable, NCVirt, get_movable, a, b);
|
160 |
+
}
|
161 |
+
};
|
162 |
+
|
163 |
+
struct Base {
|
164 |
+
/* for some reason MSVC2015 can't compile this if the function is pure virtual */
|
165 |
+
virtual std::string dispatch() const { return {}; };
|
166 |
+
virtual ~Base() = default;
|
167 |
+
Base() = default;
|
168 |
+
Base(const Base&) = delete;
|
169 |
+
};
|
170 |
+
|
171 |
+
struct DispatchIssue : Base {
|
172 |
+
std::string dispatch() const override {
|
173 |
+
PYBIND11_OVERRIDE_PURE(std::string, Base, dispatch, /* no arguments */);
|
174 |
+
}
|
175 |
+
};
|
176 |
+
|
177 |
+
static void test_gil() {
|
178 |
+
{
|
179 |
+
py::gil_scoped_acquire lock;
|
180 |
+
py::print("1st lock acquired");
|
181 |
+
|
182 |
+
}
|
183 |
+
|
184 |
+
{
|
185 |
+
py::gil_scoped_acquire lock;
|
186 |
+
py::print("2nd lock acquired");
|
187 |
+
}
|
188 |
+
|
189 |
+
}
|
190 |
+
|
191 |
+
static void test_gil_from_thread() {
|
192 |
+
py::gil_scoped_release release;
|
193 |
+
|
194 |
+
std::thread t(test_gil);
|
195 |
+
t.join();
|
196 |
+
}
|
197 |
+
|
198 |
+
|
199 |
+
// Forward declaration (so that we can put the main tests here; the inherited virtual approaches are
|
200 |
+
// rather long).
|
201 |
+
void initialize_inherited_virtuals(py::module_ &m);
|
202 |
+
|
203 |
+
TEST_SUBMODULE(virtual_functions, m) {
|
204 |
+
// test_override
|
205 |
+
py::class_<ExampleVirt, PyExampleVirt>(m, "ExampleVirt")
|
206 |
+
.def(py::init<int>())
|
207 |
+
/* Reference original class in function definitions */
|
208 |
+
.def("run", &ExampleVirt::run)
|
209 |
+
.def("run_bool", &ExampleVirt::run_bool)
|
210 |
+
.def("pure_virtual", &ExampleVirt::pure_virtual);
|
211 |
+
|
212 |
+
py::class_<NonCopyable>(m, "NonCopyable")
|
213 |
+
.def(py::init<int, int>());
|
214 |
+
|
215 |
+
py::class_<Movable>(m, "Movable")
|
216 |
+
.def(py::init<int, int>());
|
217 |
+
|
218 |
+
// test_move_support
|
219 |
+
#if !defined(__INTEL_COMPILER) && !defined(__CUDACC__) && !defined(__PGIC__)
|
220 |
+
py::class_<NCVirt, NCVirtTrampoline>(m, "NCVirt")
|
221 |
+
.def(py::init<>())
|
222 |
+
.def("get_noncopyable", &NCVirt::get_noncopyable)
|
223 |
+
.def("get_movable", &NCVirt::get_movable)
|
224 |
+
.def("print_nc", &NCVirt::print_nc)
|
225 |
+
.def("print_movable", &NCVirt::print_movable);
|
226 |
+
#endif
|
227 |
+
|
228 |
+
m.def("runExampleVirt", [](ExampleVirt *ex, int value) { return ex->run(value); });
|
229 |
+
m.def("runExampleVirtBool", [](ExampleVirt* ex) { return ex->run_bool(); });
|
230 |
+
m.def("runExampleVirtVirtual", [](ExampleVirt *ex) { ex->pure_virtual(); });
|
231 |
+
|
232 |
+
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
|
233 |
+
initialize_inherited_virtuals(m);
|
234 |
+
|
235 |
+
// test_alias_delay_initialization1
|
236 |
+
// don't invoke Python dispatch classes by default when instantiating C++ classes
|
237 |
+
// that were not extended on the Python side
|
238 |
+
struct A {
|
239 |
+
A() = default;
|
240 |
+
A(const A&) = delete;
|
241 |
+
virtual ~A() = default;
|
242 |
+
virtual void f() { py::print("A.f()"); }
|
243 |
+
};
|
244 |
+
|
245 |
+
struct PyA : A {
|
246 |
+
PyA() { py::print("PyA.PyA()"); }
|
247 |
+
PyA(const PyA&) = delete;
|
248 |
+
~PyA() override { py::print("PyA.~PyA()"); }
|
249 |
+
|
250 |
+
void f() override {
|
251 |
+
py::print("PyA.f()");
|
252 |
+
// This convolution just gives a `void`, but tests that PYBIND11_TYPE() works to protect
|
253 |
+
// a type containing a ,
|
254 |
+
PYBIND11_OVERRIDE(PYBIND11_TYPE(typename std::enable_if<true, void>::type), A, f);
|
255 |
+
}
|
256 |
+
};
|
257 |
+
|
258 |
+
py::class_<A, PyA>(m, "A")
|
259 |
+
.def(py::init<>())
|
260 |
+
.def("f", &A::f);
|
261 |
+
|
262 |
+
m.def("call_f", [](A *a) { a->f(); });
|
263 |
+
|
264 |
+
// test_alias_delay_initialization2
|
265 |
+
// ... unless we explicitly request it, as in this example:
|
266 |
+
struct A2 {
|
267 |
+
A2() = default;
|
268 |
+
A2(const A2&) = delete;
|
269 |
+
virtual ~A2() = default;
|
270 |
+
virtual void f() { py::print("A2.f()"); }
|
271 |
+
};
|
272 |
+
|
273 |
+
struct PyA2 : A2 {
|
274 |
+
PyA2() { py::print("PyA2.PyA2()"); }
|
275 |
+
PyA2(const PyA2&) = delete;
|
276 |
+
~PyA2() override { py::print("PyA2.~PyA2()"); }
|
277 |
+
void f() override {
|
278 |
+
py::print("PyA2.f()");
|
279 |
+
PYBIND11_OVERRIDE(void, A2, f);
|
280 |
+
}
|
281 |
+
};
|
282 |
+
|
283 |
+
py::class_<A2, PyA2>(m, "A2")
|
284 |
+
.def(py::init_alias<>())
|
285 |
+
.def(py::init([](int) { return new PyA2(); }))
|
286 |
+
.def("f", &A2::f);
|
287 |
+
|
288 |
+
m.def("call_f", [](A2 *a2) { a2->f(); });
|
289 |
+
|
290 |
+
// test_dispatch_issue
|
291 |
+
// #159: virtual function dispatch has problems with similar-named functions
|
292 |
+
py::class_<Base, DispatchIssue>(m, "DispatchIssue")
|
293 |
+
.def(py::init<>())
|
294 |
+
.def("dispatch", &Base::dispatch);
|
295 |
+
|
296 |
+
m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
|
297 |
+
|
298 |
+
// test_override_ref
|
299 |
+
// #392/397: overriding reference-returning functions
|
300 |
+
class OverrideTest {
|
301 |
+
public:
|
302 |
+
struct A { std::string value = "hi"; };
|
303 |
+
std::string v;
|
304 |
+
A a;
|
305 |
+
explicit OverrideTest(const std::string &v) : v{v} {}
|
306 |
+
OverrideTest() = default;
|
307 |
+
OverrideTest(const OverrideTest&) = delete;
|
308 |
+
virtual std::string str_value() { return v; }
|
309 |
+
virtual std::string &str_ref() { return v; }
|
310 |
+
virtual A A_value() { return a; }
|
311 |
+
virtual A &A_ref() { return a; }
|
312 |
+
virtual ~OverrideTest() = default;
|
313 |
+
};
|
314 |
+
|
315 |
+
class PyOverrideTest : public OverrideTest {
|
316 |
+
public:
|
317 |
+
using OverrideTest::OverrideTest;
|
318 |
+
std::string str_value() override { PYBIND11_OVERRIDE(std::string, OverrideTest, str_value); }
|
319 |
+
// Not allowed (uncommenting should hit a static_assert failure): we can't get a reference
|
320 |
+
// to a python numeric value, since we only copy values in the numeric type caster:
|
321 |
+
// std::string &str_ref() override { PYBIND11_OVERRIDE(std::string &, OverrideTest, str_ref); }
|
322 |
+
// But we can work around it like this:
|
323 |
+
private:
|
324 |
+
std::string _tmp;
|
325 |
+
std::string str_ref_helper() { PYBIND11_OVERRIDE(std::string, OverrideTest, str_ref); }
|
326 |
+
public:
|
327 |
+
std::string &str_ref() override { return _tmp = str_ref_helper(); }
|
328 |
+
|
329 |
+
A A_value() override { PYBIND11_OVERRIDE(A, OverrideTest, A_value); }
|
330 |
+
A &A_ref() override { PYBIND11_OVERRIDE(A &, OverrideTest, A_ref); }
|
331 |
+
};
|
332 |
+
|
333 |
+
py::class_<OverrideTest::A>(m, "OverrideTest_A")
|
334 |
+
.def_readwrite("value", &OverrideTest::A::value);
|
335 |
+
py::class_<OverrideTest, PyOverrideTest>(m, "OverrideTest")
|
336 |
+
.def(py::init<const std::string &>())
|
337 |
+
.def("str_value", &OverrideTest::str_value)
|
338 |
+
// .def("str_ref", &OverrideTest::str_ref)
|
339 |
+
.def("A_value", &OverrideTest::A_value)
|
340 |
+
.def("A_ref", &OverrideTest::A_ref);
|
341 |
+
}
|
342 |
+
|
343 |
+
|
344 |
+
// Inheriting virtual methods. We do two versions here: the repeat-everything version and the
|
345 |
+
// templated trampoline versions mentioned in docs/advanced.rst.
|
346 |
+
//
|
347 |
+
// These base classes are exactly the same, but we technically need distinct
|
348 |
+
// classes for this example code because we need to be able to bind them
|
349 |
+
// properly (pybind11, sensibly, doesn't allow us to bind the same C++ class to
|
350 |
+
// multiple python classes).
|
351 |
+
class A_Repeat {
|
352 |
+
#define A_METHODS \
|
353 |
+
public: \
|
354 |
+
virtual int unlucky_number() = 0; \
|
355 |
+
virtual std::string say_something(unsigned times) { \
|
356 |
+
std::string s = ""; \
|
357 |
+
for (unsigned i = 0; i < times; ++i) \
|
358 |
+
s += "hi"; \
|
359 |
+
return s; \
|
360 |
+
} \
|
361 |
+
std::string say_everything() { \
|
362 |
+
return say_something(1) + " " + std::to_string(unlucky_number()); \
|
363 |
+
}
|
364 |
+
A_METHODS
|
365 |
+
A_Repeat() = default;
|
366 |
+
A_Repeat(const A_Repeat&) = delete;
|
367 |
+
virtual ~A_Repeat() = default;
|
368 |
+
};
|
369 |
+
class B_Repeat : public A_Repeat {
|
370 |
+
#define B_METHODS \
|
371 |
+
public: \
|
372 |
+
int unlucky_number() override { return 13; } \
|
373 |
+
std::string say_something(unsigned times) override { \
|
374 |
+
return "B says hi " + std::to_string(times) + " times"; \
|
375 |
+
} \
|
376 |
+
virtual double lucky_number() { return 7.0; }
|
377 |
+
B_METHODS
|
378 |
+
};
|
379 |
+
class C_Repeat : public B_Repeat {
|
380 |
+
#define C_METHODS \
|
381 |
+
public: \
|
382 |
+
int unlucky_number() override { return 4444; } \
|
383 |
+
double lucky_number() override { return 888; }
|
384 |
+
C_METHODS
|
385 |
+
};
|
386 |
+
class D_Repeat : public C_Repeat {
|
387 |
+
#define D_METHODS // Nothing overridden.
|
388 |
+
D_METHODS
|
389 |
+
};
|
390 |
+
|
391 |
+
// Base classes for templated inheritance trampolines. Identical to the repeat-everything version:
|
392 |
+
class A_Tpl {
|
393 |
+
A_METHODS;
|
394 |
+
A_Tpl() = default;
|
395 |
+
A_Tpl(const A_Tpl&) = delete;
|
396 |
+
virtual ~A_Tpl() = default;
|
397 |
+
};
|
398 |
+
class B_Tpl : public A_Tpl { B_METHODS };
|
399 |
+
class C_Tpl : public B_Tpl { C_METHODS };
|
400 |
+
class D_Tpl : public C_Tpl { D_METHODS };
|
401 |
+
|
402 |
+
|
403 |
+
// Inheritance approach 1: each trampoline gets every virtual method (11 in total)
|
404 |
+
class PyA_Repeat : public A_Repeat {
|
405 |
+
public:
|
406 |
+
using A_Repeat::A_Repeat;
|
407 |
+
int unlucky_number() override { PYBIND11_OVERRIDE_PURE(int, A_Repeat, unlucky_number, ); }
|
408 |
+
std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, A_Repeat, say_something, times); }
|
409 |
+
};
|
410 |
+
class PyB_Repeat : public B_Repeat {
|
411 |
+
public:
|
412 |
+
using B_Repeat::B_Repeat;
|
413 |
+
int unlucky_number() override { PYBIND11_OVERRIDE(int, B_Repeat, unlucky_number, ); }
|
414 |
+
std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, B_Repeat, say_something, times); }
|
415 |
+
double lucky_number() override { PYBIND11_OVERRIDE(double, B_Repeat, lucky_number, ); }
|
416 |
+
};
|
417 |
+
class PyC_Repeat : public C_Repeat {
|
418 |
+
public:
|
419 |
+
using C_Repeat::C_Repeat;
|
420 |
+
int unlucky_number() override { PYBIND11_OVERRIDE(int, C_Repeat, unlucky_number, ); }
|
421 |
+
std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, C_Repeat, say_something, times); }
|
422 |
+
double lucky_number() override { PYBIND11_OVERRIDE(double, C_Repeat, lucky_number, ); }
|
423 |
+
};
|
424 |
+
class PyD_Repeat : public D_Repeat {
|
425 |
+
public:
|
426 |
+
using D_Repeat::D_Repeat;
|
427 |
+
int unlucky_number() override { PYBIND11_OVERRIDE(int, D_Repeat, unlucky_number, ); }
|
428 |
+
std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, D_Repeat, say_something, times); }
|
429 |
+
double lucky_number() override { PYBIND11_OVERRIDE(double, D_Repeat, lucky_number, ); }
|
430 |
+
};
|
431 |
+
|
432 |
+
// Inheritance approach 2: templated trampoline classes.
|
433 |
+
//
|
434 |
+
// Advantages:
|
435 |
+
// - we have only 2 (template) class and 4 method declarations (one per virtual method, plus one for
|
436 |
+
// any override of a pure virtual method), versus 4 classes and 6 methods (MI) or 4 classes and 11
|
437 |
+
// methods (repeat).
|
438 |
+
// - Compared to MI, we also don't have to change the non-trampoline inheritance to virtual, and can
|
439 |
+
// properly inherit constructors.
|
440 |
+
//
|
441 |
+
// Disadvantage:
|
442 |
+
// - the compiler must still generate and compile 14 different methods (more, even, than the 11
|
443 |
+
// required for the repeat approach) instead of the 6 required for MI. (If there was no pure
|
444 |
+
// method (or no pure method override), the number would drop down to the same 11 as the repeat
|
445 |
+
// approach).
|
446 |
+
template <class Base = A_Tpl>
|
447 |
+
class PyA_Tpl : public Base {
|
448 |
+
public:
|
449 |
+
using Base::Base; // Inherit constructors
|
450 |
+
int unlucky_number() override { PYBIND11_OVERRIDE_PURE(int, Base, unlucky_number, ); }
|
451 |
+
std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, Base, say_something, times); }
|
452 |
+
};
|
453 |
+
template <class Base = B_Tpl>
|
454 |
+
class PyB_Tpl : public PyA_Tpl<Base> {
|
455 |
+
public:
|
456 |
+
using PyA_Tpl<Base>::PyA_Tpl; // Inherit constructors (via PyA_Tpl's inherited constructors)
|
457 |
+
int unlucky_number() override { PYBIND11_OVERRIDE(int, Base, unlucky_number, ); }
|
458 |
+
double lucky_number() override { PYBIND11_OVERRIDE(double, Base, lucky_number, ); }
|
459 |
+
};
|
460 |
+
// Since C_Tpl and D_Tpl don't declare any new virtual methods, we don't actually need these (we can
|
461 |
+
// use PyB_Tpl<C_Tpl> and PyB_Tpl<D_Tpl> for the trampoline classes instead):
|
462 |
+
/*
|
463 |
+
template <class Base = C_Tpl> class PyC_Tpl : public PyB_Tpl<Base> {
|
464 |
+
public:
|
465 |
+
using PyB_Tpl<Base>::PyB_Tpl;
|
466 |
+
};
|
467 |
+
template <class Base = D_Tpl> class PyD_Tpl : public PyC_Tpl<Base> {
|
468 |
+
public:
|
469 |
+
using PyC_Tpl<Base>::PyC_Tpl;
|
470 |
+
};
|
471 |
+
*/
|
472 |
+
|
473 |
+
void initialize_inherited_virtuals(py::module_ &m) {
|
474 |
+
// test_inherited_virtuals
|
475 |
+
|
476 |
+
// Method 1: repeat
|
477 |
+
py::class_<A_Repeat, PyA_Repeat>(m, "A_Repeat")
|
478 |
+
.def(py::init<>())
|
479 |
+
.def("unlucky_number", &A_Repeat::unlucky_number)
|
480 |
+
.def("say_something", &A_Repeat::say_something)
|
481 |
+
.def("say_everything", &A_Repeat::say_everything);
|
482 |
+
py::class_<B_Repeat, A_Repeat, PyB_Repeat>(m, "B_Repeat")
|
483 |
+
.def(py::init<>())
|
484 |
+
.def("lucky_number", &B_Repeat::lucky_number);
|
485 |
+
py::class_<C_Repeat, B_Repeat, PyC_Repeat>(m, "C_Repeat")
|
486 |
+
.def(py::init<>());
|
487 |
+
py::class_<D_Repeat, C_Repeat, PyD_Repeat>(m, "D_Repeat")
|
488 |
+
.def(py::init<>());
|
489 |
+
|
490 |
+
// test_
|
491 |
+
// Method 2: Templated trampolines
|
492 |
+
py::class_<A_Tpl, PyA_Tpl<>>(m, "A_Tpl")
|
493 |
+
.def(py::init<>())
|
494 |
+
.def("unlucky_number", &A_Tpl::unlucky_number)
|
495 |
+
.def("say_something", &A_Tpl::say_something)
|
496 |
+
.def("say_everything", &A_Tpl::say_everything);
|
497 |
+
py::class_<B_Tpl, A_Tpl, PyB_Tpl<>>(m, "B_Tpl")
|
498 |
+
.def(py::init<>())
|
499 |
+
.def("lucky_number", &B_Tpl::lucky_number);
|
500 |
+
py::class_<C_Tpl, B_Tpl, PyB_Tpl<C_Tpl>>(m, "C_Tpl")
|
501 |
+
.def(py::init<>());
|
502 |
+
py::class_<D_Tpl, C_Tpl, PyB_Tpl<D_Tpl>>(m, "D_Tpl")
|
503 |
+
.def(py::init<>());
|
504 |
+
|
505 |
+
|
506 |
+
// Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
|
507 |
+
m.def("test_gil", &test_gil);
|
508 |
+
m.def("test_gil_from_thread", &test_gil_from_thread);
|
509 |
+
};
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/test_virtual_functions.py
ADDED
@@ -0,0 +1,408 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
import pytest
|
3 |
+
|
4 |
+
import env # noqa: F401
|
5 |
+
|
6 |
+
m = pytest.importorskip("pybind11_tests.virtual_functions")
|
7 |
+
from pybind11_tests import ConstructorStats # noqa: E402
|
8 |
+
|
9 |
+
|
10 |
+
def test_override(capture, msg):
|
11 |
+
class ExtendedExampleVirt(m.ExampleVirt):
|
12 |
+
def __init__(self, state):
|
13 |
+
super(ExtendedExampleVirt, self).__init__(state + 1)
|
14 |
+
self.data = "Hello world"
|
15 |
+
|
16 |
+
def run(self, value):
|
17 |
+
print("ExtendedExampleVirt::run(%i), calling parent.." % value)
|
18 |
+
return super(ExtendedExampleVirt, self).run(value + 1)
|
19 |
+
|
20 |
+
def run_bool(self):
|
21 |
+
print("ExtendedExampleVirt::run_bool()")
|
22 |
+
return False
|
23 |
+
|
24 |
+
def get_string1(self):
|
25 |
+
return "override1"
|
26 |
+
|
27 |
+
def pure_virtual(self):
|
28 |
+
print("ExtendedExampleVirt::pure_virtual(): %s" % self.data)
|
29 |
+
|
30 |
+
class ExtendedExampleVirt2(ExtendedExampleVirt):
|
31 |
+
def __init__(self, state):
|
32 |
+
super(ExtendedExampleVirt2, self).__init__(state + 1)
|
33 |
+
|
34 |
+
def get_string2(self):
|
35 |
+
return "override2"
|
36 |
+
|
37 |
+
ex12 = m.ExampleVirt(10)
|
38 |
+
with capture:
|
39 |
+
assert m.runExampleVirt(ex12, 20) == 30
|
40 |
+
assert (
|
41 |
+
capture
|
42 |
+
== """
|
43 |
+
Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)
|
44 |
+
""" # noqa: E501 line too long
|
45 |
+
)
|
46 |
+
|
47 |
+
with pytest.raises(RuntimeError) as excinfo:
|
48 |
+
m.runExampleVirtVirtual(ex12)
|
49 |
+
assert (
|
50 |
+
msg(excinfo.value)
|
51 |
+
== 'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
|
52 |
+
)
|
53 |
+
|
54 |
+
ex12p = ExtendedExampleVirt(10)
|
55 |
+
with capture:
|
56 |
+
assert m.runExampleVirt(ex12p, 20) == 32
|
57 |
+
assert (
|
58 |
+
capture
|
59 |
+
== """
|
60 |
+
ExtendedExampleVirt::run(20), calling parent..
|
61 |
+
Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)
|
62 |
+
""" # noqa: E501 line too long
|
63 |
+
)
|
64 |
+
with capture:
|
65 |
+
assert m.runExampleVirtBool(ex12p) is False
|
66 |
+
assert capture == "ExtendedExampleVirt::run_bool()"
|
67 |
+
with capture:
|
68 |
+
m.runExampleVirtVirtual(ex12p)
|
69 |
+
assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world"
|
70 |
+
|
71 |
+
ex12p2 = ExtendedExampleVirt2(15)
|
72 |
+
with capture:
|
73 |
+
assert m.runExampleVirt(ex12p2, 50) == 68
|
74 |
+
assert (
|
75 |
+
capture
|
76 |
+
== """
|
77 |
+
ExtendedExampleVirt::run(50), calling parent..
|
78 |
+
Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)
|
79 |
+
""" # noqa: E501 line too long
|
80 |
+
)
|
81 |
+
|
82 |
+
cstats = ConstructorStats.get(m.ExampleVirt)
|
83 |
+
assert cstats.alive() == 3
|
84 |
+
del ex12, ex12p, ex12p2
|
85 |
+
assert cstats.alive() == 0
|
86 |
+
assert cstats.values() == ["10", "11", "17"]
|
87 |
+
assert cstats.copy_constructions == 0
|
88 |
+
assert cstats.move_constructions >= 0
|
89 |
+
|
90 |
+
|
91 |
+
def test_alias_delay_initialization1(capture):
|
92 |
+
"""`A` only initializes its trampoline class when we inherit from it
|
93 |
+
|
94 |
+
If we just create and use an A instance directly, the trampoline initialization is
|
95 |
+
bypassed and we only initialize an A() instead (for performance reasons).
|
96 |
+
"""
|
97 |
+
|
98 |
+
class B(m.A):
|
99 |
+
def __init__(self):
|
100 |
+
super(B, self).__init__()
|
101 |
+
|
102 |
+
def f(self):
|
103 |
+
print("In python f()")
|
104 |
+
|
105 |
+
# C++ version
|
106 |
+
with capture:
|
107 |
+
a = m.A()
|
108 |
+
m.call_f(a)
|
109 |
+
del a
|
110 |
+
pytest.gc_collect()
|
111 |
+
assert capture == "A.f()"
|
112 |
+
|
113 |
+
# Python version
|
114 |
+
with capture:
|
115 |
+
b = B()
|
116 |
+
m.call_f(b)
|
117 |
+
del b
|
118 |
+
pytest.gc_collect()
|
119 |
+
assert (
|
120 |
+
capture
|
121 |
+
== """
|
122 |
+
PyA.PyA()
|
123 |
+
PyA.f()
|
124 |
+
In python f()
|
125 |
+
PyA.~PyA()
|
126 |
+
"""
|
127 |
+
)
|
128 |
+
|
129 |
+
|
130 |
+
def test_alias_delay_initialization2(capture):
|
131 |
+
"""`A2`, unlike the above, is configured to always initialize the alias
|
132 |
+
|
133 |
+
While the extra initialization and extra class layer has small virtual dispatch
|
134 |
+
performance penalty, it also allows us to do more things with the trampoline
|
135 |
+
class such as defining local variables and performing construction/destruction.
|
136 |
+
"""
|
137 |
+
|
138 |
+
class B2(m.A2):
|
139 |
+
def __init__(self):
|
140 |
+
super(B2, self).__init__()
|
141 |
+
|
142 |
+
def f(self):
|
143 |
+
print("In python B2.f()")
|
144 |
+
|
145 |
+
# No python subclass version
|
146 |
+
with capture:
|
147 |
+
a2 = m.A2()
|
148 |
+
m.call_f(a2)
|
149 |
+
del a2
|
150 |
+
pytest.gc_collect()
|
151 |
+
a3 = m.A2(1)
|
152 |
+
m.call_f(a3)
|
153 |
+
del a3
|
154 |
+
pytest.gc_collect()
|
155 |
+
assert (
|
156 |
+
capture
|
157 |
+
== """
|
158 |
+
PyA2.PyA2()
|
159 |
+
PyA2.f()
|
160 |
+
A2.f()
|
161 |
+
PyA2.~PyA2()
|
162 |
+
PyA2.PyA2()
|
163 |
+
PyA2.f()
|
164 |
+
A2.f()
|
165 |
+
PyA2.~PyA2()
|
166 |
+
"""
|
167 |
+
)
|
168 |
+
|
169 |
+
# Python subclass version
|
170 |
+
with capture:
|
171 |
+
b2 = B2()
|
172 |
+
m.call_f(b2)
|
173 |
+
del b2
|
174 |
+
pytest.gc_collect()
|
175 |
+
assert (
|
176 |
+
capture
|
177 |
+
== """
|
178 |
+
PyA2.PyA2()
|
179 |
+
PyA2.f()
|
180 |
+
In python B2.f()
|
181 |
+
PyA2.~PyA2()
|
182 |
+
"""
|
183 |
+
)
|
184 |
+
|
185 |
+
|
186 |
+
# PyPy: Reference count > 1 causes call with noncopyable instance
|
187 |
+
# to fail in ncv1.print_nc()
|
188 |
+
@pytest.mark.xfail("env.PYPY")
|
189 |
+
@pytest.mark.skipif(
|
190 |
+
not hasattr(m, "NCVirt"), reason="NCVirt does not work on Intel/PGI/NVCC compilers"
|
191 |
+
)
|
192 |
+
def test_move_support():
|
193 |
+
class NCVirtExt(m.NCVirt):
|
194 |
+
def get_noncopyable(self, a, b):
|
195 |
+
# Constructs and returns a new instance:
|
196 |
+
nc = m.NonCopyable(a * a, b * b)
|
197 |
+
return nc
|
198 |
+
|
199 |
+
def get_movable(self, a, b):
|
200 |
+
# Return a referenced copy
|
201 |
+
self.movable = m.Movable(a, b)
|
202 |
+
return self.movable
|
203 |
+
|
204 |
+
class NCVirtExt2(m.NCVirt):
|
205 |
+
def get_noncopyable(self, a, b):
|
206 |
+
# Keep a reference: this is going to throw an exception
|
207 |
+
self.nc = m.NonCopyable(a, b)
|
208 |
+
return self.nc
|
209 |
+
|
210 |
+
def get_movable(self, a, b):
|
211 |
+
# Return a new instance without storing it
|
212 |
+
return m.Movable(a, b)
|
213 |
+
|
214 |
+
ncv1 = NCVirtExt()
|
215 |
+
assert ncv1.print_nc(2, 3) == "36"
|
216 |
+
assert ncv1.print_movable(4, 5) == "9"
|
217 |
+
ncv2 = NCVirtExt2()
|
218 |
+
assert ncv2.print_movable(7, 7) == "14"
|
219 |
+
# Don't check the exception message here because it differs under debug/non-debug mode
|
220 |
+
with pytest.raises(RuntimeError):
|
221 |
+
ncv2.print_nc(9, 9)
|
222 |
+
|
223 |
+
nc_stats = ConstructorStats.get(m.NonCopyable)
|
224 |
+
mv_stats = ConstructorStats.get(m.Movable)
|
225 |
+
assert nc_stats.alive() == 1
|
226 |
+
assert mv_stats.alive() == 1
|
227 |
+
del ncv1, ncv2
|
228 |
+
assert nc_stats.alive() == 0
|
229 |
+
assert mv_stats.alive() == 0
|
230 |
+
assert nc_stats.values() == ["4", "9", "9", "9"]
|
231 |
+
assert mv_stats.values() == ["4", "5", "7", "7"]
|
232 |
+
assert nc_stats.copy_constructions == 0
|
233 |
+
assert mv_stats.copy_constructions == 1
|
234 |
+
assert nc_stats.move_constructions >= 0
|
235 |
+
assert mv_stats.move_constructions >= 0
|
236 |
+
|
237 |
+
|
238 |
+
def test_dispatch_issue(msg):
|
239 |
+
"""#159: virtual function dispatch has problems with similar-named functions"""
|
240 |
+
|
241 |
+
class PyClass1(m.DispatchIssue):
|
242 |
+
def dispatch(self):
|
243 |
+
return "Yay.."
|
244 |
+
|
245 |
+
class PyClass2(m.DispatchIssue):
|
246 |
+
def dispatch(self):
|
247 |
+
with pytest.raises(RuntimeError) as excinfo:
|
248 |
+
super(PyClass2, self).dispatch()
|
249 |
+
assert (
|
250 |
+
msg(excinfo.value)
|
251 |
+
== 'Tried to call pure virtual function "Base::dispatch"'
|
252 |
+
)
|
253 |
+
|
254 |
+
return m.dispatch_issue_go(PyClass1())
|
255 |
+
|
256 |
+
b = PyClass2()
|
257 |
+
assert m.dispatch_issue_go(b) == "Yay.."
|
258 |
+
|
259 |
+
|
260 |
+
def test_override_ref():
|
261 |
+
"""#392/397: overriding reference-returning functions"""
|
262 |
+
o = m.OverrideTest("asdf")
|
263 |
+
|
264 |
+
# Not allowed (see associated .cpp comment)
|
265 |
+
# i = o.str_ref()
|
266 |
+
# assert o.str_ref() == "asdf"
|
267 |
+
assert o.str_value() == "asdf"
|
268 |
+
|
269 |
+
assert o.A_value().value == "hi"
|
270 |
+
a = o.A_ref()
|
271 |
+
assert a.value == "hi"
|
272 |
+
a.value = "bye"
|
273 |
+
assert a.value == "bye"
|
274 |
+
|
275 |
+
|
276 |
+
def test_inherited_virtuals():
|
277 |
+
class AR(m.A_Repeat):
|
278 |
+
def unlucky_number(self):
|
279 |
+
return 99
|
280 |
+
|
281 |
+
class AT(m.A_Tpl):
|
282 |
+
def unlucky_number(self):
|
283 |
+
return 999
|
284 |
+
|
285 |
+
obj = AR()
|
286 |
+
assert obj.say_something(3) == "hihihi"
|
287 |
+
assert obj.unlucky_number() == 99
|
288 |
+
assert obj.say_everything() == "hi 99"
|
289 |
+
|
290 |
+
obj = AT()
|
291 |
+
assert obj.say_something(3) == "hihihi"
|
292 |
+
assert obj.unlucky_number() == 999
|
293 |
+
assert obj.say_everything() == "hi 999"
|
294 |
+
|
295 |
+
for obj in [m.B_Repeat(), m.B_Tpl()]:
|
296 |
+
assert obj.say_something(3) == "B says hi 3 times"
|
297 |
+
assert obj.unlucky_number() == 13
|
298 |
+
assert obj.lucky_number() == 7.0
|
299 |
+
assert obj.say_everything() == "B says hi 1 times 13"
|
300 |
+
|
301 |
+
for obj in [m.C_Repeat(), m.C_Tpl()]:
|
302 |
+
assert obj.say_something(3) == "B says hi 3 times"
|
303 |
+
assert obj.unlucky_number() == 4444
|
304 |
+
assert obj.lucky_number() == 888.0
|
305 |
+
assert obj.say_everything() == "B says hi 1 times 4444"
|
306 |
+
|
307 |
+
class CR(m.C_Repeat):
|
308 |
+
def lucky_number(self):
|
309 |
+
return m.C_Repeat.lucky_number(self) + 1.25
|
310 |
+
|
311 |
+
obj = CR()
|
312 |
+
assert obj.say_something(3) == "B says hi 3 times"
|
313 |
+
assert obj.unlucky_number() == 4444
|
314 |
+
assert obj.lucky_number() == 889.25
|
315 |
+
assert obj.say_everything() == "B says hi 1 times 4444"
|
316 |
+
|
317 |
+
class CT(m.C_Tpl):
|
318 |
+
pass
|
319 |
+
|
320 |
+
obj = CT()
|
321 |
+
assert obj.say_something(3) == "B says hi 3 times"
|
322 |
+
assert obj.unlucky_number() == 4444
|
323 |
+
assert obj.lucky_number() == 888.0
|
324 |
+
assert obj.say_everything() == "B says hi 1 times 4444"
|
325 |
+
|
326 |
+
class CCR(CR):
|
327 |
+
def lucky_number(self):
|
328 |
+
return CR.lucky_number(self) * 10
|
329 |
+
|
330 |
+
obj = CCR()
|
331 |
+
assert obj.say_something(3) == "B says hi 3 times"
|
332 |
+
assert obj.unlucky_number() == 4444
|
333 |
+
assert obj.lucky_number() == 8892.5
|
334 |
+
assert obj.say_everything() == "B says hi 1 times 4444"
|
335 |
+
|
336 |
+
class CCT(CT):
|
337 |
+
def lucky_number(self):
|
338 |
+
return CT.lucky_number(self) * 1000
|
339 |
+
|
340 |
+
obj = CCT()
|
341 |
+
assert obj.say_something(3) == "B says hi 3 times"
|
342 |
+
assert obj.unlucky_number() == 4444
|
343 |
+
assert obj.lucky_number() == 888000.0
|
344 |
+
assert obj.say_everything() == "B says hi 1 times 4444"
|
345 |
+
|
346 |
+
class DR(m.D_Repeat):
|
347 |
+
def unlucky_number(self):
|
348 |
+
return 123
|
349 |
+
|
350 |
+
def lucky_number(self):
|
351 |
+
return 42.0
|
352 |
+
|
353 |
+
for obj in [m.D_Repeat(), m.D_Tpl()]:
|
354 |
+
assert obj.say_something(3) == "B says hi 3 times"
|
355 |
+
assert obj.unlucky_number() == 4444
|
356 |
+
assert obj.lucky_number() == 888.0
|
357 |
+
assert obj.say_everything() == "B says hi 1 times 4444"
|
358 |
+
|
359 |
+
obj = DR()
|
360 |
+
assert obj.say_something(3) == "B says hi 3 times"
|
361 |
+
assert obj.unlucky_number() == 123
|
362 |
+
assert obj.lucky_number() == 42.0
|
363 |
+
assert obj.say_everything() == "B says hi 1 times 123"
|
364 |
+
|
365 |
+
class DT(m.D_Tpl):
|
366 |
+
def say_something(self, times):
|
367 |
+
return "DT says:" + (" quack" * times)
|
368 |
+
|
369 |
+
def unlucky_number(self):
|
370 |
+
return 1234
|
371 |
+
|
372 |
+
def lucky_number(self):
|
373 |
+
return -4.25
|
374 |
+
|
375 |
+
obj = DT()
|
376 |
+
assert obj.say_something(3) == "DT says: quack quack quack"
|
377 |
+
assert obj.unlucky_number() == 1234
|
378 |
+
assert obj.lucky_number() == -4.25
|
379 |
+
assert obj.say_everything() == "DT says: quack 1234"
|
380 |
+
|
381 |
+
class DT2(DT):
|
382 |
+
def say_something(self, times):
|
383 |
+
return "DT2: " + ("QUACK" * times)
|
384 |
+
|
385 |
+
def unlucky_number(self):
|
386 |
+
return -3
|
387 |
+
|
388 |
+
class BT(m.B_Tpl):
|
389 |
+
def say_something(self, times):
|
390 |
+
return "BT" * times
|
391 |
+
|
392 |
+
def unlucky_number(self):
|
393 |
+
return -7
|
394 |
+
|
395 |
+
def lucky_number(self):
|
396 |
+
return -1.375
|
397 |
+
|
398 |
+
obj = BT()
|
399 |
+
assert obj.say_something(3) == "BTBTBT"
|
400 |
+
assert obj.unlucky_number() == -7
|
401 |
+
assert obj.lucky_number() == -1.375
|
402 |
+
assert obj.say_everything() == "BT -7"
|
403 |
+
|
404 |
+
|
405 |
+
def test_issue_1454():
|
406 |
+
# Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
|
407 |
+
m.test_gil()
|
408 |
+
m.test_gil_from_thread()
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/valgrind-numpy-scipy.supp
ADDED
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Valgrind suppression file for NumPy & SciPy errors and leaks in pybind11 tests
|
2 |
+
#
|
3 |
+
# On updating a dependency, to get a list of "default" leaks in e.g. NumPy, run
|
4 |
+
# `PYTHONMALLOC=malloc valgrind --leak-check=full --show-leak-kinds=definite,indirect python3.9-dbg -c "import numpy"`
|
5 |
+
# To use these suppression files, add e.g. `--suppressions=valgrind-numpy-scipy.supp`
|
6 |
+
|
7 |
+
{
|
8 |
+
Leaks when importing NumPy
|
9 |
+
Memcheck:Leak
|
10 |
+
fun:malloc
|
11 |
+
fun:_PyMem_RawMalloc
|
12 |
+
fun:PyObject_Malloc
|
13 |
+
fun:_PyObject_GC_Alloc
|
14 |
+
fun:_PyObject_GC_Malloc
|
15 |
+
fun:_PyObject_GC_NewVar
|
16 |
+
fun:tuple_alloc
|
17 |
+
fun:PyTuple_Pack
|
18 |
+
...
|
19 |
+
fun:__pyx_pymod_exec_*
|
20 |
+
}
|
21 |
+
|
22 |
+
{
|
23 |
+
Leaks when importing NumPy (bis)
|
24 |
+
Memcheck:Leak
|
25 |
+
fun:malloc
|
26 |
+
fun:_PyMem_RawMalloc
|
27 |
+
fun:PyObject_Malloc
|
28 |
+
fun:_PyObject_New
|
29 |
+
fun:PyCode_NewWithPosOnlyArgs
|
30 |
+
fun:PyCode_New
|
31 |
+
...
|
32 |
+
fun:__pyx_pymod_exec_*
|
33 |
+
}
|
34 |
+
|
35 |
+
{
|
36 |
+
Leaks when importing NumPy (ter)
|
37 |
+
Memcheck:Leak
|
38 |
+
fun:malloc
|
39 |
+
fun:_PyMem_RawMalloc
|
40 |
+
fun:PyObject_Malloc
|
41 |
+
fun:_PyObject_GC_Alloc
|
42 |
+
fun:_PyObject_GC_Malloc
|
43 |
+
fun:_PyObject_GC_NewVar
|
44 |
+
fun:tuple_alloc
|
45 |
+
fun:_PyTuple_FromArray
|
46 |
+
fun:_PyObject_MakeTpCall
|
47 |
+
fun:_PyObject_VectorcallTstate
|
48 |
+
fun:PyObject_Vectorcall
|
49 |
+
fun:call_function
|
50 |
+
fun:_PyEval_EvalFrameDefault
|
51 |
+
fun:_PyEval_EvalFrame
|
52 |
+
fun:function_code_fastcall
|
53 |
+
fun:_PyFunction_Vectorcall
|
54 |
+
}
|
55 |
+
|
56 |
+
{
|
57 |
+
Leaks when importing NumPy (quater)
|
58 |
+
Memcheck:Leak
|
59 |
+
fun:malloc
|
60 |
+
fun:_PyMem_RawMalloc
|
61 |
+
fun:PyObject_Malloc
|
62 |
+
fun:_PyObject_GC_Alloc
|
63 |
+
fun:_PyObject_GC_Malloc
|
64 |
+
fun:_PyObject_GC_NewVar
|
65 |
+
fun:tuple_alloc
|
66 |
+
fun:_PyTuple_FromArray
|
67 |
+
fun:_PyObject_MakeTpCall
|
68 |
+
fun:_PyObject_VectorcallTstate
|
69 |
+
fun:_PyObject_CallFunctionVa
|
70 |
+
fun:PyObject_CallFunction
|
71 |
+
fun:PyImport_Import
|
72 |
+
}
|
73 |
+
|
74 |
+
{
|
75 |
+
Leaks when importing NumPy (quinquies)
|
76 |
+
Memcheck:Leak
|
77 |
+
fun:malloc
|
78 |
+
fun:_PyMem_RawMalloc
|
79 |
+
fun:PyObject_Malloc
|
80 |
+
fun:_PyObject_GC_Alloc
|
81 |
+
fun:_PyObject_GC_Malloc
|
82 |
+
fun:_PyObject_GC_NewVar
|
83 |
+
fun:tuple_alloc
|
84 |
+
fun:PyTuple_New
|
85 |
+
fun:r_object
|
86 |
+
fun:r_object
|
87 |
+
fun:r_object
|
88 |
+
fun:r_object
|
89 |
+
}
|
90 |
+
|
91 |
+
{
|
92 |
+
Leaks when importing NumPy (sexies)
|
93 |
+
Memcheck:Leak
|
94 |
+
fun:malloc
|
95 |
+
fun:_PyMem_RawMalloc
|
96 |
+
fun:PyObject_Malloc
|
97 |
+
fun:_PyObject_GC_Alloc
|
98 |
+
fun:_PyObject_GC_Malloc
|
99 |
+
fun:_PyObject_GC_NewVar
|
100 |
+
fun:tuple_alloc
|
101 |
+
fun:PyTuple_New
|
102 |
+
fun:dictiter_iternextitem
|
103 |
+
fun:list_extend
|
104 |
+
fun:_PyList_Extend
|
105 |
+
fun:PySequence_List
|
106 |
+
}
|
107 |
+
|
108 |
+
{
|
109 |
+
Leak when importing scipy.fft
|
110 |
+
Memcheck:Leak
|
111 |
+
fun:_Znwm
|
112 |
+
fun:PyInit_pypocketfft
|
113 |
+
fun:_PyImport_LoadDynamicModuleWithSpec
|
114 |
+
fun:_imp_create_dynamic_impl*
|
115 |
+
fun:_imp_create_dynamic
|
116 |
+
fun:cfunction_vectorcall_FASTCALL
|
117 |
+
fun:PyVectorcall_Call
|
118 |
+
fun:_PyObject_Call
|
119 |
+
fun:PyObject_Call
|
120 |
+
fun:do_call_core
|
121 |
+
fun:_PyEval_EvalFrameDefault
|
122 |
+
fun:_PyEval_EvalFrame
|
123 |
+
fun:_PyEval_EvalCode
|
124 |
+
}
|
125 |
+
|
126 |
+
{
|
127 |
+
NumPy leaks when spawning a subprocess
|
128 |
+
Memcheck:Leak
|
129 |
+
fun:malloc
|
130 |
+
...
|
131 |
+
fun:_buffer_get_info
|
132 |
+
fun:array_getbuffer
|
133 |
+
fun:PyObject_GetBuffer
|
134 |
+
fun:__Pyx__GetBufferAndValidate*
|
135 |
+
fun:__pyx_f_5numpy_6random_13bit_generator_12SeedSequence_mix_entropy
|
136 |
+
fun:__pyx_pw_5numpy_6random_13bit_generator_12SeedSequence_1__init__
|
137 |
+
fun:type_call
|
138 |
+
fun:__Pyx__PyObject_CallOneArg
|
139 |
+
fun:__pyx_pw_5numpy_6random_13bit_generator_12BitGenerator_1__init__
|
140 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tests/valgrind-python.supp
ADDED
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Valgrind suppression file for CPython errors and leaks in pybind11 tests
|
2 |
+
|
3 |
+
# Taken verbatim from https://github.com/python/cpython/blob/3.9/Misc/valgrind-python.supp#L266-L272
|
4 |
+
{
|
5 |
+
Uninitialised byte(s) false alarm, see bpo-35561
|
6 |
+
Memcheck:Param
|
7 |
+
epoll_ctl(event)
|
8 |
+
fun:epoll_ctl
|
9 |
+
fun:pyepoll_internal_ctl
|
10 |
+
}
|
11 |
+
|
12 |
+
{
|
13 |
+
Python leaks when spawning a subprocess
|
14 |
+
Memcheck:Leak
|
15 |
+
fun:malloc
|
16 |
+
fun:_PyMem_RawMalloc
|
17 |
+
fun:PyMem_RawMalloc
|
18 |
+
fun:PyThread_allocate_lock
|
19 |
+
fun:_PyEval_InitState
|
20 |
+
fun:PyInterpreterState_New
|
21 |
+
...
|
22 |
+
fun:pyinit_core*
|
23 |
+
fun:Py_InitializeFromConfig
|
24 |
+
fun:pymain_init
|
25 |
+
fun:pymain_main
|
26 |
+
}
|
27 |
+
|
28 |
+
{
|
29 |
+
Python leaks when spawning a subprocess
|
30 |
+
Memcheck:Leak
|
31 |
+
fun:malloc
|
32 |
+
fun:_PyMem_RawMalloc
|
33 |
+
fun:_PyMem_DebugRawAlloc
|
34 |
+
fun:_PyMem_DebugRawMalloc
|
35 |
+
fun:PyMem_RawMalloc
|
36 |
+
fun:PyThread_allocate_lock
|
37 |
+
fun:_PyRuntimeState_Init_impl
|
38 |
+
fun:_PyRuntimeState_Init
|
39 |
+
fun:_PyRuntime_Initialize
|
40 |
+
fun:pymain_init
|
41 |
+
fun:pymain_main
|
42 |
+
fun:Py_BytesMain
|
43 |
+
}
|
44 |
+
|
45 |
+
{
|
46 |
+
Python leaks when spawning a subprocess
|
47 |
+
Memcheck:Leak
|
48 |
+
fun:malloc
|
49 |
+
fun:_PyMem_RawMalloc
|
50 |
+
fun:PyMem_RawMalloc
|
51 |
+
fun:PyThread_allocate_lock
|
52 |
+
fun:_PyImport_AcquireLock
|
53 |
+
fun:_imp_acquire_lock_impl*
|
54 |
+
fun:_imp_acquire_lock
|
55 |
+
fun:cfunction_vectorcall_NOARGS
|
56 |
+
fun:_PyObject_VectorcallTstate
|
57 |
+
fun:PyObject_Vectorcall
|
58 |
+
fun:call_function
|
59 |
+
fun:_PyEval_EvalFrameDefault
|
60 |
+
fun:_PyEval_EvalFrame
|
61 |
+
fun:function_code_fastcall
|
62 |
+
}
|
63 |
+
|
64 |
+
{
|
65 |
+
Python leaks when spawning a subprocess
|
66 |
+
Memcheck:Leak
|
67 |
+
fun:malloc
|
68 |
+
fun:_PyMem_RawMalloc
|
69 |
+
fun:PyMem_RawMalloc
|
70 |
+
fun:PyThread_allocate_lock
|
71 |
+
fun:newlockobject
|
72 |
+
...
|
73 |
+
fun:cfunction_vectorcall_NOARGS
|
74 |
+
fun:_PyObject_VectorcallTstate
|
75 |
+
fun:PyObject_Vectorcall
|
76 |
+
fun:call_function
|
77 |
+
fun:_PyEval_EvalFrameDefault
|
78 |
+
fun:_PyEval_EvalFrame
|
79 |
+
fun:function_code_fastcall
|
80 |
+
fun:_PyFunction_Vectorcall
|
81 |
+
}
|
82 |
+
|
83 |
+
{
|
84 |
+
Python leaks when spawning a subprocess
|
85 |
+
Memcheck:Leak
|
86 |
+
fun:malloc
|
87 |
+
fun:_PyMem_RawMalloc
|
88 |
+
fun:PyMem_RawMalloc
|
89 |
+
fun:PyThread_allocate_lock
|
90 |
+
fun:rlock_new
|
91 |
+
fun:type_call
|
92 |
+
fun:_PyObject_Call
|
93 |
+
fun:PyObject_Call
|
94 |
+
fun:do_call_core
|
95 |
+
fun:_PyEval_EvalFrameDefault
|
96 |
+
fun:_PyEval_EvalFrame
|
97 |
+
fun:_PyEval_EvalCode
|
98 |
+
fun:_PyFunction_Vectorcall
|
99 |
+
}
|
100 |
+
|
101 |
+
# Not really CPython-specific, see link
|
102 |
+
{
|
103 |
+
dlopen leak (https://stackoverflow.com/questions/1542457/memory-leak-reported-by-valgrind-in-dlopen)
|
104 |
+
Memcheck:Leak
|
105 |
+
fun:malloc
|
106 |
+
...
|
107 |
+
fun:dl_open_worker
|
108 |
+
fun:_dl_catch_exception
|
109 |
+
fun:_dl_open
|
110 |
+
fun:dlopen_doit
|
111 |
+
fun:_dl_catch_exception
|
112 |
+
fun:_dl_catch_error
|
113 |
+
fun:_dlerror_run
|
114 |
+
fun:dlopen@@GLIBC_2.2.5
|
115 |
+
fun:_PyImport_FindSharedFuncptr
|
116 |
+
fun:_PyImport_LoadDynamicModuleWithSpec
|
117 |
+
}
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/FindCatch.cmake
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# - Find the Catch test framework or download it (single header)
|
2 |
+
#
|
3 |
+
# This is a quick module for internal use. It assumes that Catch is
|
4 |
+
# REQUIRED and that a minimum version is provided (not EXACT). If
|
5 |
+
# a suitable version isn't found locally, the single header file
|
6 |
+
# will be downloaded and placed in the build dir: PROJECT_BINARY_DIR.
|
7 |
+
#
|
8 |
+
# This code sets the following variables:
|
9 |
+
# CATCH_INCLUDE_DIR - path to catch.hpp
|
10 |
+
# CATCH_VERSION - version number
|
11 |
+
|
12 |
+
if(NOT Catch_FIND_VERSION)
|
13 |
+
message(FATAL_ERROR "A version number must be specified.")
|
14 |
+
elseif(Catch_FIND_REQUIRED)
|
15 |
+
message(FATAL_ERROR "This module assumes Catch is not required.")
|
16 |
+
elseif(Catch_FIND_VERSION_EXACT)
|
17 |
+
message(FATAL_ERROR "Exact version numbers are not supported, only minimum.")
|
18 |
+
endif()
|
19 |
+
|
20 |
+
# Extract the version number from catch.hpp
|
21 |
+
function(_get_catch_version)
|
22 |
+
file(
|
23 |
+
STRINGS "${CATCH_INCLUDE_DIR}/catch.hpp" version_line
|
24 |
+
REGEX "Catch v.*"
|
25 |
+
LIMIT_COUNT 1)
|
26 |
+
if(version_line MATCHES "Catch v([0-9]+)\\.([0-9]+)\\.([0-9]+)")
|
27 |
+
set(CATCH_VERSION
|
28 |
+
"${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}"
|
29 |
+
PARENT_SCOPE)
|
30 |
+
endif()
|
31 |
+
endfunction()
|
32 |
+
|
33 |
+
# Download the single-header version of Catch
|
34 |
+
function(_download_catch version destination_dir)
|
35 |
+
message(STATUS "Downloading catch v${version}...")
|
36 |
+
set(url https://github.com/philsquared/Catch/releases/download/v${version}/catch.hpp)
|
37 |
+
file(DOWNLOAD ${url} "${destination_dir}/catch.hpp" STATUS status)
|
38 |
+
list(GET status 0 error)
|
39 |
+
if(error)
|
40 |
+
message(FATAL_ERROR "Could not download ${url}")
|
41 |
+
endif()
|
42 |
+
set(CATCH_INCLUDE_DIR
|
43 |
+
"${destination_dir}"
|
44 |
+
CACHE INTERNAL "")
|
45 |
+
endfunction()
|
46 |
+
|
47 |
+
# Look for catch locally
|
48 |
+
find_path(
|
49 |
+
CATCH_INCLUDE_DIR
|
50 |
+
NAMES catch.hpp
|
51 |
+
PATH_SUFFIXES catch2)
|
52 |
+
if(CATCH_INCLUDE_DIR)
|
53 |
+
_get_catch_version()
|
54 |
+
endif()
|
55 |
+
|
56 |
+
# Download the header if it wasn't found or if it's outdated
|
57 |
+
if(NOT CATCH_VERSION OR CATCH_VERSION VERSION_LESS ${Catch_FIND_VERSION})
|
58 |
+
if(DOWNLOAD_CATCH)
|
59 |
+
_download_catch(${Catch_FIND_VERSION} "${PROJECT_BINARY_DIR}/catch/")
|
60 |
+
_get_catch_version()
|
61 |
+
else()
|
62 |
+
set(CATCH_FOUND FALSE)
|
63 |
+
return()
|
64 |
+
endif()
|
65 |
+
endif()
|
66 |
+
|
67 |
+
add_library(Catch2::Catch2 IMPORTED INTERFACE)
|
68 |
+
set_property(TARGET Catch2::Catch2 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CATCH_INCLUDE_DIR}")
|
69 |
+
|
70 |
+
set(CATCH_FOUND TRUE)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/FindEigen3.cmake
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# - Try to find Eigen3 lib
|
2 |
+
#
|
3 |
+
# This module supports requiring a minimum version, e.g. you can do
|
4 |
+
# find_package(Eigen3 3.1.2)
|
5 |
+
# to require version 3.1.2 or newer of Eigen3.
|
6 |
+
#
|
7 |
+
# Once done this will define
|
8 |
+
#
|
9 |
+
# EIGEN3_FOUND - system has eigen lib with correct version
|
10 |
+
# EIGEN3_INCLUDE_DIR - the eigen include directory
|
11 |
+
# EIGEN3_VERSION - eigen version
|
12 |
+
|
13 |
+
# Copyright (c) 2006, 2007 Montel Laurent, <[email protected]>
|
14 |
+
# Copyright (c) 2008, 2009 Gael Guennebaud, <[email protected]>
|
15 |
+
# Copyright (c) 2009 Benoit Jacob <[email protected]>
|
16 |
+
# Redistribution and use is allowed according to the terms of the 2-clause BSD license.
|
17 |
+
|
18 |
+
if(NOT Eigen3_FIND_VERSION)
|
19 |
+
if(NOT Eigen3_FIND_VERSION_MAJOR)
|
20 |
+
set(Eigen3_FIND_VERSION_MAJOR 2)
|
21 |
+
endif(NOT Eigen3_FIND_VERSION_MAJOR)
|
22 |
+
if(NOT Eigen3_FIND_VERSION_MINOR)
|
23 |
+
set(Eigen3_FIND_VERSION_MINOR 91)
|
24 |
+
endif(NOT Eigen3_FIND_VERSION_MINOR)
|
25 |
+
if(NOT Eigen3_FIND_VERSION_PATCH)
|
26 |
+
set(Eigen3_FIND_VERSION_PATCH 0)
|
27 |
+
endif(NOT Eigen3_FIND_VERSION_PATCH)
|
28 |
+
|
29 |
+
set(Eigen3_FIND_VERSION
|
30 |
+
"${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}")
|
31 |
+
endif(NOT Eigen3_FIND_VERSION)
|
32 |
+
|
33 |
+
macro(_eigen3_check_version)
|
34 |
+
file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header)
|
35 |
+
|
36 |
+
string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match
|
37 |
+
"${_eigen3_version_header}")
|
38 |
+
set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}")
|
39 |
+
string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match
|
40 |
+
"${_eigen3_version_header}")
|
41 |
+
set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}")
|
42 |
+
string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match
|
43 |
+
"${_eigen3_version_header}")
|
44 |
+
set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}")
|
45 |
+
|
46 |
+
set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION})
|
47 |
+
if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
|
48 |
+
set(EIGEN3_VERSION_OK FALSE)
|
49 |
+
else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
|
50 |
+
set(EIGEN3_VERSION_OK TRUE)
|
51 |
+
endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
|
52 |
+
|
53 |
+
if(NOT EIGEN3_VERSION_OK)
|
54 |
+
|
55 |
+
message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, "
|
56 |
+
"but at least version ${Eigen3_FIND_VERSION} is required")
|
57 |
+
endif(NOT EIGEN3_VERSION_OK)
|
58 |
+
endmacro(_eigen3_check_version)
|
59 |
+
|
60 |
+
if(EIGEN3_INCLUDE_DIR)
|
61 |
+
|
62 |
+
# in cache already
|
63 |
+
_eigen3_check_version()
|
64 |
+
set(EIGEN3_FOUND ${EIGEN3_VERSION_OK})
|
65 |
+
|
66 |
+
else(EIGEN3_INCLUDE_DIR)
|
67 |
+
if(NOT DEFINED KDE4_INCLUDE_DIR)
|
68 |
+
set(KDE4_INCLUDE_DIR "")
|
69 |
+
endif()
|
70 |
+
|
71 |
+
find_path(
|
72 |
+
EIGEN3_INCLUDE_DIR
|
73 |
+
NAMES signature_of_eigen3_matrix_library
|
74 |
+
PATHS ${CMAKE_INSTALL_PREFIX}/include ${KDE4_INCLUDE_DIR}
|
75 |
+
PATH_SUFFIXES eigen3 eigen)
|
76 |
+
|
77 |
+
if(EIGEN3_INCLUDE_DIR)
|
78 |
+
_eigen3_check_version()
|
79 |
+
endif(EIGEN3_INCLUDE_DIR)
|
80 |
+
|
81 |
+
include(FindPackageHandleStandardArgs)
|
82 |
+
find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK)
|
83 |
+
|
84 |
+
mark_as_advanced(EIGEN3_INCLUDE_DIR)
|
85 |
+
|
86 |
+
endif(EIGEN3_INCLUDE_DIR)
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/FindPythonLibsNew.cmake
ADDED
@@ -0,0 +1,257 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# - Find python libraries
|
2 |
+
# This module finds the libraries corresponding to the Python interpreter
|
3 |
+
# FindPythonInterp provides.
|
4 |
+
# This code sets the following variables:
|
5 |
+
#
|
6 |
+
# PYTHONLIBS_FOUND - have the Python libs been found
|
7 |
+
# PYTHON_PREFIX - path to the Python installation
|
8 |
+
# PYTHON_LIBRARIES - path to the python library
|
9 |
+
# PYTHON_INCLUDE_DIRS - path to where Python.h is found
|
10 |
+
# PYTHON_MODULE_EXTENSION - lib extension, e.g. '.so' or '.pyd'
|
11 |
+
# PYTHON_MODULE_PREFIX - lib name prefix: usually an empty string
|
12 |
+
# PYTHON_SITE_PACKAGES - path to installation site-packages
|
13 |
+
# PYTHON_IS_DEBUG - whether the Python interpreter is a debug build
|
14 |
+
#
|
15 |
+
# Thanks to talljimbo for the patch adding the 'LDVERSION' config
|
16 |
+
# variable usage.
|
17 |
+
|
18 |
+
#=============================================================================
|
19 |
+
# Copyright 2001-2009 Kitware, Inc.
|
20 |
+
# Copyright 2012 Continuum Analytics, Inc.
|
21 |
+
#
|
22 |
+
# All rights reserved.
|
23 |
+
#
|
24 |
+
# Redistribution and use in source and binary forms, with or without
|
25 |
+
# modification, are permitted provided that the following conditions
|
26 |
+
# are met:
|
27 |
+
#
|
28 |
+
# * Redistributions of source code must retain the above copyright
|
29 |
+
# notice, this list of conditions and the following disclaimer.
|
30 |
+
#
|
31 |
+
# * Redistributions in binary form must reproduce the above copyright
|
32 |
+
# notice, this list of conditions and the following disclaimer in the
|
33 |
+
# documentation and/or other materials provided with the distribution.
|
34 |
+
#
|
35 |
+
# * Neither the names of Kitware, Inc., the Insight Software Consortium,
|
36 |
+
# nor the names of their contributors may be used to endorse or promote
|
37 |
+
# products derived from this software without specific prior written
|
38 |
+
# permission.
|
39 |
+
#
|
40 |
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
41 |
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
42 |
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
43 |
+
# # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
44 |
+
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
45 |
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
46 |
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
47 |
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
48 |
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
49 |
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
50 |
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
51 |
+
#=============================================================================
|
52 |
+
|
53 |
+
# Checking for the extension makes sure that `LibsNew` was found and not just `Libs`.
|
54 |
+
if(PYTHONLIBS_FOUND AND PYTHON_MODULE_EXTENSION)
|
55 |
+
return()
|
56 |
+
endif()
|
57 |
+
|
58 |
+
if(PythonLibsNew_FIND_QUIETLY)
|
59 |
+
set(_pythonlibs_quiet QUIET)
|
60 |
+
else()
|
61 |
+
set(_pythonlibs_quiet "")
|
62 |
+
endif()
|
63 |
+
|
64 |
+
if(PythonLibsNew_FIND_REQUIRED)
|
65 |
+
set(_pythonlibs_required REQUIRED)
|
66 |
+
endif()
|
67 |
+
|
68 |
+
# Check to see if the `python` command is present and from a virtual
|
69 |
+
# environment, conda, or GHA activation - if it is, try to use that.
|
70 |
+
|
71 |
+
if(NOT DEFINED PYTHON_EXECUTABLE)
|
72 |
+
if(DEFINED ENV{VIRTUAL_ENV})
|
73 |
+
find_program(
|
74 |
+
PYTHON_EXECUTABLE python
|
75 |
+
PATHS "$ENV{VIRTUAL_ENV}" "$ENV{VIRTUAL_ENV}/bin"
|
76 |
+
NO_DEFAULT_PATH)
|
77 |
+
elseif(DEFINED ENV{CONDA_PREFIX})
|
78 |
+
find_program(
|
79 |
+
PYTHON_EXECUTABLE python
|
80 |
+
PATHS "$ENV{CONDA_PREFIX}" "$ENV{CONDA_PREFIX}/bin"
|
81 |
+
NO_DEFAULT_PATH)
|
82 |
+
elseif(DEFINED ENV{pythonLocation})
|
83 |
+
find_program(
|
84 |
+
PYTHON_EXECUTABLE python
|
85 |
+
PATHS "$ENV{pythonLocation}" "$ENV{pythonLocation}/bin"
|
86 |
+
NO_DEFAULT_PATH)
|
87 |
+
endif()
|
88 |
+
if(NOT PYTHON_EXECUTABLE)
|
89 |
+
unset(PYTHON_EXECUTABLE)
|
90 |
+
endif()
|
91 |
+
endif()
|
92 |
+
|
93 |
+
# Use the Python interpreter to find the libs.
|
94 |
+
if(NOT PythonLibsNew_FIND_VERSION)
|
95 |
+
set(PythonLibsNew_FIND_VERSION "")
|
96 |
+
endif()
|
97 |
+
|
98 |
+
find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} ${_pythonlibs_required}
|
99 |
+
${_pythonlibs_quiet})
|
100 |
+
|
101 |
+
if(NOT PYTHONINTERP_FOUND)
|
102 |
+
set(PYTHONLIBS_FOUND FALSE)
|
103 |
+
set(PythonLibsNew_FOUND FALSE)
|
104 |
+
return()
|
105 |
+
endif()
|
106 |
+
|
107 |
+
# According to https://stackoverflow.com/questions/646518/python-how-to-detect-debug-interpreter
|
108 |
+
# testing whether sys has the gettotalrefcount function is a reliable, cross-platform
|
109 |
+
# way to detect a CPython debug interpreter.
|
110 |
+
#
|
111 |
+
# The library suffix is from the config var LDVERSION sometimes, otherwise
|
112 |
+
# VERSION. VERSION will typically be like "2.7" on unix, and "27" on windows.
|
113 |
+
execute_process(
|
114 |
+
COMMAND
|
115 |
+
"${PYTHON_EXECUTABLE}" "-c" "from distutils import sysconfig as s;import sys;import struct;
|
116 |
+
print('.'.join(str(v) for v in sys.version_info));
|
117 |
+
print(sys.prefix);
|
118 |
+
print(s.get_python_inc(plat_specific=True));
|
119 |
+
print(s.get_python_lib(plat_specific=True));
|
120 |
+
print(s.get_config_var('EXT_SUFFIX') or s.get_config_var('SO'));
|
121 |
+
print(hasattr(sys, 'gettotalrefcount')+0);
|
122 |
+
print(struct.calcsize('@P'));
|
123 |
+
print(s.get_config_var('LDVERSION') or s.get_config_var('VERSION'));
|
124 |
+
print(s.get_config_var('LIBDIR') or '');
|
125 |
+
print(s.get_config_var('MULTIARCH') or '');
|
126 |
+
"
|
127 |
+
RESULT_VARIABLE _PYTHON_SUCCESS
|
128 |
+
OUTPUT_VARIABLE _PYTHON_VALUES
|
129 |
+
ERROR_VARIABLE _PYTHON_ERROR_VALUE)
|
130 |
+
|
131 |
+
if(NOT _PYTHON_SUCCESS MATCHES 0)
|
132 |
+
if(PythonLibsNew_FIND_REQUIRED)
|
133 |
+
message(FATAL_ERROR "Python config failure:\n${_PYTHON_ERROR_VALUE}")
|
134 |
+
endif()
|
135 |
+
set(PYTHONLIBS_FOUND FALSE)
|
136 |
+
set(PythonLibsNew_FOUND FALSE)
|
137 |
+
return()
|
138 |
+
endif()
|
139 |
+
|
140 |
+
# Convert the process output into a list
|
141 |
+
if(WIN32)
|
142 |
+
string(REGEX REPLACE "\\\\" "/" _PYTHON_VALUES ${_PYTHON_VALUES})
|
143 |
+
endif()
|
144 |
+
string(REGEX REPLACE ";" "\\\\;" _PYTHON_VALUES ${_PYTHON_VALUES})
|
145 |
+
string(REGEX REPLACE "\n" ";" _PYTHON_VALUES ${_PYTHON_VALUES})
|
146 |
+
list(GET _PYTHON_VALUES 0 _PYTHON_VERSION_LIST)
|
147 |
+
list(GET _PYTHON_VALUES 1 PYTHON_PREFIX)
|
148 |
+
list(GET _PYTHON_VALUES 2 PYTHON_INCLUDE_DIR)
|
149 |
+
list(GET _PYTHON_VALUES 3 PYTHON_SITE_PACKAGES)
|
150 |
+
list(GET _PYTHON_VALUES 4 PYTHON_MODULE_EXTENSION)
|
151 |
+
list(GET _PYTHON_VALUES 5 PYTHON_IS_DEBUG)
|
152 |
+
list(GET _PYTHON_VALUES 6 PYTHON_SIZEOF_VOID_P)
|
153 |
+
list(GET _PYTHON_VALUES 7 PYTHON_LIBRARY_SUFFIX)
|
154 |
+
list(GET _PYTHON_VALUES 8 PYTHON_LIBDIR)
|
155 |
+
list(GET _PYTHON_VALUES 9 PYTHON_MULTIARCH)
|
156 |
+
|
157 |
+
# Make sure the Python has the same pointer-size as the chosen compiler
|
158 |
+
# Skip if CMAKE_SIZEOF_VOID_P is not defined
|
159 |
+
if(CMAKE_SIZEOF_VOID_P AND (NOT "${PYTHON_SIZEOF_VOID_P}" STREQUAL "${CMAKE_SIZEOF_VOID_P}"))
|
160 |
+
if(PythonLibsNew_FIND_REQUIRED)
|
161 |
+
math(EXPR _PYTHON_BITS "${PYTHON_SIZEOF_VOID_P} * 8")
|
162 |
+
math(EXPR _CMAKE_BITS "${CMAKE_SIZEOF_VOID_P} * 8")
|
163 |
+
message(FATAL_ERROR "Python config failure: Python is ${_PYTHON_BITS}-bit, "
|
164 |
+
"chosen compiler is ${_CMAKE_BITS}-bit")
|
165 |
+
endif()
|
166 |
+
set(PYTHONLIBS_FOUND FALSE)
|
167 |
+
set(PythonLibsNew_FOUND FALSE)
|
168 |
+
return()
|
169 |
+
endif()
|
170 |
+
|
171 |
+
# The built-in FindPython didn't always give the version numbers
|
172 |
+
string(REGEX REPLACE "\\." ";" _PYTHON_VERSION_LIST ${_PYTHON_VERSION_LIST})
|
173 |
+
list(GET _PYTHON_VERSION_LIST 0 PYTHON_VERSION_MAJOR)
|
174 |
+
list(GET _PYTHON_VERSION_LIST 1 PYTHON_VERSION_MINOR)
|
175 |
+
list(GET _PYTHON_VERSION_LIST 2 PYTHON_VERSION_PATCH)
|
176 |
+
set(PYTHON_VERSION "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}.${PYTHON_VERSION_PATCH}")
|
177 |
+
|
178 |
+
# Make sure all directory separators are '/'
|
179 |
+
string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX "${PYTHON_PREFIX}")
|
180 |
+
string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}")
|
181 |
+
string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES "${PYTHON_SITE_PACKAGES}")
|
182 |
+
|
183 |
+
if(CMAKE_HOST_WIN32)
|
184 |
+
set(PYTHON_LIBRARY "${PYTHON_PREFIX}/libs/python${PYTHON_LIBRARY_SUFFIX}.lib")
|
185 |
+
|
186 |
+
# when run in a venv, PYTHON_PREFIX points to it. But the libraries remain in the
|
187 |
+
# original python installation. They may be found relative to PYTHON_INCLUDE_DIR.
|
188 |
+
if(NOT EXISTS "${PYTHON_LIBRARY}")
|
189 |
+
get_filename_component(_PYTHON_ROOT ${PYTHON_INCLUDE_DIR} DIRECTORY)
|
190 |
+
set(PYTHON_LIBRARY "${_PYTHON_ROOT}/libs/python${PYTHON_LIBRARY_SUFFIX}.lib")
|
191 |
+
endif()
|
192 |
+
|
193 |
+
# if we are in MSYS & MINGW, and we didn't find windows python lib, look for system python lib
|
194 |
+
if(DEFINED ENV{MSYSTEM}
|
195 |
+
AND MINGW
|
196 |
+
AND NOT EXISTS "${PYTHON_LIBRARY}")
|
197 |
+
if(PYTHON_MULTIARCH)
|
198 |
+
set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}" "${PYTHON_LIBDIR}")
|
199 |
+
else()
|
200 |
+
set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}")
|
201 |
+
endif()
|
202 |
+
unset(PYTHON_LIBRARY)
|
203 |
+
find_library(
|
204 |
+
PYTHON_LIBRARY
|
205 |
+
NAMES "python${PYTHON_LIBRARY_SUFFIX}"
|
206 |
+
PATHS ${_PYTHON_LIBS_SEARCH}
|
207 |
+
NO_DEFAULT_PATH)
|
208 |
+
endif()
|
209 |
+
|
210 |
+
# raise an error if the python libs are still not found.
|
211 |
+
if(NOT EXISTS "${PYTHON_LIBRARY}")
|
212 |
+
message(FATAL_ERROR "Python libraries not found")
|
213 |
+
endif()
|
214 |
+
|
215 |
+
else()
|
216 |
+
if(PYTHON_MULTIARCH)
|
217 |
+
set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}" "${PYTHON_LIBDIR}")
|
218 |
+
else()
|
219 |
+
set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}")
|
220 |
+
endif()
|
221 |
+
#message(STATUS "Searching for Python libs in ${_PYTHON_LIBS_SEARCH}")
|
222 |
+
# Probably this needs to be more involved. It would be nice if the config
|
223 |
+
# information the python interpreter itself gave us were more complete.
|
224 |
+
find_library(
|
225 |
+
PYTHON_LIBRARY
|
226 |
+
NAMES "python${PYTHON_LIBRARY_SUFFIX}"
|
227 |
+
PATHS ${_PYTHON_LIBS_SEARCH}
|
228 |
+
NO_DEFAULT_PATH)
|
229 |
+
|
230 |
+
# If all else fails, just set the name/version and let the linker figure out the path.
|
231 |
+
if(NOT PYTHON_LIBRARY)
|
232 |
+
set(PYTHON_LIBRARY python${PYTHON_LIBRARY_SUFFIX})
|
233 |
+
endif()
|
234 |
+
endif()
|
235 |
+
|
236 |
+
mark_as_advanced(PYTHON_LIBRARY PYTHON_INCLUDE_DIR)
|
237 |
+
|
238 |
+
# We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the
|
239 |
+
# cache entries because they are meant to specify the location of a single
|
240 |
+
# library. We now set the variables listed by the documentation for this
|
241 |
+
# module.
|
242 |
+
set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
|
243 |
+
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
|
244 |
+
if(NOT PYTHON_DEBUG_LIBRARY)
|
245 |
+
set(PYTHON_DEBUG_LIBRARY "")
|
246 |
+
endif()
|
247 |
+
set(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}")
|
248 |
+
|
249 |
+
find_package_message(PYTHON "Found PythonLibs: ${PYTHON_LIBRARY}"
|
250 |
+
"${PYTHON_EXECUTABLE}${PYTHON_VERSION_STRING}")
|
251 |
+
|
252 |
+
set(PYTHONLIBS_FOUND TRUE)
|
253 |
+
set(PythonLibsNew_FOUND TRUE)
|
254 |
+
|
255 |
+
if(NOT PYTHON_MODULE_PREFIX)
|
256 |
+
set(PYTHON_MODULE_PREFIX "")
|
257 |
+
endif()
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/check-style.sh
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
#
|
3 |
+
# Script to check include/test code for common pybind11 code style errors.
|
4 |
+
#
|
5 |
+
# This script currently checks for
|
6 |
+
#
|
7 |
+
# 1. missing space between keyword and parenthesis, e.g.: for(, if(, while(
|
8 |
+
# 2. Missing space between right parenthesis and brace, e.g. 'for (...){'
|
9 |
+
# 3. opening brace on its own line. It should always be on the same line as the
|
10 |
+
# if/while/for/do statement.
|
11 |
+
#
|
12 |
+
# Invoke as: tools/check-style.sh <filenames>
|
13 |
+
#
|
14 |
+
|
15 |
+
check_style_errors=0
|
16 |
+
IFS=$'\n'
|
17 |
+
|
18 |
+
|
19 |
+
found="$(grep '\<\(if\|for\|while\|catch\)(\|){' "$@" -rn --color=always)"
|
20 |
+
if [ -n "$found" ]; then
|
21 |
+
echo -e '\033[31;01mError: found the following coding style problems:\033[0m'
|
22 |
+
check_style_errors=1
|
23 |
+
echo "${found//^/ /}"
|
24 |
+
fi
|
25 |
+
|
26 |
+
found="$(awk '
|
27 |
+
function prefix(filename, lineno) {
|
28 |
+
return " \033[35m" filename "\033[36m:\033[32m" lineno "\033[36m:\033[0m"
|
29 |
+
}
|
30 |
+
function mark(pattern, string) { sub(pattern, "\033[01;31m&\033[0m", string); return string }
|
31 |
+
last && /^\s*{/ {
|
32 |
+
print prefix(FILENAME, FNR-1) mark("\\)\\s*$", last)
|
33 |
+
print prefix(FILENAME, FNR) mark("^\\s*{", $0)
|
34 |
+
last=""
|
35 |
+
}
|
36 |
+
{ last = /(if|for|while|catch|switch)\s*\(.*\)\s*$/ ? $0 : "" }
|
37 |
+
' "$(find include -type f)" "$@")"
|
38 |
+
if [ -n "$found" ]; then
|
39 |
+
check_style_errors=1
|
40 |
+
echo -e '\033[31;01mError: braces should occur on the same line as the if/while/.. statement. Found issues in the following files:\033[0m'
|
41 |
+
echo "$found"
|
42 |
+
fi
|
43 |
+
|
44 |
+
exit $check_style_errors
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/cmake_uninstall.cmake.in
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Source: https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#can-i-do-make-uninstall-with-cmake
|
2 |
+
|
3 |
+
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
|
4 |
+
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
|
5 |
+
endif()
|
6 |
+
|
7 |
+
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
|
8 |
+
string(REGEX REPLACE "\n" ";" files "${files}")
|
9 |
+
foreach(file ${files})
|
10 |
+
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
|
11 |
+
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
12 |
+
exec_program(
|
13 |
+
"@CMAKE_COMMAND@" ARGS
|
14 |
+
"-E remove \"$ENV{DESTDIR}${file}\""
|
15 |
+
OUTPUT_VARIABLE rm_out
|
16 |
+
RETURN_VALUE rm_retval)
|
17 |
+
if(NOT "${rm_retval}" STREQUAL 0)
|
18 |
+
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
|
19 |
+
endif()
|
20 |
+
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
21 |
+
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
|
22 |
+
endif()
|
23 |
+
endforeach()
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/libsize.py
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
from __future__ import print_function, division
|
3 |
+
import os
|
4 |
+
import sys
|
5 |
+
|
6 |
+
# Internal build script for generating debugging test .so size.
|
7 |
+
# Usage:
|
8 |
+
# python libsize.py file.so save.txt -- displays the size of file.so and, if save.txt exists, compares it to the
|
9 |
+
# size in it, then overwrites save.txt with the new size for future runs.
|
10 |
+
|
11 |
+
if len(sys.argv) != 3:
|
12 |
+
sys.exit("Invalid arguments: usage: python libsize.py file.so save.txt")
|
13 |
+
|
14 |
+
lib = sys.argv[1]
|
15 |
+
save = sys.argv[2]
|
16 |
+
|
17 |
+
if not os.path.exists(lib):
|
18 |
+
sys.exit("Error: requested file ({}) does not exist".format(lib))
|
19 |
+
|
20 |
+
libsize = os.path.getsize(lib)
|
21 |
+
|
22 |
+
print("------", os.path.basename(lib), "file size:", libsize, end="")
|
23 |
+
|
24 |
+
if os.path.exists(save):
|
25 |
+
with open(save) as sf:
|
26 |
+
oldsize = int(sf.readline())
|
27 |
+
|
28 |
+
if oldsize > 0:
|
29 |
+
change = libsize - oldsize
|
30 |
+
if change == 0:
|
31 |
+
print(" (no change)")
|
32 |
+
else:
|
33 |
+
print(" (change of {:+} bytes = {:+.2%})".format(change, change / oldsize))
|
34 |
+
else:
|
35 |
+
print()
|
36 |
+
|
37 |
+
with open(save, "w") as sf:
|
38 |
+
sf.write(str(libsize))
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/make_changelog.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
# -*- coding: utf-8 -*-
|
3 |
+
|
4 |
+
import re
|
5 |
+
|
6 |
+
import ghapi.all
|
7 |
+
|
8 |
+
from rich import print
|
9 |
+
from rich.syntax import Syntax
|
10 |
+
|
11 |
+
|
12 |
+
ENTRY = re.compile(
|
13 |
+
r"""
|
14 |
+
Suggested \s changelog \s entry:
|
15 |
+
.*
|
16 |
+
```rst
|
17 |
+
\s*
|
18 |
+
(.*?)
|
19 |
+
\s*
|
20 |
+
```
|
21 |
+
""",
|
22 |
+
re.DOTALL | re.VERBOSE,
|
23 |
+
)
|
24 |
+
|
25 |
+
print()
|
26 |
+
|
27 |
+
|
28 |
+
api = ghapi.all.GhApi(owner="pybind", repo="pybind11")
|
29 |
+
|
30 |
+
issues_pages = ghapi.page.paged(
|
31 |
+
api.issues.list_for_repo, labels="needs changelog", state="closed"
|
32 |
+
)
|
33 |
+
issues = (issue for page in issues_pages for issue in page)
|
34 |
+
missing = []
|
35 |
+
|
36 |
+
for issue in issues:
|
37 |
+
changelog = ENTRY.findall(issue.body)
|
38 |
+
if changelog:
|
39 |
+
(msg,) = changelog
|
40 |
+
if not msg.startswith("* "):
|
41 |
+
msg = "* " + msg
|
42 |
+
if not msg.endswith("."):
|
43 |
+
msg += "."
|
44 |
+
|
45 |
+
msg += f"\n `#{issue.number} <{issue.html_url}>`_"
|
46 |
+
|
47 |
+
print(Syntax(msg, "rst", theme="ansi_light", word_wrap=True))
|
48 |
+
print()
|
49 |
+
|
50 |
+
else:
|
51 |
+
missing.append(issue)
|
52 |
+
|
53 |
+
if missing:
|
54 |
+
print()
|
55 |
+
print("[blue]" + "-" * 30)
|
56 |
+
print()
|
57 |
+
|
58 |
+
for issue in missing:
|
59 |
+
print(f"[red bold]Missing:[/red bold][red] {issue.title}")
|
60 |
+
print(f"[red] {issue.html_url}\n")
|
61 |
+
|
62 |
+
print("[bold]Template:\n")
|
63 |
+
msg = "## Suggested changelog entry:\n\n```rst\n\n```"
|
64 |
+
print(Syntax(msg, "md", theme="ansi_light"))
|
65 |
+
|
66 |
+
print()
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/pybind11Common.cmake
ADDED
@@ -0,0 +1,402 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#[======================================================[.rst
|
2 |
+
|
3 |
+
Adds the following targets::
|
4 |
+
|
5 |
+
pybind11::pybind11 - link to headers and pybind11
|
6 |
+
pybind11::module - Adds module links
|
7 |
+
pybind11::embed - Adds embed links
|
8 |
+
pybind11::lto - Link time optimizations (manual selection)
|
9 |
+
pybind11::thin_lto - Link time optimizations (manual selection)
|
10 |
+
pybind11::python_link_helper - Adds link to Python libraries
|
11 |
+
pybind11::python2_no_register - Avoid warning/error with Python 2 + C++14/7
|
12 |
+
pybind11::windows_extras - MSVC bigobj and mp for building multithreaded
|
13 |
+
pybind11::opt_size - avoid optimizations that increase code size
|
14 |
+
|
15 |
+
Adds the following functions::
|
16 |
+
|
17 |
+
pybind11_strip(target) - strip target after building on linux/macOS
|
18 |
+
pybind11_find_import(module) - See if a module is installed.
|
19 |
+
|
20 |
+
#]======================================================]
|
21 |
+
|
22 |
+
# CMake 3.10 has an include_guard command, but we can't use that yet
|
23 |
+
if(TARGET pybind11::lto)
|
24 |
+
return()
|
25 |
+
endif()
|
26 |
+
|
27 |
+
# If we are in subdirectory mode, all IMPORTED targets must be GLOBAL. If we
|
28 |
+
# are in CONFIG mode, they should be "normal" targets instead.
|
29 |
+
# In CMake 3.11+ you can promote a target to global after you create it,
|
30 |
+
# which might be simpler than this check.
|
31 |
+
get_property(
|
32 |
+
is_config
|
33 |
+
TARGET pybind11::headers
|
34 |
+
PROPERTY IMPORTED)
|
35 |
+
if(NOT is_config)
|
36 |
+
set(optional_global GLOBAL)
|
37 |
+
endif()
|
38 |
+
|
39 |
+
# If not run in Python mode, we still would like this to at least
|
40 |
+
# include pybind11's include directory:
|
41 |
+
set(pybind11_INCLUDE_DIRS
|
42 |
+
"${pybind11_INCLUDE_DIR}"
|
43 |
+
CACHE INTERNAL "Include directory for pybind11 (Python not requested)")
|
44 |
+
|
45 |
+
# --------------------- Shared targets ----------------------------
|
46 |
+
|
47 |
+
# Build an interface library target:
|
48 |
+
add_library(pybind11::pybind11 IMPORTED INTERFACE ${optional_global})
|
49 |
+
set_property(
|
50 |
+
TARGET pybind11::pybind11
|
51 |
+
APPEND
|
52 |
+
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::headers)
|
53 |
+
|
54 |
+
# Build a module target:
|
55 |
+
add_library(pybind11::module IMPORTED INTERFACE ${optional_global})
|
56 |
+
set_property(
|
57 |
+
TARGET pybind11::module
|
58 |
+
APPEND
|
59 |
+
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11)
|
60 |
+
|
61 |
+
# Build an embed library target:
|
62 |
+
add_library(pybind11::embed IMPORTED INTERFACE ${optional_global})
|
63 |
+
set_property(
|
64 |
+
TARGET pybind11::embed
|
65 |
+
APPEND
|
66 |
+
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11)
|
67 |
+
|
68 |
+
# ----------------------- no register ----------------------
|
69 |
+
|
70 |
+
# Workaround for Python 2.7 and C++17 (C++14 as a warning) incompatibility
|
71 |
+
# This adds the flags -Wno-register and -Wno-deprecated-register if the compiler
|
72 |
+
# is Clang 3.9+ or AppleClang and the compile language is CXX, or /wd5033 for MSVC (all languages,
|
73 |
+
# since MSVC didn't recognize COMPILE_LANGUAGE until CMake 3.11+).
|
74 |
+
|
75 |
+
add_library(pybind11::python2_no_register INTERFACE IMPORTED ${optional_global})
|
76 |
+
set(clang_4plus
|
77 |
+
"$<AND:$<CXX_COMPILER_ID:Clang>,$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,3.9>>>")
|
78 |
+
set(no_register "$<OR:${clang_4plus},$<CXX_COMPILER_ID:AppleClang>>")
|
79 |
+
|
80 |
+
if(MSVC AND CMAKE_VERSION VERSION_LESS 3.11)
|
81 |
+
set(cxx_no_register "${no_register}")
|
82 |
+
else()
|
83 |
+
set(cxx_no_register "$<AND:$<COMPILE_LANGUAGE:CXX>,${no_register}>")
|
84 |
+
endif()
|
85 |
+
|
86 |
+
set(msvc "$<CXX_COMPILER_ID:MSVC>")
|
87 |
+
|
88 |
+
set_property(
|
89 |
+
TARGET pybind11::python2_no_register
|
90 |
+
PROPERTY INTERFACE_COMPILE_OPTIONS
|
91 |
+
"$<${cxx_no_register}:-Wno-register;-Wno-deprecated-register>" "$<${msvc}:/wd5033>")
|
92 |
+
|
93 |
+
# --------------------------- link helper ---------------------------
|
94 |
+
|
95 |
+
add_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global})
|
96 |
+
|
97 |
+
if(CMAKE_VERSION VERSION_LESS 3.13)
|
98 |
+
# In CMake 3.11+, you can set INTERFACE properties via the normal methods, and
|
99 |
+
# this would be simpler.
|
100 |
+
set_property(
|
101 |
+
TARGET pybind11::python_link_helper
|
102 |
+
APPEND
|
103 |
+
PROPERTY INTERFACE_LINK_LIBRARIES "$<$<PLATFORM_ID:Darwin>:-undefined dynamic_lookup>")
|
104 |
+
else()
|
105 |
+
# link_options was added in 3.13+
|
106 |
+
# This is safer, because you are ensured the deduplication pass in CMake will not consider
|
107 |
+
# these separate and remove one but not the other.
|
108 |
+
set_property(
|
109 |
+
TARGET pybind11::python_link_helper
|
110 |
+
APPEND
|
111 |
+
PROPERTY INTERFACE_LINK_OPTIONS "$<$<PLATFORM_ID:Darwin>:LINKER:-undefined,dynamic_lookup>")
|
112 |
+
endif()
|
113 |
+
|
114 |
+
# ------------------------ Windows extras -------------------------
|
115 |
+
|
116 |
+
add_library(pybind11::windows_extras IMPORTED INTERFACE ${optional_global})
|
117 |
+
|
118 |
+
if(MSVC) # That's also clang-cl
|
119 |
+
# /bigobj is needed for bigger binding projects due to the limit to 64k
|
120 |
+
# addressable sections
|
121 |
+
set_property(
|
122 |
+
TARGET pybind11::windows_extras
|
123 |
+
APPEND
|
124 |
+
PROPERTY INTERFACE_COMPILE_OPTIONS /bigobj)
|
125 |
+
|
126 |
+
# /MP enables multithreaded builds (relevant when there are many files) for MSVC
|
127 |
+
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # no Clang no Intel
|
128 |
+
if(CMAKE_VERSION VERSION_LESS 3.11)
|
129 |
+
set_property(
|
130 |
+
TARGET pybind11::windows_extras
|
131 |
+
APPEND
|
132 |
+
PROPERTY INTERFACE_COMPILE_OPTIONS $<$<NOT:$<CONFIG:Debug>>:/MP>)
|
133 |
+
else()
|
134 |
+
# Only set these options for C++ files. This is important so that, for
|
135 |
+
# instance, projects that include other types of source files like CUDA
|
136 |
+
# .cu files don't get these options propagated to nvcc since that would
|
137 |
+
# cause the build to fail.
|
138 |
+
set_property(
|
139 |
+
TARGET pybind11::windows_extras
|
140 |
+
APPEND
|
141 |
+
PROPERTY INTERFACE_COMPILE_OPTIONS
|
142 |
+
$<$<NOT:$<CONFIG:Debug>>:$<$<COMPILE_LANGUAGE:CXX>:/MP>>)
|
143 |
+
endif()
|
144 |
+
endif()
|
145 |
+
endif()
|
146 |
+
|
147 |
+
# ----------------------- Optimize binary size --------------------------
|
148 |
+
|
149 |
+
add_library(pybind11::opt_size IMPORTED INTERFACE ${optional_global})
|
150 |
+
|
151 |
+
if(MSVC)
|
152 |
+
set(PYBIND11_OPT_SIZE /Os)
|
153 |
+
else()
|
154 |
+
set(PYBIND11_OPT_SIZE -Os)
|
155 |
+
endif()
|
156 |
+
|
157 |
+
set_property(
|
158 |
+
TARGET pybind11::opt_size
|
159 |
+
APPEND
|
160 |
+
PROPERTY INTERFACE_COMPILE_OPTIONS $<$<CONFIG:Release>:${PYBIND11_OPT_SIZE}>
|
161 |
+
$<$<CONFIG:MinSizeRel>:${PYBIND11_OPT_SIZE}>
|
162 |
+
$<$<CONFIG:RelWithDebInfo>:${PYBIND11_OPT_SIZE}>)
|
163 |
+
|
164 |
+
# ----------------------- Legacy option --------------------------
|
165 |
+
|
166 |
+
# Warn or error if old variable name used
|
167 |
+
if(PYBIND11_CPP_STANDARD)
|
168 |
+
string(REGEX MATCH [[..$]] VAL "${PYBIND11_CPP_STANDARD}")
|
169 |
+
if(CMAKE_CXX_STANDARD)
|
170 |
+
if(NOT CMAKE_CXX_STANDARD STREQUAL VAL)
|
171 |
+
message(WARNING "CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} does not match "
|
172 |
+
"PYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}, "
|
173 |
+
"please remove PYBIND11_CPP_STANDARD from your cache")
|
174 |
+
endif()
|
175 |
+
else()
|
176 |
+
set(supported_standards 11 14 17 20)
|
177 |
+
if("${VAL}" IN_LIST supported_standards)
|
178 |
+
message(WARNING "USE -DCMAKE_CXX_STANDARD=${VAL} instead of PYBIND11_CPP_STANDARD")
|
179 |
+
set(CMAKE_CXX_STANDARD
|
180 |
+
${VAL}
|
181 |
+
CACHE STRING "From PYBIND11_CPP_STANDARD")
|
182 |
+
else()
|
183 |
+
message(FATAL_ERROR "PYBIND11_CPP_STANDARD should be replaced with CMAKE_CXX_STANDARD "
|
184 |
+
"(last two chars: ${VAL} not understood as a valid CXX std)")
|
185 |
+
endif()
|
186 |
+
endif()
|
187 |
+
endif()
|
188 |
+
|
189 |
+
# --------------------- Python specifics -------------------------
|
190 |
+
|
191 |
+
# Check to see which Python mode we are in, new, old, or no python
|
192 |
+
if(PYBIND11_NOPYTHON)
|
193 |
+
set(_pybind11_nopython ON)
|
194 |
+
elseif(
|
195 |
+
PYBIND11_FINDPYTHON
|
196 |
+
OR Python_FOUND
|
197 |
+
OR Python2_FOUND
|
198 |
+
OR Python3_FOUND)
|
199 |
+
# New mode
|
200 |
+
include("${CMAKE_CURRENT_LIST_DIR}/pybind11NewTools.cmake")
|
201 |
+
|
202 |
+
else()
|
203 |
+
|
204 |
+
# Classic mode
|
205 |
+
include("${CMAKE_CURRENT_LIST_DIR}/pybind11Tools.cmake")
|
206 |
+
|
207 |
+
endif()
|
208 |
+
|
209 |
+
# --------------------- pybind11_find_import -------------------------------
|
210 |
+
|
211 |
+
if(NOT _pybind11_nopython)
|
212 |
+
# Check to see if modules are importable. Use REQUIRED to force an error if
|
213 |
+
# one of the modules is not found. <package_name>_FOUND will be set if the
|
214 |
+
# package was found (underscores replace dashes if present). QUIET will hide
|
215 |
+
# the found message, and VERSION will require a minimum version. A successful
|
216 |
+
# find will cache the result.
|
217 |
+
function(pybind11_find_import PYPI_NAME)
|
218 |
+
# CMake variables need underscores (PyPI doesn't care)
|
219 |
+
string(REPLACE "-" "_" NORM_PYPI_NAME "${PYPI_NAME}")
|
220 |
+
|
221 |
+
# Return if found previously
|
222 |
+
if(${NORM_PYPI_NAME}_FOUND)
|
223 |
+
return()
|
224 |
+
endif()
|
225 |
+
|
226 |
+
set(options "REQUIRED;QUIET")
|
227 |
+
set(oneValueArgs "VERSION")
|
228 |
+
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "" ${ARGN})
|
229 |
+
|
230 |
+
if(ARG_REQUIRED)
|
231 |
+
set(status_level FATAL_ERROR)
|
232 |
+
else()
|
233 |
+
set(status_level WARNING)
|
234 |
+
endif()
|
235 |
+
|
236 |
+
execute_process(
|
237 |
+
COMMAND
|
238 |
+
${${_Python}_EXECUTABLE} -c
|
239 |
+
"from pkg_resources import get_distribution; print(get_distribution('${PYPI_NAME}').version)"
|
240 |
+
RESULT_VARIABLE RESULT_PRESENT
|
241 |
+
OUTPUT_VARIABLE PKG_VERSION
|
242 |
+
ERROR_QUIET)
|
243 |
+
|
244 |
+
string(STRIP "${PKG_VERSION}" PKG_VERSION)
|
245 |
+
|
246 |
+
# If a result is present, this failed
|
247 |
+
if(RESULT_PRESENT)
|
248 |
+
set(${NORM_PYPI_NAME}_FOUND
|
249 |
+
${NORM_PYPI_NAME}-NOTFOUND
|
250 |
+
CACHE INTERNAL "")
|
251 |
+
# Always warn or error
|
252 |
+
message(
|
253 |
+
${status_level}
|
254 |
+
"Missing: ${PYPI_NAME} ${ARG_VERSION}\nTry: ${${_Python}_EXECUTABLE} -m pip install ${PYPI_NAME}"
|
255 |
+
)
|
256 |
+
else()
|
257 |
+
if(ARG_VERSION AND PKG_VERSION VERSION_LESS ARG_VERSION)
|
258 |
+
message(
|
259 |
+
${status_level}
|
260 |
+
"Version incorrect: ${PYPI_NAME} ${PKG_VERSION} found, ${ARG_VERSION} required - try upgrading"
|
261 |
+
)
|
262 |
+
else()
|
263 |
+
set(${NORM_PYPI_NAME}_FOUND
|
264 |
+
YES
|
265 |
+
CACHE INTERNAL "")
|
266 |
+
set(${NORM_PYPI_NAME}_VERSION
|
267 |
+
${PKG_VERSION}
|
268 |
+
CACHE INTERNAL "")
|
269 |
+
endif()
|
270 |
+
if(NOT ARG_QUIET)
|
271 |
+
message(STATUS "Found ${PYPI_NAME} ${PKG_VERSION}")
|
272 |
+
endif()
|
273 |
+
endif()
|
274 |
+
if(NOT ARG_VERSION OR (NOT PKG_VERSION VERSION_LESS ARG_VERSION))
|
275 |
+
# We have successfully found a good version, cache to avoid calling again.
|
276 |
+
endif()
|
277 |
+
endfunction()
|
278 |
+
endif()
|
279 |
+
|
280 |
+
# --------------------- LTO -------------------------------
|
281 |
+
|
282 |
+
include(CheckCXXCompilerFlag)
|
283 |
+
|
284 |
+
# Checks whether the given CXX/linker flags can compile and link a cxx file.
|
285 |
+
# cxxflags and linkerflags are lists of flags to use. The result variable is a
|
286 |
+
# unique variable name for each set of flags: the compilation result will be
|
287 |
+
# cached base on the result variable. If the flags work, sets them in
|
288 |
+
# cxxflags_out/linkerflags_out internal cache variables (in addition to
|
289 |
+
# ${result}).
|
290 |
+
function(_pybind11_return_if_cxx_and_linker_flags_work result cxxflags linkerflags cxxflags_out
|
291 |
+
linkerflags_out)
|
292 |
+
set(CMAKE_REQUIRED_LIBRARIES ${linkerflags})
|
293 |
+
check_cxx_compiler_flag("${cxxflags}" ${result})
|
294 |
+
if(${result})
|
295 |
+
set(${cxxflags_out}
|
296 |
+
"${cxxflags}"
|
297 |
+
PARENT_SCOPE)
|
298 |
+
set(${linkerflags_out}
|
299 |
+
"${linkerflags}"
|
300 |
+
PARENT_SCOPE)
|
301 |
+
endif()
|
302 |
+
endfunction()
|
303 |
+
|
304 |
+
function(_pybind11_generate_lto target prefer_thin_lto)
|
305 |
+
if(MINGW)
|
306 |
+
message(STATUS "${target} disabled (problems with undefined symbols for MinGW for now)")
|
307 |
+
return()
|
308 |
+
endif()
|
309 |
+
|
310 |
+
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
311 |
+
set(cxx_append "")
|
312 |
+
set(linker_append "")
|
313 |
+
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT APPLE)
|
314 |
+
# Clang Gold plugin does not support -Os; append -O3 to MinSizeRel builds to override it
|
315 |
+
set(linker_append ";$<$<CONFIG:MinSizeRel>:-O3>")
|
316 |
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND NOT MINGW)
|
317 |
+
set(cxx_append ";-fno-fat-lto-objects")
|
318 |
+
endif()
|
319 |
+
|
320 |
+
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND prefer_thin_lto)
|
321 |
+
_pybind11_return_if_cxx_and_linker_flags_work(
|
322 |
+
HAS_FLTO_THIN "-flto=thin${cxx_append}" "-flto=thin${linker_append}"
|
323 |
+
PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)
|
324 |
+
endif()
|
325 |
+
|
326 |
+
if(NOT HAS_FLTO_THIN)
|
327 |
+
_pybind11_return_if_cxx_and_linker_flags_work(
|
328 |
+
HAS_FLTO "-flto${cxx_append}" "-flto${linker_append}" PYBIND11_LTO_CXX_FLAGS
|
329 |
+
PYBIND11_LTO_LINKER_FLAGS)
|
330 |
+
endif()
|
331 |
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
|
332 |
+
# Intel equivalent to LTO is called IPO
|
333 |
+
_pybind11_return_if_cxx_and_linker_flags_work(HAS_INTEL_IPO "-ipo" "-ipo"
|
334 |
+
PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)
|
335 |
+
elseif(MSVC)
|
336 |
+
# cmake only interprets libraries as linker flags when they start with a - (otherwise it
|
337 |
+
# converts /LTCG to \LTCG as if it was a Windows path). Luckily MSVC supports passing flags
|
338 |
+
# with - instead of /, even if it is a bit non-standard:
|
339 |
+
_pybind11_return_if_cxx_and_linker_flags_work(HAS_MSVC_GL_LTCG "/GL" "-LTCG"
|
340 |
+
PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)
|
341 |
+
endif()
|
342 |
+
|
343 |
+
# Enable LTO flags if found, except for Debug builds
|
344 |
+
if(PYBIND11_LTO_CXX_FLAGS)
|
345 |
+
# CONFIG takes multiple values in CMake 3.19+, until then we have to use OR
|
346 |
+
set(is_debug "$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>")
|
347 |
+
set(not_debug "$<NOT:${is_debug}>")
|
348 |
+
set(cxx_lang "$<COMPILE_LANGUAGE:CXX>")
|
349 |
+
if(MSVC AND CMAKE_VERSION VERSION_LESS 3.11)
|
350 |
+
set(genex "${not_debug}")
|
351 |
+
else()
|
352 |
+
set(genex "$<AND:${not_debug},${cxx_lang}>")
|
353 |
+
endif()
|
354 |
+
set_property(
|
355 |
+
TARGET ${target}
|
356 |
+
APPEND
|
357 |
+
PROPERTY INTERFACE_COMPILE_OPTIONS "$<${genex}:${PYBIND11_LTO_CXX_FLAGS}>")
|
358 |
+
if(CMAKE_PROJECT_NAME STREQUAL "pybind11")
|
359 |
+
message(STATUS "${target} enabled")
|
360 |
+
endif()
|
361 |
+
else()
|
362 |
+
if(CMAKE_PROJECT_NAME STREQUAL "pybind11")
|
363 |
+
message(STATUS "${target} disabled (not supported by the compiler and/or linker)")
|
364 |
+
endif()
|
365 |
+
endif()
|
366 |
+
|
367 |
+
if(PYBIND11_LTO_LINKER_FLAGS)
|
368 |
+
if(CMAKE_VERSION VERSION_LESS 3.11)
|
369 |
+
set_property(
|
370 |
+
TARGET ${target}
|
371 |
+
APPEND
|
372 |
+
PROPERTY INTERFACE_LINK_LIBRARIES "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>")
|
373 |
+
else()
|
374 |
+
set_property(
|
375 |
+
TARGET ${target}
|
376 |
+
APPEND
|
377 |
+
PROPERTY INTERFACE_LINK_OPTIONS "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>")
|
378 |
+
endif()
|
379 |
+
endif()
|
380 |
+
endfunction()
|
381 |
+
|
382 |
+
add_library(pybind11::lto IMPORTED INTERFACE ${optional_global})
|
383 |
+
_pybind11_generate_lto(pybind11::lto FALSE)
|
384 |
+
|
385 |
+
add_library(pybind11::thin_lto IMPORTED INTERFACE ${optional_global})
|
386 |
+
_pybind11_generate_lto(pybind11::thin_lto TRUE)
|
387 |
+
|
388 |
+
# ---------------------- pybind11_strip -----------------------------
|
389 |
+
|
390 |
+
function(pybind11_strip target_name)
|
391 |
+
# Strip unnecessary sections of the binary on Linux/macOS
|
392 |
+
if(CMAKE_STRIP)
|
393 |
+
if(APPLE)
|
394 |
+
set(x_opt -x)
|
395 |
+
endif()
|
396 |
+
|
397 |
+
add_custom_command(
|
398 |
+
TARGET ${target_name}
|
399 |
+
POST_BUILD
|
400 |
+
COMMAND ${CMAKE_STRIP} ${x_opt} $<TARGET_FILE:${target_name}>)
|
401 |
+
endif()
|
402 |
+
endfunction()
|
third-party/DPVO/Pangolin/components/pango_python/pybind11/tools/pybind11Config.cmake.in
ADDED
@@ -0,0 +1,233 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#[=============================================================================[.rst:
|
2 |
+
|
3 |
+
pybind11Config.cmake
|
4 |
+
####################
|
5 |
+
|
6 |
+
Exported variables
|
7 |
+
==================
|
8 |
+
|
9 |
+
This module sets the following variables in your project:
|
10 |
+
|
11 |
+
``pybind11_FOUND``
|
12 |
+
true if pybind11 and all required components found on the system
|
13 |
+
``pybind11_VERSION``
|
14 |
+
pybind11 version in format Major.Minor.Release
|
15 |
+
``pybind11_VERSION_TYPE``
|
16 |
+
pybind11 version type (dev, release)
|
17 |
+
``pybind11_INCLUDE_DIRS``
|
18 |
+
Directories where pybind11 and python headers are located.
|
19 |
+
``pybind11_INCLUDE_DIR``
|
20 |
+
Directory where pybind11 headers are located.
|
21 |
+
``pybind11_DEFINITIONS``
|
22 |
+
Definitions necessary to use pybind11, namely USING_pybind11.
|
23 |
+
``pybind11_LIBRARIES``
|
24 |
+
Compile flags and python libraries (as needed) to link against.
|
25 |
+
``pybind11_LIBRARY``
|
26 |
+
Empty.
|
27 |
+
|
28 |
+
Available components: None
|
29 |
+
|
30 |
+
|
31 |
+
Exported targets
|
32 |
+
================
|
33 |
+
|
34 |
+
If pybind11 is found, this module defines the following ``IMPORTED``
|
35 |
+
interface library targets:
|
36 |
+
|
37 |
+
``pybind11::module``
|
38 |
+
for extension modules.
|
39 |
+
``pybind11::embed``
|
40 |
+
for embedding the Python interpreter.
|
41 |
+
|
42 |
+
Python headers, libraries (as needed by platform), and the C++ standard
|
43 |
+
are attached to the target.
|
44 |
+
|
45 |
+
Advanced targets are also supplied - these are primary for users building
|
46 |
+
complex applications, and they are available in all modes:
|
47 |
+
|
48 |
+
``pybind11::headers``
|
49 |
+
Just the pybind11 headers and minimum compile requirements.
|
50 |
+
``pybind11::pybind11``
|
51 |
+
Python headers too.
|
52 |
+
``pybind11::python_link_helper``
|
53 |
+
Just the "linking" part of ``pybind11:module``, for CMake < 3.15.
|
54 |
+
``pybind11::python2_no_register``
|
55 |
+
Quiets the warning/error when mixing C++14+ and Python 2, also included in ``pybind11::module``.
|
56 |
+
``pybind11::thin_lto``
|
57 |
+
An alternative to ``INTERPROCEDURAL_OPTIMIZATION``.
|
58 |
+
``pybind11::lto``
|
59 |
+
An alternative to ``INTERPROCEDURAL_OPTIMIZATION`` (also avoids thin LTO on clang).
|
60 |
+
``pybind11::windows_extras``
|
61 |
+
Adds bigobj and mp for MSVC.
|
62 |
+
|
63 |
+
Modes
|
64 |
+
=====
|
65 |
+
|
66 |
+
There are two modes provided; classic, which is built on the old Python
|
67 |
+
discovery packages in CMake, or the new FindPython mode, which uses FindPython
|
68 |
+
from 3.12+ forward (3.15+ _highly_ recommended).
|
69 |
+
|
70 |
+
New FindPython mode
|
71 |
+
^^^^^^^^^^^^^^^^^^^
|
72 |
+
|
73 |
+
To activate this mode, either call ``find_package(Python COMPONENTS Interpreter Development)``
|
74 |
+
before finding this package, or set the ``PYBIND11_FINDPYTHON`` variable to ON. In this mode,
|
75 |
+
you can either use the basic targets, or use the FindPython tools:
|
76 |
+
|
77 |
+
.. code-block:: cmake
|
78 |
+
|
79 |
+
find_package(Python COMPONENTS Interpreter Development)
|
80 |
+
find_package(pybind11 CONFIG)
|
81 |
+
|
82 |
+
# pybind11 method:
|
83 |
+
pybind11_add_module(MyModule1 src1.cpp)
|
84 |
+
|
85 |
+
# Python method:
|
86 |
+
Python_add_library(MyModule2 src2.cpp)
|
87 |
+
target_link_libraries(MyModule2 pybind11::headers)
|
88 |
+
set_target_properties(MyModule2 PROPERTIES
|
89 |
+
INTERPROCEDURAL_OPTIMIZATION ON
|
90 |
+
CXX_VISIBILITY_PRESET ON
|
91 |
+
VISIBLITY_INLINES_HIDDEN ON)
|
92 |
+
|
93 |
+
If you build targets yourself, you may be interested in stripping the output
|
94 |
+
for reduced size; this is the one other feature that the helper function gives you.
|
95 |
+
|
96 |
+
Classic mode
|
97 |
+
^^^^^^^^^^^^
|
98 |
+
|
99 |
+
Set PythonLibsNew variables to influence python detection and
|
100 |
+
CMAKE_CXX_STANDARD to influence standard setting.
|
101 |
+
|
102 |
+
.. code-block:: cmake
|
103 |
+
|
104 |
+
find_package(pybind11 CONFIG REQUIRED)
|
105 |
+
|
106 |
+
# Create an extension module
|
107 |
+
add_library(mylib MODULE main.cpp)
|
108 |
+
target_link_libraries(mylib PUBLIC pybind11::module)
|
109 |
+
|
110 |
+
# Or embed the Python interpreter into an executable
|
111 |
+
add_executable(myexe main.cpp)
|
112 |
+
target_link_libraries(myexe PUBLIC pybind11::embed)
|
113 |
+
|
114 |
+
|
115 |
+
Hints
|
116 |
+
=====
|
117 |
+
|
118 |
+
The following variables can be set to guide the search for this package:
|
119 |
+
|
120 |
+
``pybind11_DIR``
|
121 |
+
CMake variable, set to directory containing this Config file.
|
122 |
+
``CMAKE_PREFIX_PATH``
|
123 |
+
CMake variable, set to root directory of this package.
|
124 |
+
``PATH``
|
125 |
+
Environment variable, set to bin directory of this package.
|
126 |
+
``CMAKE_DISABLE_FIND_PACKAGE_pybind11``
|
127 |
+
CMake variable, disables ``find_package(pybind11)`` when not ``REQUIRED``,
|
128 |
+
perhaps to force internal build.
|
129 |
+
|
130 |
+
Commands
|
131 |
+
========
|
132 |
+
|
133 |
+
pybind11_add_module
|
134 |
+
^^^^^^^^^^^^^^^^^^^
|
135 |
+
|
136 |
+
This module defines the following commands to assist with creating Python modules:
|
137 |
+
|
138 |
+
.. code-block:: cmake
|
139 |
+
|
140 |
+
pybind11_add_module(<target>
|
141 |
+
[STATIC|SHARED|MODULE]
|
142 |
+
[THIN_LTO] [OPT_SIZE] [NO_EXTRAS] [WITHOUT_SOABI]
|
143 |
+
<files>...
|
144 |
+
)
|
145 |
+
|
146 |
+
Add a module and setup all helpers. You can select the type of the library; the
|
147 |
+
default is ``MODULE``. There are several options:
|
148 |
+
|
149 |
+
``OPT_SIZE``
|
150 |
+
Optimize for size, even if the ``CMAKE_BUILD_TYPE`` is not ``RelSize``.
|
151 |
+
``THIN_LTO``
|
152 |
+
Use thin TLO instead of regular if there's a choice (pybind11's selection
|
153 |
+
is disabled if ``CMAKE_INTERPROCEDURAL_OPTIMIZATIONS`` is set).
|
154 |
+
``WITHOUT_SOABI``
|
155 |
+
Disable the SOABI component (``PYBIND11_NEWPYTHON`` mode only).
|
156 |
+
``NO_EXTRAS``
|
157 |
+
Disable all extras, exit immediately after making the module.
|
158 |
+
|
159 |
+
pybind11_strip
|
160 |
+
^^^^^^^^^^^^^^
|
161 |
+
|
162 |
+
.. code-block:: cmake
|
163 |
+
|
164 |
+
pybind11_strip(<target>)
|
165 |
+
|
166 |
+
Strip a target after building it (linux/macOS), called by ``pybind11_add_module``.
|
167 |
+
|
168 |
+
pybind11_extension
|
169 |
+
^^^^^^^^^^^^^^^^^^
|
170 |
+
|
171 |
+
.. code-block:: cmake
|
172 |
+
|
173 |
+
pybind11_extension(<target>)
|
174 |
+
|
175 |
+
Sets the Python extension name correctly for Python on your platform, called by
|
176 |
+
``pybind11_add_module``.
|
177 |
+
|
178 |
+
pybind11_find_import(module)
|
179 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
180 |
+
|
181 |
+
.. code-block:: cmake
|
182 |
+
|
183 |
+
pybind11_find_import(<module> [VERSION <number>] [REQUIRED] [QUIET])
|
184 |
+
|
185 |
+
See if a module is installed. Use the registered name (the one on PyPI). You
|
186 |
+
can specify a ``VERSION``, and you can specify ``REQUIRED`` or ``QUIET``. Only available if
|
187 |
+
``NOPYTHON`` mode is not active. Sets ``module_VERSION`` and ``module_FOUND``. Caches the
|
188 |
+
result once a valid install is found.
|
189 |
+
|
190 |
+
Suggested usage
|
191 |
+
===============
|
192 |
+
|
193 |
+
Using ``find_package`` with version info is not recommended except for release versions.
|
194 |
+
|
195 |
+
.. code-block:: cmake
|
196 |
+
|
197 |
+
find_package(pybind11 CONFIG)
|
198 |
+
find_package(pybind11 2.0 EXACT CONFIG REQUIRED)
|
199 |
+
|
200 |
+
#]=============================================================================]
|
201 |
+
@PACKAGE_INIT@
|
202 |
+
|
203 |
+
# Location of pybind11/pybind11.h
|
204 |
+
# This will be relative unless explicitly set as absolute
|
205 |
+
set(pybind11_INCLUDE_DIR "@pybind11_INCLUDEDIR@")
|
206 |
+
|
207 |
+
set(pybind11_LIBRARY "")
|
208 |
+
set(pybind11_DEFINITIONS USING_pybind11)
|
209 |
+
set(pybind11_VERSION_TYPE "@pybind11_VERSION_TYPE@")
|
210 |
+
|
211 |
+
check_required_components(pybind11)
|
212 |
+
|
213 |
+
if(TARGET pybind11::python_link_helper)
|
214 |
+
# This has already been setup elsewhere, such as with a previous call or
|
215 |
+
# add_subdirectory
|
216 |
+
return()
|
217 |
+
endif()
|
218 |
+
|
219 |
+
include("${CMAKE_CURRENT_LIST_DIR}/pybind11Targets.cmake")
|
220 |
+
|
221 |
+
# Easier to use / remember
|
222 |
+
add_library(pybind11::headers IMPORTED INTERFACE)
|
223 |
+
set_target_properties(pybind11::headers PROPERTIES INTERFACE_LINK_LIBRARIES
|
224 |
+
pybind11::pybind11_headers)
|
225 |
+
|
226 |
+
include("${CMAKE_CURRENT_LIST_DIR}/pybind11Common.cmake")
|
227 |
+
|
228 |
+
if(NOT pybind11_FIND_QUIETLY)
|
229 |
+
message(
|
230 |
+
STATUS
|
231 |
+
"Found pybind11: ${pybind11_INCLUDE_DIR} (found version \"${pybind11_VERSION}\" ${pybind11_VERSION_TYPE})"
|
232 |
+
)
|
233 |
+
endif()
|