1 from __future__
import annotations
7 m = pytest.importorskip(
"pybind11_tests.virtual_functions")
8 from pybind11_tests
import ConstructorStats
12 class ExtendedExampleVirt(m.ExampleVirt):
15 self.data =
"Hello world"
18 print(f
"ExtendedExampleVirt::run({value}), calling parent..")
19 return super().
run(value + 1)
22 print(
"ExtendedExampleVirt::run_bool()")
25 def get_string1(self):
28 def pure_virtual(self):
29 print(f
"ExtendedExampleVirt::pure_virtual(): {self.data}")
31 class ExtendedExampleVirt2(ExtendedExampleVirt):
35 def get_string2(self):
38 ex12 = m.ExampleVirt(10)
40 assert m.runExampleVirt(ex12, 20) == 30
44 Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)
48 with pytest.raises(RuntimeError)
as excinfo:
49 m.runExampleVirtVirtual(ex12)
52 ==
'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
55 ex12p = ExtendedExampleVirt(10)
57 assert m.runExampleVirt(ex12p, 20) == 32
61 ExtendedExampleVirt::run(20), calling parent..
62 Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)
66 assert m.runExampleVirtBool(ex12p)
is False
67 assert capture ==
"ExtendedExampleVirt::run_bool()"
69 m.runExampleVirtVirtual(ex12p)
70 assert capture ==
"ExtendedExampleVirt::pure_virtual(): Hello world"
72 ex12p2 = ExtendedExampleVirt2(15)
74 assert m.runExampleVirt(ex12p2, 50) == 68
78 ExtendedExampleVirt::run(50), calling parent..
79 Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)
84 assert cstats.alive() == 3
85 del ex12, ex12p, ex12p2
86 assert cstats.alive() == 0
87 assert cstats.values() == [
"10",
"11",
"17"]
88 assert cstats.copy_constructions == 0
89 assert cstats.move_constructions >= 0
93 """`A` only initializes its trampoline class when we inherit from it
95 If we just create and use an A instance directly, the trampoline initialization is
96 bypassed and we only initialize an A() instead (for performance reasons).
104 print(
"In python f()")
112 assert capture ==
"A.f()"
132 """`A2`, unlike the above, is configured to always initialize the alias
134 While the extra initialization and extra class layer has small virtual dispatch
135 performance penalty, it also allows us to do more things with the trampoline
136 class such as defining local variables and performing construction/destruction.
144 print(
"In python B2.f()")
189 @pytest.mark.xfail(
"env.PYPY")
191 not hasattr(m,
"NCVirt"), reason=
"NCVirt does not work on Intel/PGI/NVCC compilers"
194 class NCVirtExt(m.NCVirt):
195 def get_noncopyable(self, a, b):
197 return m.NonCopyable(a * a, b * b)
199 def get_movable(self, a, b):
201 self.movable = m.Movable(a, b)
204 class NCVirtExt2(m.NCVirt):
205 def get_noncopyable(self, a, b):
207 self.nc = m.NonCopyable(a, b)
210 def get_movable(self, a, b):
212 return m.Movable(a, b)
215 assert ncv1.print_nc(2, 3) ==
"36"
216 assert ncv1.print_movable(4, 5) ==
"9"
218 assert ncv2.print_movable(7, 7) ==
"14"
220 with pytest.raises(RuntimeError):
225 assert nc_stats.alive() == 1
226 assert mv_stats.alive() == 1
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
239 """#159: virtual function dispatch has problems with similar-named functions"""
241 class PyClass1(m.DispatchIssue):
245 class PyClass2(m.DispatchIssue):
247 with pytest.raises(RuntimeError)
as excinfo:
251 ==
'Tried to call pure virtual function "Base::dispatch"'
254 return m.dispatch_issue_go(PyClass1())
257 assert m.dispatch_issue_go(b) ==
"Yay.."
261 """#3357: Recursive dispatch fails to find python function override"""
268 class Adder(m.Adder):
269 def __call__(self, first, second, visitor):
273 (
lambda: visitor(Data(first.value + second.value)))()
275 class StoreResultVisitor:
279 def __call__(self, data):
280 self.result = data.value
282 store = StoreResultVisitor()
284 m.add2(Data(1), Data(2),
Adder(), store)
285 assert store.result == 3
289 m.add3(Data(1), Data(2), Data(3),
Adder(), store)
290 assert store.result == 6
294 """#392/397: overriding reference-returning functions"""
295 o = m.OverrideTest(
"asdf")
300 assert o.str_value() ==
"asdf"
302 assert o.A_value().value ==
"hi"
304 assert a.value ==
"hi"
306 assert a.value ==
"bye"
310 class AR(m.A_Repeat):
311 def unlucky_number(self):
315 def unlucky_number(self):
319 assert obj.say_something(3) ==
"hihihi"
320 assert obj.unlucky_number() == 99
321 assert obj.say_everything() ==
"hi 99"
324 assert obj.say_something(3) ==
"hihihi"
325 assert obj.unlucky_number() == 999
326 assert obj.say_everything() ==
"hi 999"
328 for obj
in [m.B_Repeat(), m.B_Tpl()]:
329 assert obj.say_something(3) ==
"B says hi 3 times"
330 assert obj.unlucky_number() == 13
331 assert obj.lucky_number() == 7.0
332 assert obj.say_everything() ==
"B says hi 1 times 13"
334 for obj
in [m.C_Repeat(), m.C_Tpl()]:
335 assert obj.say_something(3) ==
"B says hi 3 times"
336 assert obj.unlucky_number() == 4444
337 assert obj.lucky_number() == 888.0
338 assert obj.say_everything() ==
"B says hi 1 times 4444"
340 class CR(m.C_Repeat):
341 def lucky_number(self):
342 return m.C_Repeat.lucky_number(self) + 1.25
345 assert obj.say_something(3) ==
"B says hi 3 times"
346 assert obj.unlucky_number() == 4444
347 assert obj.lucky_number() == 889.25
348 assert obj.say_everything() ==
"B says hi 1 times 4444"
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"
360 def lucky_number(self):
361 return CR.lucky_number(self) * 10
364 assert obj.say_something(3) ==
"B says hi 3 times"
365 assert obj.unlucky_number() == 4444
366 assert obj.lucky_number() == 8892.5
367 assert obj.say_everything() ==
"B says hi 1 times 4444"
370 def lucky_number(self):
371 return CT.lucky_number(self) * 1000
374 assert obj.say_something(3) ==
"B says hi 3 times"
375 assert obj.unlucky_number() == 4444
376 assert obj.lucky_number() == 888000.0
377 assert obj.say_everything() ==
"B says hi 1 times 4444"
379 class DR(m.D_Repeat):
380 def unlucky_number(self):
383 def lucky_number(self):
386 for obj
in [m.D_Repeat(), m.D_Tpl()]:
387 assert obj.say_something(3) ==
"B says hi 3 times"
388 assert obj.unlucky_number() == 4444
389 assert obj.lucky_number() == 888.0
390 assert obj.say_everything() ==
"B says hi 1 times 4444"
393 assert obj.say_something(3) ==
"B says hi 3 times"
394 assert obj.unlucky_number() == 123
395 assert obj.lucky_number() == 42.0
396 assert obj.say_everything() ==
"B says hi 1 times 123"
399 def say_something(self, times):
400 return "DT says:" + (
" quack" * times)
402 def unlucky_number(self):
405 def lucky_number(self):
409 assert obj.say_something(3) ==
"DT says: quack quack quack"
410 assert obj.unlucky_number() == 1234
411 assert obj.lucky_number() == -4.25
412 assert obj.say_everything() ==
"DT says: quack 1234"
415 def say_something(self, times):
416 return "DT2: " + (
"QUACK" * times)
418 def unlucky_number(self):
422 def say_something(self, times):
425 def unlucky_number(self):
428 def lucky_number(self):
432 assert obj.say_something(3) ==
"BTBTBT"
433 assert obj.unlucky_number() == -7
434 assert obj.lucky_number() == -1.375
435 assert obj.say_everything() ==
"BT -7"
441 m.test_gil_from_thread()
446 class Test(m.test_override_cache_helper):
453 class Test(m.test_override_cache_helper):
458 for _
in range(1500):
459 assert m.test_override_cache(
func()) == 42
460 assert m.test_override_cache(
func2()) == 0