5 m = pytest.importorskip(
"pybind11_tests.virtual_functions")
6 from pybind11_tests
import ConstructorStats
10 class ExtendedExampleVirt(m.ExampleVirt):
13 self.data =
"Hello world"
16 print(f
"ExtendedExampleVirt::run({value}), calling parent..")
17 return super().
run(value + 1)
20 print(
"ExtendedExampleVirt::run_bool()")
23 def get_string1(self):
26 def pure_virtual(self):
27 print(f
"ExtendedExampleVirt::pure_virtual(): {self.data}")
29 class ExtendedExampleVirt2(ExtendedExampleVirt):
33 def get_string2(self):
36 ex12 = m.ExampleVirt(10)
38 assert m.runExampleVirt(ex12, 20) == 30
42 Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)
46 with pytest.raises(RuntimeError)
as excinfo:
47 m.runExampleVirtVirtual(ex12)
50 ==
'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
53 ex12p = ExtendedExampleVirt(10)
55 assert m.runExampleVirt(ex12p, 20) == 32
59 ExtendedExampleVirt::run(20), calling parent..
60 Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)
64 assert m.runExampleVirtBool(ex12p)
is False
65 assert capture ==
"ExtendedExampleVirt::run_bool()"
67 m.runExampleVirtVirtual(ex12p)
68 assert capture ==
"ExtendedExampleVirt::pure_virtual(): Hello world"
70 ex12p2 = ExtendedExampleVirt2(15)
72 assert m.runExampleVirt(ex12p2, 50) == 68
76 ExtendedExampleVirt::run(50), calling parent..
77 Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)
82 assert cstats.alive() == 3
83 del ex12, ex12p, ex12p2
84 assert cstats.alive() == 0
85 assert cstats.values() == [
"10",
"11",
"17"]
86 assert cstats.copy_constructions == 0
87 assert cstats.move_constructions >= 0
91 """`A` only initializes its trampoline class when we inherit from it
93 If we just create and use an A instance directly, the trampoline initialization is
94 bypassed and we only initialize an A() instead (for performance reasons).
102 print(
"In python f()")
110 assert capture ==
"A.f()"
130 """`A2`, unlike the above, is configured to always initialize the alias
132 While the extra initialization and extra class layer has small virtual dispatch
133 performance penalty, it also allows us to do more things with the trampoline
134 class such as defining local variables and performing construction/destruction.
142 print(
"In python B2.f()")
187 @pytest.mark.xfail(
"env.PYPY")
189 not hasattr(m,
"NCVirt"), reason=
"NCVirt does not work on Intel/PGI/NVCC compilers"
192 class NCVirtExt(m.NCVirt):
193 def get_noncopyable(self, a, b):
195 return m.NonCopyable(a * a, b * b)
197 def get_movable(self, a, b):
199 self.movable = m.Movable(a, b)
202 class NCVirtExt2(m.NCVirt):
203 def get_noncopyable(self, a, b):
205 self.nc = m.NonCopyable(a, b)
208 def get_movable(self, a, b):
210 return m.Movable(a, b)
213 assert ncv1.print_nc(2, 3) ==
"36"
214 assert ncv1.print_movable(4, 5) ==
"9"
216 assert ncv2.print_movable(7, 7) ==
"14"
218 with pytest.raises(RuntimeError):
223 assert nc_stats.alive() == 1
224 assert mv_stats.alive() == 1
226 assert nc_stats.alive() == 0
227 assert mv_stats.alive() == 0
228 assert nc_stats.values() == [
"4",
"9",
"9",
"9"]
229 assert mv_stats.values() == [
"4",
"5",
"7",
"7"]
230 assert nc_stats.copy_constructions == 0
231 assert mv_stats.copy_constructions == 1
232 assert nc_stats.move_constructions >= 0
233 assert mv_stats.move_constructions >= 0
237 """#159: virtual function dispatch has problems with similar-named functions"""
239 class PyClass1(m.DispatchIssue):
243 class PyClass2(m.DispatchIssue):
245 with pytest.raises(RuntimeError)
as excinfo:
249 ==
'Tried to call pure virtual function "Base::dispatch"'
252 return m.dispatch_issue_go(PyClass1())
255 assert m.dispatch_issue_go(b) ==
"Yay.."
259 """#3357: Recursive dispatch fails to find python function override"""
266 class Adder(m.Adder):
267 def __call__(self, first, second, visitor):
271 (
lambda: visitor(Data(first.value + second.value)))()
273 class StoreResultVisitor:
277 def __call__(self, data):
278 self.result = data.value
280 store = StoreResultVisitor()
282 m.add2(Data(1), Data(2),
Adder(), store)
283 assert store.result == 3
287 m.add3(Data(1), Data(2), Data(3),
Adder(), store)
288 assert store.result == 6
292 """#392/397: overriding reference-returning functions"""
293 o = m.OverrideTest(
"asdf")
298 assert o.str_value() ==
"asdf"
300 assert o.A_value().value ==
"hi"
302 assert a.value ==
"hi"
304 assert a.value ==
"bye"
308 class AR(m.A_Repeat):
309 def unlucky_number(self):
313 def unlucky_number(self):
317 assert obj.say_something(3) ==
"hihihi"
318 assert obj.unlucky_number() == 99
319 assert obj.say_everything() ==
"hi 99"
322 assert obj.say_something(3) ==
"hihihi"
323 assert obj.unlucky_number() == 999
324 assert obj.say_everything() ==
"hi 999"
326 for obj
in [m.B_Repeat(), m.B_Tpl()]:
327 assert obj.say_something(3) ==
"B says hi 3 times"
328 assert obj.unlucky_number() == 13
329 assert obj.lucky_number() == 7.0
330 assert obj.say_everything() ==
"B says hi 1 times 13"
332 for obj
in [m.C_Repeat(), m.C_Tpl()]:
333 assert obj.say_something(3) ==
"B says hi 3 times"
334 assert obj.unlucky_number() == 4444
335 assert obj.lucky_number() == 888.0
336 assert obj.say_everything() ==
"B says hi 1 times 4444"
338 class CR(m.C_Repeat):
339 def lucky_number(self):
340 return m.C_Repeat.lucky_number(self) + 1.25
343 assert obj.say_something(3) ==
"B says hi 3 times"
344 assert obj.unlucky_number() == 4444
345 assert obj.lucky_number() == 889.25
346 assert obj.say_everything() ==
"B says hi 1 times 4444"
352 assert obj.say_something(3) ==
"B says hi 3 times"
353 assert obj.unlucky_number() == 4444
354 assert obj.lucky_number() == 888.0
355 assert obj.say_everything() ==
"B says hi 1 times 4444"
358 def lucky_number(self):
359 return CR.lucky_number(self) * 10
362 assert obj.say_something(3) ==
"B says hi 3 times"
363 assert obj.unlucky_number() == 4444
364 assert obj.lucky_number() == 8892.5
365 assert obj.say_everything() ==
"B says hi 1 times 4444"
368 def lucky_number(self):
369 return CT.lucky_number(self) * 1000
372 assert obj.say_something(3) ==
"B says hi 3 times"
373 assert obj.unlucky_number() == 4444
374 assert obj.lucky_number() == 888000.0
375 assert obj.say_everything() ==
"B says hi 1 times 4444"
377 class DR(m.D_Repeat):
378 def unlucky_number(self):
381 def lucky_number(self):
384 for obj
in [m.D_Repeat(), m.D_Tpl()]:
385 assert obj.say_something(3) ==
"B says hi 3 times"
386 assert obj.unlucky_number() == 4444
387 assert obj.lucky_number() == 888.0
388 assert obj.say_everything() ==
"B says hi 1 times 4444"
391 assert obj.say_something(3) ==
"B says hi 3 times"
392 assert obj.unlucky_number() == 123
393 assert obj.lucky_number() == 42.0
394 assert obj.say_everything() ==
"B says hi 1 times 123"
397 def say_something(self, times):
398 return "DT says:" + (
" quack" * times)
400 def unlucky_number(self):
403 def lucky_number(self):
407 assert obj.say_something(3) ==
"DT says: quack quack quack"
408 assert obj.unlucky_number() == 1234
409 assert obj.lucky_number() == -4.25
410 assert obj.say_everything() ==
"DT says: quack 1234"
413 def say_something(self, times):
414 return "DT2: " + (
"QUACK" * times)
416 def unlucky_number(self):
420 def say_something(self, times):
423 def unlucky_number(self):
426 def lucky_number(self):
430 assert obj.say_something(3) ==
"BTBTBT"
431 assert obj.unlucky_number() == -7
432 assert obj.lucky_number() == -1.375
433 assert obj.say_everything() ==
"BT -7"
439 m.test_gil_from_thread()
444 class Test(m.test_override_cache_helper):
451 class Test(m.test_override_cache_helper):
456 for _
in range(1500):
457 assert m.test_override_cache(
func()) == 42
458 assert m.test_override_cache(
func2()) == 0