1 from __future__
import annotations
9 m = pytest.importorskip(
"pybind11_tests.virtual_functions")
10 from pybind11_tests
import ConstructorStats
14 class ExtendedExampleVirt(m.ExampleVirt):
17 self.data =
"Hello world"
20 print(f
"ExtendedExampleVirt::run({value}), calling parent..")
21 return super().
run(value + 1)
24 print(
"ExtendedExampleVirt::run_bool()")
27 def get_string1(self):
30 def pure_virtual(self):
31 print(f
"ExtendedExampleVirt::pure_virtual(): {self.data}")
33 class ExtendedExampleVirt2(ExtendedExampleVirt):
37 def get_string2(self):
40 ex12 = m.ExampleVirt(10)
42 assert m.runExampleVirt(ex12, 20) == 30
46 Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)
50 with pytest.raises(RuntimeError)
as excinfo:
51 m.runExampleVirtVirtual(ex12)
54 ==
'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
57 ex12p = ExtendedExampleVirt(10)
59 assert m.runExampleVirt(ex12p, 20) == 32
63 ExtendedExampleVirt::run(20), calling parent..
64 Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)
68 assert m.runExampleVirtBool(ex12p)
is False
69 assert capture ==
"ExtendedExampleVirt::run_bool()"
71 m.runExampleVirtVirtual(ex12p)
72 assert capture ==
"ExtendedExampleVirt::pure_virtual(): Hello world"
74 ex12p2 = ExtendedExampleVirt2(15)
76 assert m.runExampleVirt(ex12p2, 50) == 68
80 ExtendedExampleVirt::run(50), calling parent..
81 Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)
86 assert cstats.alive() == 3
87 del ex12, ex12p, ex12p2
88 assert cstats.alive() == 0
89 assert cstats.values() == [
"10",
"11",
"17"]
90 assert cstats.copy_constructions == 0
91 assert cstats.move_constructions >= 0
95 """`A` only initializes its trampoline class when we inherit from it
97 If we just create and use an A instance directly, the trampoline initialization is
98 bypassed and we only initialize an A() instead (for performance reasons).
106 print(
"In python f()")
114 assert capture ==
"A.f()"
134 """`A2`, unlike the above, is configured to always initialize the alias
136 While the extra initialization and extra class layer has small virtual dispatch
137 performance penalty, it also allows us to do more things with the trampoline
138 class such as defining local variables and performing construction/destruction.
146 print(
"In python B2.f()")
191 @pytest.mark.xfail(
"env.PYPY")
193 not hasattr(m,
"NCVirt"), reason=
"NCVirt does not work on Intel/PGI/NVCC compilers"
196 class NCVirtExt(m.NCVirt):
197 def get_noncopyable(self, a, b):
199 return m.NonCopyable(a * a, b * b)
201 def get_movable(self, a, b):
203 self.movable = m.Movable(a, b)
206 class NCVirtExt2(m.NCVirt):
207 def get_noncopyable(self, a, b):
209 self.nc = m.NonCopyable(a, b)
212 def get_movable(self, a, b):
214 return m.Movable(a, b)
217 assert ncv1.print_nc(2, 3) ==
"36"
218 assert ncv1.print_movable(4, 5) ==
"9"
220 assert ncv2.print_movable(7, 7) ==
"14"
222 with pytest.raises(RuntimeError):
227 assert nc_stats.alive() == 1
228 assert mv_stats.alive() == 1
230 assert nc_stats.alive() == 0
231 assert mv_stats.alive() == 0
232 assert nc_stats.values() == [
"4",
"9",
"9",
"9"]
233 assert mv_stats.values() == [
"4",
"5",
"7",
"7"]
234 assert nc_stats.copy_constructions == 0
235 assert mv_stats.copy_constructions == 1
236 assert nc_stats.move_constructions >= 0
237 assert mv_stats.move_constructions >= 0
241 """#159: virtual function dispatch has problems with similar-named functions"""
243 class PyClass1(m.DispatchIssue):
247 class PyClass2(m.DispatchIssue):
249 with pytest.raises(RuntimeError)
as excinfo:
253 ==
'Tried to call pure virtual function "Base::dispatch"'
256 return m.dispatch_issue_go(PyClass1())
259 assert m.dispatch_issue_go(b) ==
"Yay.."
263 """#3357: Recursive dispatch fails to find python function override"""
270 class Adder(m.Adder):
271 def __call__(self, first, second, visitor):
275 (
lambda: visitor(Data(first.value + second.value)))()
277 class StoreResultVisitor:
281 def __call__(self, data):
282 self.result = data.value
284 store = StoreResultVisitor()
286 m.add2(Data(1), Data(2),
Adder(), store)
287 assert store.result == 3
291 m.add3(Data(1), Data(2), Data(3),
Adder(), store)
292 assert store.result == 6
296 """#392/397: overriding reference-returning functions"""
297 o = m.OverrideTest(
"asdf")
302 assert o.str_value() ==
"asdf"
304 assert o.A_value().value ==
"hi"
306 assert a.value ==
"hi"
308 assert a.value ==
"bye"
312 class AR(m.A_Repeat):
313 def unlucky_number(self):
317 def unlucky_number(self):
321 assert obj.say_something(3) ==
"hihihi"
322 assert obj.unlucky_number() == 99
323 assert obj.say_everything() ==
"hi 99"
326 assert obj.say_something(3) ==
"hihihi"
327 assert obj.unlucky_number() == 999
328 assert obj.say_everything() ==
"hi 999"
330 for obj
in [m.B_Repeat(), m.B_Tpl()]:
331 assert obj.say_something(3) ==
"B says hi 3 times"
332 assert obj.unlucky_number() == 13
333 assert obj.lucky_number() == 7.0
334 assert obj.say_everything() ==
"B says hi 1 times 13"
336 for obj
in [m.C_Repeat(), m.C_Tpl()]:
337 assert obj.say_something(3) ==
"B says hi 3 times"
338 assert obj.unlucky_number() == 4444
339 assert obj.lucky_number() == 888.0
340 assert obj.say_everything() ==
"B says hi 1 times 4444"
342 class CR(m.C_Repeat):
343 def lucky_number(self):
344 return m.C_Repeat.lucky_number(self) + 1.25
347 assert obj.say_something(3) ==
"B says hi 3 times"
348 assert obj.unlucky_number() == 4444
349 assert obj.lucky_number() == 889.25
350 assert obj.say_everything() ==
"B says hi 1 times 4444"
356 assert obj.say_something(3) ==
"B says hi 3 times"
357 assert obj.unlucky_number() == 4444
358 assert obj.lucky_number() == 888.0
359 assert obj.say_everything() ==
"B says hi 1 times 4444"
362 def lucky_number(self):
363 return CR.lucky_number(self) * 10
366 assert obj.say_something(3) ==
"B says hi 3 times"
367 assert obj.unlucky_number() == 4444
368 assert obj.lucky_number() == 8892.5
369 assert obj.say_everything() ==
"B says hi 1 times 4444"
372 def lucky_number(self):
373 return CT.lucky_number(self) * 1000
376 assert obj.say_something(3) ==
"B says hi 3 times"
377 assert obj.unlucky_number() == 4444
378 assert obj.lucky_number() == 888000.0
379 assert obj.say_everything() ==
"B says hi 1 times 4444"
381 class DR(m.D_Repeat):
382 def unlucky_number(self):
385 def lucky_number(self):
388 for obj
in [m.D_Repeat(), m.D_Tpl()]:
389 assert obj.say_something(3) ==
"B says hi 3 times"
390 assert obj.unlucky_number() == 4444
391 assert obj.lucky_number() == 888.0
392 assert obj.say_everything() ==
"B says hi 1 times 4444"
395 assert obj.say_something(3) ==
"B says hi 3 times"
396 assert obj.unlucky_number() == 123
397 assert obj.lucky_number() == 42.0
398 assert obj.say_everything() ==
"B says hi 1 times 123"
401 def say_something(self, times):
402 return "DT says:" + (
" quack" * times)
404 def unlucky_number(self):
407 def lucky_number(self):
411 assert obj.say_something(3) ==
"DT says: quack quack quack"
412 assert obj.unlucky_number() == 1234
413 assert obj.lucky_number() == -4.25
414 assert obj.say_everything() ==
"DT says: quack 1234"
417 def say_something(self, times):
418 return "DT2: " + (
"QUACK" * times)
420 def unlucky_number(self):
424 def say_something(self, times):
427 def unlucky_number(self):
430 def lucky_number(self):
434 assert obj.say_something(3) ==
"BTBTBT"
435 assert obj.unlucky_number() == -7
436 assert obj.lucky_number() == -1.375
437 assert obj.say_everything() ==
"BT -7"
440 @pytest.mark.skipif(sys.platform.startswith(
"emscripten"), reason=
"Requires threads")
444 m.test_gil_from_thread()
449 class Test(m.test_override_cache_helper):
456 class Test(m.test_override_cache_helper):
461 for _
in range(1500):
462 assert m.test_override_cache(
func()) == 42
463 assert m.test_override_cache(
func2()) == 0