test_class.py
Go to the documentation of this file.
1 from __future__ import annotations
2 
3 from unittest import mock
4 
5 import pytest
6 
7 import env
8 from pybind11_tests import PYBIND11_REFCNT_IMMORTAL, ConstructorStats, UserType
9 from pybind11_tests import class_ as m
10 
11 
13  expected_name = "UserType" if env.PYPY else "pybind11_tests.UserType"
14  assert m.obj_class_name(UserType(1)) == expected_name
15  assert m.obj_class_name(UserType) == expected_name
16 
17 
18 def test_repr():
19  assert "pybind11_type" in repr(type(UserType))
20  assert "UserType" in repr(UserType)
21 
22 
23 def test_instance(msg):
24  with pytest.raises(TypeError) as excinfo:
25  m.NoConstructor()
26  assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!"
27 
28  instance = m.NoConstructor.new_instance()
29 
30  cstats = ConstructorStats.get(m.NoConstructor)
31  assert cstats.alive() == 1
32  del instance
33  assert cstats.alive() == 0
34 
35 
37  instance = m.NoConstructorNew() # .__new__(m.NoConstructor.__class__)
38  cstats = ConstructorStats.get(m.NoConstructorNew)
39  assert cstats.alive() == 1
40  del instance
41  assert cstats.alive() == 0
42 
43 
44 def test_type():
45  assert m.check_type(1) == m.DerivedClass1
46  with pytest.raises(RuntimeError) as execinfo:
47  m.check_type(0)
48 
49  assert "pybind11::detail::get_type_info: unable to find type info" in str(
50  execinfo.value
51  )
52  assert "Invalid" in str(execinfo.value)
53 
54  # Currently not supported
55  # See https://github.com/pybind/pybind11/issues/2486
56  # assert m.check_type(2) == int
57 
58 
60  assert m.get_type_of(1) == int
61  assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
62  assert m.get_type_of(int) == type
63 
64 
66  assert m.get_type_classic(1) == int
67  assert m.get_type_classic(m.DerivedClass1()) == m.DerivedClass1
68  assert m.get_type_classic(int) == type
69 
70 
72  # If the above test deleted the class, this will segfault
73  assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
74 
75 
77  assert m.as_type(int) == int
78 
79  with pytest.raises(TypeError):
80  assert m.as_type(1) == int
81 
82  with pytest.raises(TypeError):
83  assert m.as_type(m.DerivedClass1()) == m.DerivedClass1
84 
85 
86 def test_docstrings(doc):
87  assert doc(UserType) == "A `py::class_` type for testing"
88  assert UserType.__name__ == "UserType"
89  assert UserType.__module__ == "pybind11_tests"
90  assert UserType.get_value.__name__ == "get_value"
91  assert UserType.get_value.__module__ == "pybind11_tests"
92 
93  assert (
94  doc(UserType.get_value)
95  == """
96  get_value(self: m.UserType) -> int
97 
98  Get value using a method
99  """
100  )
101  assert doc(UserType.value) == "Get/set value using a property"
102 
103  assert (
104  doc(m.NoConstructor.new_instance)
105  == """
106  new_instance() -> m.class_.NoConstructor
107 
108  Return an instance
109  """
110  )
111 
112 
113 def test_qualname(doc):
114  """Tests that a properly qualified name is set in __qualname__ and that
115  generated docstrings properly use it and the module name"""
116  assert m.NestBase.__qualname__ == "NestBase"
117  assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
118 
119  assert (
120  doc(m.NestBase.__init__)
121  == """
122  __init__(self: m.class_.NestBase) -> None
123  """
124  )
125  assert (
126  doc(m.NestBase.g)
127  == """
128  g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None
129  """
130  )
131  assert (
132  doc(m.NestBase.Nested.__init__)
133  == """
134  __init__(self: m.class_.NestBase.Nested) -> None
135  """
136  )
137  assert (
138  doc(m.NestBase.Nested.fn)
139  == """
140  fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
141  """
142  )
143  assert (
144  doc(m.NestBase.Nested.fa)
145  == """
146  fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
147  """
148  )
149  assert m.NestBase.__module__ == "pybind11_tests.class_"
150  assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
151 
152 
154  roger = m.Rabbit("Rabbit")
155  assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
156  assert m.pet_name_species(roger) == "Rabbit is a parrot"
157 
158  polly = m.Pet("Polly", "parrot")
159  assert polly.name() + " is a " + polly.species() == "Polly is a parrot"
160  assert m.pet_name_species(polly) == "Polly is a parrot"
161 
162  molly = m.Dog("Molly")
163  assert molly.name() + " is a " + molly.species() == "Molly is a dog"
164  assert m.pet_name_species(molly) == "Molly is a dog"
165 
166  fred = m.Hamster("Fred")
167  assert fred.name() + " is a " + fred.species() == "Fred is a rodent"
168 
169  assert m.dog_bark(molly) == "Woof!"
170 
171  with pytest.raises(TypeError) as excinfo:
172  m.dog_bark(polly)
173  assert (
174  msg(excinfo.value)
175  == """
176  dog_bark(): incompatible function arguments. The following argument types are supported:
177  1. (arg0: m.class_.Dog) -> str
178 
179  Invoked with: <m.class_.Pet object at 0>
180  """
181  )
182 
183  with pytest.raises(TypeError) as excinfo:
184  m.Chimera("lion", "goat")
185  assert "No constructor defined!" in str(excinfo.value)
186 
187 
189  # Single base
190  class Python(m.Pet):
191  def __init__(self):
192  pass
193 
194  with pytest.raises(TypeError) as exc_info:
195  Python()
196  expected = "m.class_.Pet.__init__() must be called when overriding __init__"
197  assert msg(exc_info.value) == expected
198 
199  # Multiple bases
200  class RabbitHamster(m.Rabbit, m.Hamster):
201  def __init__(self):
202  m.Rabbit.__init__(self, "RabbitHamster")
203 
204  with pytest.raises(TypeError) as exc_info:
205  RabbitHamster()
206  expected = "m.class_.Hamster.__init__() must be called when overriding __init__"
207  assert msg(exc_info.value) == expected
208 
209 
210 @pytest.mark.parametrize(
211  "mock_return_value", [None, (1, 2, 3), m.Pet("Polly", "parrot"), m.Dog("Molly")]
212 )
213 def test_mock_new(mock_return_value):
214  with mock.patch.object(
215  m.Pet, "__new__", return_value=mock_return_value
216  ) as mock_new:
217  obj = m.Pet("Noname", "Nospecies")
218  assert obj is mock_return_value
219  mock_new.assert_called_once_with(m.Pet, "Noname", "Nospecies")
220 
221 
223  assert type(m.return_class_1()).__name__ == "DerivedClass1"
224  assert type(m.return_class_2()).__name__ == "DerivedClass2"
225  assert type(m.return_none()).__name__ == "NoneType"
226  # Repeat these a few times in a random order to ensure no invalid caching is applied
227  assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
228  assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
229  assert type(m.return_class_n(0)).__name__ == "BaseClass"
230  assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
231  assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
232  assert type(m.return_class_n(0)).__name__ == "BaseClass"
233  assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
234 
235 
237  objects = [(), {}, m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4
238  expected = (True, True, True, True, True, False, False)
239  assert m.check_instances(objects) == expected
240 
241 
243  import re
244 
245  with pytest.raises(RuntimeError) as excinfo:
246  m.mismatched_holder_1()
247  assert re.match(
248  'generic_type: type ".*MismatchDerived1" does not have a non-default '
249  'holder type while its base ".*MismatchBase1" does',
250  str(excinfo.value),
251  )
252 
253  with pytest.raises(RuntimeError) as excinfo:
254  m.mismatched_holder_2()
255  assert re.match(
256  'generic_type: type ".*MismatchDerived2" has a non-default holder type '
257  'while its base ".*MismatchBase2" does not',
258  str(excinfo.value),
259  )
260 
261 
263  """#511: problem with inheritance + overwritten def_static"""
264  b = m.MyBase.make()
265  d1 = m.MyDerived.make2()
266  d2 = m.MyDerived.make()
267 
268  assert isinstance(b, m.MyBase)
269  assert isinstance(d1, m.MyDerived)
270  assert isinstance(d2, m.MyDerived)
271 
272 
274  """Ensure the lifetime of temporary objects created for implicit conversions"""
275  assert m.implicitly_convert_argument(UserType(5)) == 5
276  assert m.implicitly_convert_variable(UserType(5)) == 5
277 
278  assert "outside a bound function" in m.implicitly_convert_variable_fail(UserType(5))
279 
280 
282  """Tests that class-specific operator new/delete functions are invoked"""
283 
284  class SubAliased(m.AliasedHasOpNewDelSize):
285  pass
286 
287  with capture:
288  a = m.HasOpNewDel()
289  b = m.HasOpNewDelSize()
290  d = m.HasOpNewDelBoth()
291  assert (
292  capture
293  == """
294  A new 8
295  B new 4
296  D new 32
297  """
298  )
299  sz_alias = str(m.AliasedHasOpNewDelSize.size_alias)
300  sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias)
301  with capture:
302  c = m.AliasedHasOpNewDelSize()
303  c2 = SubAliased()
304  assert capture == ("C new " + sz_noalias + "\n" + "C new " + sz_alias + "\n")
305 
306  with capture:
307  del a
308  pytest.gc_collect()
309  del b
310  pytest.gc_collect()
311  del d
312  pytest.gc_collect()
313  assert (
314  capture
315  == """
316  A delete
317  B delete 4
318  D delete
319  """
320  )
321 
322  with capture:
323  del c
324  pytest.gc_collect()
325  del c2
326  pytest.gc_collect()
327  assert capture == ("C delete " + sz_noalias + "\n" + "C delete " + sz_alias + "\n")
328 
329 
331  """Expose protected member functions to Python using a helper class"""
332  a = m.ProtectedA()
333  assert a.foo() == 42
334 
335  b = m.ProtectedB()
336  assert b.foo() == 42
337  assert m.read_foo(b.void_foo()) == 42
338  assert m.pointers_equal(b.get_self(), b)
339 
340  class C(m.ProtectedB):
341  def __init__(self):
342  m.ProtectedB.__init__(self)
343 
344  def foo(self):
345  return 0
346 
347  c = C()
348  assert c.foo() == 0
349 
350 
352  """Tests that simple POD classes can be constructed using C++11 brace initialization"""
353  a = m.BraceInitialization(123, "test")
354  assert a.field1 == 123
355  assert a.field2 == "test"
356 
357  # Tests that a non-simple class doesn't get brace initialization (if the
358  # class defines an initializer_list constructor, in particular, it would
359  # win over the expected constructor).
360  b = m.NoBraceInitialization([123, 456])
361  assert b.vec == [123, 456]
362 
363 
364 @pytest.mark.xfail("env.PYPY")
366  """Instances must correctly increase/decrease the reference count of their types (#1029)"""
367  from sys import getrefcount
368 
369  class PyDog(m.Dog):
370  pass
371 
372  for cls in m.Dog, PyDog:
373  refcount_1 = getrefcount(cls)
374  molly = [cls("Molly") for _ in range(10)]
375  refcount_2 = getrefcount(cls)
376 
377  del molly
378  pytest.gc_collect()
379  refcount_3 = getrefcount(cls)
380 
381  assert refcount_1 == refcount_3
382  assert (refcount_2 > refcount_1) or (
383  refcount_2 == refcount_1 == PYBIND11_REFCNT_IMMORTAL
384  )
385 
386 
388  # ensure that there is no runaway reentrant implicit conversion (#1035)
389  with pytest.raises(TypeError) as excinfo:
390  m.BogusImplicitConversion(0)
391  assert (
392  msg(excinfo.value)
393  == """
394  __init__(): incompatible constructor arguments. The following argument types are supported:
395  1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
396 
397  Invoked with: 0
398  """
399  )
400 
401 
403  with pytest.raises(TypeError) as exc_info:
404  m.test_error_after_conversions("hello")
405  assert str(exc_info.value).startswith(
406  "Unable to convert function return value to a Python type!"
407  )
408 
409 
411  if hasattr(m, "Aligned"):
412  p = m.Aligned().ptr()
413  assert p % 1024 == 0
414 
415 
416 # https://foss.heptapod.net/pypy/pypy/-/issues/2742
417 @pytest.mark.xfail("env.PYPY")
419  with pytest.raises(TypeError) as exc_info:
420 
421  class PyFinalChild(m.IsFinal):
422  pass
423 
424  assert str(exc_info.value).endswith("is not an acceptable base type")
425 
426 
427 # https://foss.heptapod.net/pypy/pypy/-/issues/2742
428 @pytest.mark.xfail("env.PYPY")
430  with pytest.raises(TypeError) as exc_info:
431 
432  class PyNonFinalFinalChild(m.IsNonFinalFinal):
433  pass
434 
435  assert str(exc_info.value).endswith("is not an acceptable base type")
436 
437 
438 # https://github.com/pybind/pybind11/issues/1878
440  with pytest.raises(RuntimeError):
441  m.PyPrintDestructor().throw_something()
442 
443 
444 # https://github.com/pybind/pybind11/issues/1568
446  n = 100
447  instances = [m.SamePointer() for _ in range(n)]
448  for i in range(n):
449  # We need to reuse the same allocated memory for with a different type,
450  # to ensure the bug in `deregister_instance_impl` is detected. Otherwise
451  # `Py_TYPE(self) == Py_TYPE(it->second)` will still succeed, even though
452  # the `instance` is already deleted.
453  instances[i] = m.Empty()
454  # No assert: if this does not trigger the error
455  # pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
456  # and just completes without crashing, we're good.
457 
458 
459 # https://github.com/pybind/pybind11/issues/1624
461  assert issubclass(m.DerivedWithNested, m.BaseWithNested)
462  assert m.BaseWithNested.Nested != m.DerivedWithNested.Nested
463  assert m.BaseWithNested.Nested.get_name() == "BaseWithNested::Nested"
464  assert m.DerivedWithNested.Nested.get_name() == "DerivedWithNested::Nested"
465 
466 
468  import types
469 
470  module_scope = types.ModuleType("module_scope")
471  with pytest.raises(RuntimeError) as exc_info:
472  m.register_duplicate_class_name(module_scope)
473  expected = (
474  'generic_type: cannot initialize type "Duplicate": '
475  "an object with that name is already defined"
476  )
477  assert str(exc_info.value) == expected
478  with pytest.raises(RuntimeError) as exc_info:
479  m.register_duplicate_class_type(module_scope)
480  expected = 'generic_type: type "YetAnotherDuplicate" is already registered!'
481  assert str(exc_info.value) == expected
482 
483  class ClassScope:
484  pass
485 
486  with pytest.raises(RuntimeError) as exc_info:
487  m.register_duplicate_nested_class_name(ClassScope)
488  expected = (
489  'generic_type: cannot initialize type "DuplicateNested": '
490  "an object with that name is already defined"
491  )
492  assert str(exc_info.value) == expected
493  with pytest.raises(RuntimeError) as exc_info:
494  m.register_duplicate_nested_class_type(ClassScope)
495  expected = 'generic_type: type "YetAnotherDuplicateNested" is already registered!'
496  assert str(exc_info.value) == expected
497 
498 
500  assert (
501  m.Empty0().get_msg()
502  == "This is really only meant to exercise successful compilation."
503  )
test_class.test_exception_rvalue_abort
def test_exception_rvalue_abort()
Definition: test_class.py:439
test_class.test_aligned
def test_aligned()
Definition: test_class.py:410
test_class.test_repr
def test_repr()
Definition: test_class.py:18
test_class.test_inheritance
def test_inheritance(msg)
Definition: test_class.py:153
test_class.test_qualname
def test_qualname(doc)
Definition: test_class.py:113
test_class.test_multiple_instances_with_same_pointer
def test_multiple_instances_with_same_pointer()
Definition: test_class.py:445
hasattr
bool hasattr(handle obj, handle name)
Definition: pytypes.h:870
type
Definition: pytypes.h:1525
test_class.test_final
def test_final()
Definition: test_class.py:418
test_class.test_mock_new
def test_mock_new(mock_return_value)
Definition: test_class.py:213
test_class.test_override_static
def test_override_static()
Definition: test_class.py:262
gtsam::range
Double_ range(const Point2_ &p, const Point2_ &q)
Definition: slam/expressions.h:30
test_class.test_non_final_final
def test_non_final_final()
Definition: test_class.py:429
doc
Annotation for documentation.
Definition: attr.h:45
test_class.test_as_type_py
def test_as_type_py()
Definition: test_class.py:76
isinstance
bool isinstance(handle obj)
Definition: pytypes.h:842
test_class.test_type_of_classic
def test_type_of_classic()
Definition: test_class.py:65
test_class.test_instance_new
def test_instance_new()
Definition: test_class.py:36
test_class.test_register_duplicate_class
def test_register_duplicate_class()
Definition: test_class.py:467
test_class.test_type_of_py_nodelete
def test_type_of_py_nodelete()
Definition: test_class.py:71
test_class::pr4220_tripped_over_this::get_msg
std::string get_msg(const T &)
Definition: test_class.cpp:44
foo
void foo(CV_QUALIFIER Matrix3d &m)
Definition: block_nonconst_ctor_on_const_xpr_0.cpp:11
test_class.test_error_after_conversions
def test_error_after_conversions()
Definition: test_class.py:402
test_class.test_instance
def test_instance(msg)
Definition: test_class.py:23
gtwrap.interface_parser.function.__init__
def __init__(self, Union[Type, TemplatedType] ctype, str name, ParseResults default=None)
Definition: interface_parser/function.py:41
test_class.test_isinstance
def test_isinstance()
Definition: test_class.py:236
str
Definition: pytypes.h:1558
test_class.test_type_of_py
def test_type_of_py()
Definition: test_class.py:59
test_class.test_class_refcount
def test_class_refcount()
Definition: test_class.py:365
test_class.test_base_and_derived_nested_scope
def test_base_and_derived_nested_scope()
Definition: test_class.py:460
C
Matrix< Scalar, Dynamic, Dynamic > C
Definition: bench_gemm.cpp:50
ConstructorStats::get
static ConstructorStats & get(std::type_index type)
Definition: constructor_stats.h:163
test_class.test_docstrings
def test_docstrings(doc)
Definition: test_class.py:86
test_class.test_mismatched_holder
def test_mismatched_holder()
Definition: test_class.py:242
test_class.test_inheritance_init
def test_inheritance_init(msg)
Definition: test_class.py:188
test_class.test_automatic_upcasting
def test_automatic_upcasting()
Definition: test_class.py:222
test_class.test_bind_protected_functions
def test_bind_protected_functions()
Definition: test_class.py:330
test_class.test_brace_initialization
def test_brace_initialization()
Definition: test_class.py:351
test_class.test_implicit_conversion_life_support
def test_implicit_conversion_life_support()
Definition: test_class.py:273
test_class.test_obj_class_name
def test_obj_class_name()
Definition: test_class.py:12
test_class.test_operator_new_delete
def test_operator_new_delete(capture)
Definition: test_class.py:281
test_class.test_reentrant_implicit_conversion_failure
def test_reentrant_implicit_conversion_failure(msg)
Definition: test_class.py:387
test_class.test_pr4220_tripped_over_this
def test_pr4220_tripped_over_this()
Definition: test_class.py:499
test_class.test_type
def test_type()
Definition: test_class.py:44
pybind11.msg
msg
Definition: wrap/pybind11/pybind11/__init__.py:6
repr
str repr(handle h)
Definition: pytypes.h:2467


gtsam
Author(s):
autogenerated on Sun Dec 22 2024 04:15:58