test_virtual_functions.py
Go to the documentation of this file.
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 capture == """
41  Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)
42  """ # noqa: E501 line too long
43 
44  with pytest.raises(RuntimeError) as excinfo:
45  m.runExampleVirtVirtual(ex12)
46  assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
47 
48  ex12p = ExtendedExampleVirt(10)
49  with capture:
50  assert m.runExampleVirt(ex12p, 20) == 32
51  assert capture == """
52  ExtendedExampleVirt::run(20), calling parent..
53  Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)
54  """ # noqa: E501 line too long
55  with capture:
56  assert m.runExampleVirtBool(ex12p) is False
57  assert capture == "ExtendedExampleVirt::run_bool()"
58  with capture:
59  m.runExampleVirtVirtual(ex12p)
60  assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world"
61 
62  ex12p2 = ExtendedExampleVirt2(15)
63  with capture:
64  assert m.runExampleVirt(ex12p2, 50) == 68
65  assert capture == """
66  ExtendedExampleVirt::run(50), calling parent..
67  Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)
68  """ # noqa: E501 line too long
69 
70  cstats = ConstructorStats.get(m.ExampleVirt)
71  assert cstats.alive() == 3
72  del ex12, ex12p, ex12p2
73  assert cstats.alive() == 0
74  assert cstats.values() == ['10', '11', '17']
75  assert cstats.copy_constructions == 0
76  assert cstats.move_constructions >= 0
77 
78 
80  """`A` only initializes its trampoline class when we inherit from it
81 
82  If we just create and use an A instance directly, the trampoline initialization is
83  bypassed and we only initialize an A() instead (for performance reasons).
84  """
85  class B(m.A):
86  def __init__(self):
87  super(B, self).__init__()
88 
89  def f(self):
90  print("In python f()")
91 
92  # C++ version
93  with capture:
94  a = m.A()
95  m.call_f(a)
96  del a
97  pytest.gc_collect()
98  assert capture == "A.f()"
99 
100  # Python version
101  with capture:
102  b = B()
103  m.call_f(b)
104  del b
105  pytest.gc_collect()
106  assert capture == """
107  PyA.PyA()
108  PyA.f()
109  In python f()
110  PyA.~PyA()
111  """
112 
113 
115  """`A2`, unlike the above, is configured to always initialize the alias
116 
117  While the extra initialization and extra class layer has small virtual dispatch
118  performance penalty, it also allows us to do more things with the trampoline
119  class such as defining local variables and performing construction/destruction.
120  """
121  class B2(m.A2):
122  def __init__(self):
123  super(B2, self).__init__()
124 
125  def f(self):
126  print("In python B2.f()")
127 
128  # No python subclass version
129  with capture:
130  a2 = m.A2()
131  m.call_f(a2)
132  del a2
133  pytest.gc_collect()
134  a3 = m.A2(1)
135  m.call_f(a3)
136  del a3
137  pytest.gc_collect()
138  assert capture == """
139  PyA2.PyA2()
140  PyA2.f()
141  A2.f()
142  PyA2.~PyA2()
143  PyA2.PyA2()
144  PyA2.f()
145  A2.f()
146  PyA2.~PyA2()
147  """
148 
149  # Python subclass version
150  with capture:
151  b2 = B2()
152  m.call_f(b2)
153  del b2
154  pytest.gc_collect()
155  assert capture == """
156  PyA2.PyA2()
157  PyA2.f()
158  In python B2.f()
159  PyA2.~PyA2()
160  """
161 
162 
163 # PyPy: Reference count > 1 causes call with noncopyable instance
164 # to fail in ncv1.print_nc()
165 @pytest.mark.xfail("env.PYPY")
166 @pytest.mark.skipif(not hasattr(m, "NCVirt"), reason="NCVirt test broken on ICPC")
168  class NCVirtExt(m.NCVirt):
169  def get_noncopyable(self, a, b):
170  # Constructs and returns a new instance:
171  nc = m.NonCopyable(a * a, b * b)
172  return nc
173 
174  def get_movable(self, a, b):
175  # Return a referenced copy
176  self.movable = m.Movable(a, b)
177  return self.movable
178 
179  class NCVirtExt2(m.NCVirt):
180  def get_noncopyable(self, a, b):
181  # Keep a reference: this is going to throw an exception
182  self.nc = m.NonCopyable(a, b)
183  return self.nc
184 
185  def get_movable(self, a, b):
186  # Return a new instance without storing it
187  return m.Movable(a, b)
188 
189  ncv1 = NCVirtExt()
190  assert ncv1.print_nc(2, 3) == "36"
191  assert ncv1.print_movable(4, 5) == "9"
192  ncv2 = NCVirtExt2()
193  assert ncv2.print_movable(7, 7) == "14"
194  # Don't check the exception message here because it differs under debug/non-debug mode
195  with pytest.raises(RuntimeError):
196  ncv2.print_nc(9, 9)
197 
198  nc_stats = ConstructorStats.get(m.NonCopyable)
199  mv_stats = ConstructorStats.get(m.Movable)
200  assert nc_stats.alive() == 1
201  assert mv_stats.alive() == 1
202  del ncv1, ncv2
203  assert nc_stats.alive() == 0
204  assert mv_stats.alive() == 0
205  assert nc_stats.values() == ['4', '9', '9', '9']
206  assert mv_stats.values() == ['4', '5', '7', '7']
207  assert nc_stats.copy_constructions == 0
208  assert mv_stats.copy_constructions == 1
209  assert nc_stats.move_constructions >= 0
210  assert mv_stats.move_constructions >= 0
211 
212 
214  """#159: virtual function dispatch has problems with similar-named functions"""
215  class PyClass1(m.DispatchIssue):
216  def dispatch(self):
217  return "Yay.."
218 
219  class PyClass2(m.DispatchIssue):
220  def dispatch(self):
221  with pytest.raises(RuntimeError) as excinfo:
222  super(PyClass2, self).dispatch()
223  assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
224 
225  p = PyClass1()
226  return m.dispatch_issue_go(p)
227 
228  b = PyClass2()
229  assert m.dispatch_issue_go(b) == "Yay.."
230 
231 
233  """#392/397: overriding reference-returning functions"""
234  o = m.OverrideTest("asdf")
235 
236  # Not allowed (see associated .cpp comment)
237  # i = o.str_ref()
238  # assert o.str_ref() == "asdf"
239  assert o.str_value() == "asdf"
240 
241  assert o.A_value().value == "hi"
242  a = o.A_ref()
243  assert a.value == "hi"
244  a.value = "bye"
245  assert a.value == "bye"
246 
247 
249  class AR(m.A_Repeat):
250  def unlucky_number(self):
251  return 99
252 
253  class AT(m.A_Tpl):
254  def unlucky_number(self):
255  return 999
256 
257  obj = AR()
258  assert obj.say_something(3) == "hihihi"
259  assert obj.unlucky_number() == 99
260  assert obj.say_everything() == "hi 99"
261 
262  obj = AT()
263  assert obj.say_something(3) == "hihihi"
264  assert obj.unlucky_number() == 999
265  assert obj.say_everything() == "hi 999"
266 
267  for obj in [m.B_Repeat(), m.B_Tpl()]:
268  assert obj.say_something(3) == "B says hi 3 times"
269  assert obj.unlucky_number() == 13
270  assert obj.lucky_number() == 7.0
271  assert obj.say_everything() == "B says hi 1 times 13"
272 
273  for obj in [m.C_Repeat(), m.C_Tpl()]:
274  assert obj.say_something(3) == "B says hi 3 times"
275  assert obj.unlucky_number() == 4444
276  assert obj.lucky_number() == 888.0
277  assert obj.say_everything() == "B says hi 1 times 4444"
278 
279  class CR(m.C_Repeat):
280  def lucky_number(self):
281  return m.C_Repeat.lucky_number(self) + 1.25
282 
283  obj = CR()
284  assert obj.say_something(3) == "B says hi 3 times"
285  assert obj.unlucky_number() == 4444
286  assert obj.lucky_number() == 889.25
287  assert obj.say_everything() == "B says hi 1 times 4444"
288 
289  class CT(m.C_Tpl):
290  pass
291 
292  obj = CT()
293  assert obj.say_something(3) == "B says hi 3 times"
294  assert obj.unlucky_number() == 4444
295  assert obj.lucky_number() == 888.0
296  assert obj.say_everything() == "B says hi 1 times 4444"
297 
298  class CCR(CR):
299  def lucky_number(self):
300  return CR.lucky_number(self) * 10
301 
302  obj = CCR()
303  assert obj.say_something(3) == "B says hi 3 times"
304  assert obj.unlucky_number() == 4444
305  assert obj.lucky_number() == 8892.5
306  assert obj.say_everything() == "B says hi 1 times 4444"
307 
308  class CCT(CT):
309  def lucky_number(self):
310  return CT.lucky_number(self) * 1000
311 
312  obj = CCT()
313  assert obj.say_something(3) == "B says hi 3 times"
314  assert obj.unlucky_number() == 4444
315  assert obj.lucky_number() == 888000.0
316  assert obj.say_everything() == "B says hi 1 times 4444"
317 
318  class DR(m.D_Repeat):
319  def unlucky_number(self):
320  return 123
321 
322  def lucky_number(self):
323  return 42.0
324 
325  for obj in [m.D_Repeat(), m.D_Tpl()]:
326  assert obj.say_something(3) == "B says hi 3 times"
327  assert obj.unlucky_number() == 4444
328  assert obj.lucky_number() == 888.0
329  assert obj.say_everything() == "B says hi 1 times 4444"
330 
331  obj = DR()
332  assert obj.say_something(3) == "B says hi 3 times"
333  assert obj.unlucky_number() == 123
334  assert obj.lucky_number() == 42.0
335  assert obj.say_everything() == "B says hi 1 times 123"
336 
337  class DT(m.D_Tpl):
338  def say_something(self, times):
339  return "DT says:" + (' quack' * times)
340 
341  def unlucky_number(self):
342  return 1234
343 
344  def lucky_number(self):
345  return -4.25
346 
347  obj = DT()
348  assert obj.say_something(3) == "DT says: quack quack quack"
349  assert obj.unlucky_number() == 1234
350  assert obj.lucky_number() == -4.25
351  assert obj.say_everything() == "DT says: quack 1234"
352 
353  class DT2(DT):
354  def say_something(self, times):
355  return "DT2: " + ('QUACK' * times)
356 
357  def unlucky_number(self):
358  return -3
359 
360  class BT(m.B_Tpl):
361  def say_something(self, times):
362  return "BT" * times
363 
364  def unlucky_number(self):
365  return -7
366 
367  def lucky_number(self):
368  return -1.375
369 
370  obj = BT()
371  assert obj.say_something(3) == "BTBTBT"
372  assert obj.unlucky_number() == -7
373  assert obj.lucky_number() == -1.375
374  assert obj.say_everything() == "BT -7"
375 
376 
378  # Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
379  m.test_gil()
380  m.test_gil_from_thread()
void print(const Matrix &A, const string &s, ostream &stream)
Definition: Matrix.cpp:155
def test_alias_delay_initialization1(capture)
bool hasattr(handle obj, handle name)
Definition: pytypes.h:403
static ConstructorStats & get(std::type_index type)
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
def test_alias_delay_initialization2(capture)
def test_override(capture, msg)
void run(Expr &expr, Dev &dev)
Definition: TensorSyclRun.h:33


gtsam
Author(s):
autogenerated on Sat May 8 2021 02:46:04