blob: be21f3709f4f7bc8b363ed86b4d9af99856dc77f [file] [log] [blame]
Henry Schreinerd8c7ee02020-07-20 13:35:21 -04001# -*- coding: utf-8 -*-
Dean Moldovan83e328f2017-06-09 00:44:49 +02002import pytest
3
Henry Schreiner4d9024e2020-08-16 16:02:12 -04004import env # noqa: F401
5
Dean Moldovan83e328f2017-06-09 00:44:49 +02006from pybind11_tests import class_ as m
7from pybind11_tests import UserType, ConstructorStats
8
9
10def test_repr():
11 # In Python 3.3+, repr() accesses __qualname__
12 assert "pybind11_type" in repr(type(UserType))
13 assert "UserType" in repr(UserType)
14
15
16def test_instance(msg):
17 with pytest.raises(TypeError) as excinfo:
18 m.NoConstructor()
19 assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!"
20
21 instance = m.NoConstructor.new_instance()
22
23 cstats = ConstructorStats.get(m.NoConstructor)
24 assert cstats.alive() == 1
25 del instance
26 assert cstats.alive() == 0
27
28
Henry Schreinerf12ec002020-09-14 18:06:26 -040029def test_type():
30 assert m.check_type(1) == m.DerivedClass1
31 with pytest.raises(RuntimeError) as execinfo:
32 m.check_type(0)
33
34 assert 'pybind11::detail::get_type_info: unable to find type info' in str(execinfo.value)
35 assert 'Invalid' in str(execinfo.value)
36
37 # Currently not supported
38 # See https://github.com/pybind/pybind11/issues/2486
39 # assert m.check_type(2) == int
40
41
42def test_type_of_py():
43 assert m.get_type_of(1) == int
44 assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
45 assert m.get_type_of(int) == type
46
47
48def test_type_of_py_nodelete():
49 # If the above test deleted the class, this will segfault
50 assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
51
52
53def test_as_type_py():
54 assert m.as_type(int) == int
55
56 with pytest.raises(RuntimeError):
57 assert m.as_type(1) == int
58
59 with pytest.raises(RuntimeError):
60 assert m.as_type(m.DerivedClass1()) == m.DerivedClass1
61
62
Dean Moldovan83e328f2017-06-09 00:44:49 +020063def test_docstrings(doc):
64 assert doc(UserType) == "A `py::class_` type for testing"
65 assert UserType.__name__ == "UserType"
66 assert UserType.__module__ == "pybind11_tests"
67 assert UserType.get_value.__name__ == "get_value"
68 assert UserType.get_value.__module__ == "pybind11_tests"
69
70 assert doc(UserType.get_value) == """
71 get_value(self: m.UserType) -> int
72
73 Get value using a method
74 """
Jason Rhinelander391c7542017-07-25 16:47:36 -040075 assert doc(UserType.value) == "Get/set value using a property"
Dean Moldovan83e328f2017-06-09 00:44:49 +020076
77 assert doc(m.NoConstructor.new_instance) == """
78 new_instance() -> m.class_.NoConstructor
79
80 Return an instance
81 """
Dean Moldovan0bc272b2017-06-22 23:42:11 +020082
83
Jason Rhinelander71178922017-11-07 12:33:05 -040084def test_qualname(doc):
85 """Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we
86 backport the attribute) and that generated docstrings properly use it and the module name"""
87 assert m.NestBase.__qualname__ == "NestBase"
88 assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
89
90 assert doc(m.NestBase.__init__) == """
91 __init__(self: m.class_.NestBase) -> None
92 """
93 assert doc(m.NestBase.g) == """
94 g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None
95 """
96 assert doc(m.NestBase.Nested.__init__) == """
97 __init__(self: m.class_.NestBase.Nested) -> None
98 """
99 assert doc(m.NestBase.Nested.fn) == """
100 fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
101 """ # noqa: E501 line too long
102 assert doc(m.NestBase.Nested.fa) == """
103 fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
104 """ # noqa: E501 line too long
105 assert m.NestBase.__module__ == "pybind11_tests.class_"
106 assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
107
108
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200109def test_inheritance(msg):
110 roger = m.Rabbit('Rabbit')
111 assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
112 assert m.pet_name_species(roger) == "Rabbit is a parrot"
113
114 polly = m.Pet('Polly', 'parrot')
115 assert polly.name() + " is a " + polly.species() == "Polly is a parrot"
116 assert m.pet_name_species(polly) == "Polly is a parrot"
117
118 molly = m.Dog('Molly')
119 assert molly.name() + " is a " + molly.species() == "Molly is a dog"
120 assert m.pet_name_species(molly) == "Molly is a dog"
121
122 fred = m.Hamster('Fred')
123 assert fred.name() + " is a " + fred.species() == "Fred is a rodent"
124
125 assert m.dog_bark(molly) == "Woof!"
126
127 with pytest.raises(TypeError) as excinfo:
128 m.dog_bark(polly)
129 assert msg(excinfo.value) == """
130 dog_bark(): incompatible function arguments. The following argument types are supported:
131 1. (arg0: m.class_.Dog) -> str
132
133 Invoked with: <m.class_.Pet object at 0>
134 """
135
136 with pytest.raises(TypeError) as excinfo:
137 m.Chimera("lion", "goat")
138 assert "No constructor defined!" in str(excinfo.value)
139
140
Dustin Spicuzza1b0bf352020-07-07 06:04:06 -0400141def test_inheritance_init(msg):
142
143 # Single base
144 class Python(m.Pet):
145 def __init__(self):
146 pass
147 with pytest.raises(TypeError) as exc_info:
148 Python()
Yannick Jadoulf980d762020-07-09 00:14:41 +0200149 expected = ["m.class_.Pet.__init__() must be called when overriding __init__",
150 "Pet.__init__() must be called when overriding __init__"] # PyPy?
151 # TODO: fix PyPy error message wrt. tp_name/__qualname__?
152 assert msg(exc_info.value) in expected
Dustin Spicuzza1b0bf352020-07-07 06:04:06 -0400153
154 # Multiple bases
155 class RabbitHamster(m.Rabbit, m.Hamster):
156 def __init__(self):
157 m.Rabbit.__init__(self, "RabbitHamster")
158
159 with pytest.raises(TypeError) as exc_info:
160 RabbitHamster()
Yannick Jadoulf980d762020-07-09 00:14:41 +0200161 expected = ["m.class_.Hamster.__init__() must be called when overriding __init__",
162 "Hamster.__init__() must be called when overriding __init__"] # PyPy
163 assert msg(exc_info.value) in expected
Dustin Spicuzza1b0bf352020-07-07 06:04:06 -0400164
165
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200166def test_automatic_upcasting():
167 assert type(m.return_class_1()).__name__ == "DerivedClass1"
168 assert type(m.return_class_2()).__name__ == "DerivedClass2"
169 assert type(m.return_none()).__name__ == "NoneType"
170 # Repeat these a few times in a random order to ensure no invalid caching is applied
171 assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
172 assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
173 assert type(m.return_class_n(0)).__name__ == "BaseClass"
174 assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
175 assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
176 assert type(m.return_class_n(0)).__name__ == "BaseClass"
177 assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
178
179
180def test_isinstance():
181 objects = [tuple(), dict(), m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4
182 expected = (True, True, True, True, True, False, False)
183 assert m.check_instances(objects) == expected
184
185
186def test_mismatched_holder():
187 import re
188
189 with pytest.raises(RuntimeError) as excinfo:
190 m.mismatched_holder_1()
191 assert re.match('generic_type: type ".*MismatchDerived1" does not have a non-default '
192 'holder type while its base ".*MismatchBase1" does', str(excinfo.value))
193
194 with pytest.raises(RuntimeError) as excinfo:
195 m.mismatched_holder_2()
196 assert re.match('generic_type: type ".*MismatchDerived2" has a non-default holder type '
197 'while its base ".*MismatchBase2" does not', str(excinfo.value))
198
199
200def test_override_static():
201 """#511: problem with inheritance + overwritten def_static"""
202 b = m.MyBase.make()
203 d1 = m.MyDerived.make2()
204 d2 = m.MyDerived.make()
205
206 assert isinstance(b, m.MyBase)
207 assert isinstance(d1, m.MyDerived)
208 assert isinstance(d2, m.MyDerived)
Dean Moldovanaf2dda32017-06-26 20:34:06 +0200209
210
211def test_implicit_conversion_life_support():
212 """Ensure the lifetime of temporary objects created for implicit conversions"""
213 assert m.implicitly_convert_argument(UserType(5)) == 5
214 assert m.implicitly_convert_variable(UserType(5)) == 5
215
216 assert "outside a bound function" in m.implicitly_convert_variable_fail(UserType(5))
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400217
218
219def test_operator_new_delete(capture):
220 """Tests that class-specific operator new/delete functions are invoked"""
221
222 class SubAliased(m.AliasedHasOpNewDelSize):
223 pass
224
225 with capture:
226 a = m.HasOpNewDel()
227 b = m.HasOpNewDelSize()
228 d = m.HasOpNewDelBoth()
229 assert capture == """
230 A new 8
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400231 B new 4
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400232 D new 32
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400233 """
234 sz_alias = str(m.AliasedHasOpNewDelSize.size_alias)
235 sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias)
236 with capture:
237 c = m.AliasedHasOpNewDelSize()
238 c2 = SubAliased()
239 assert capture == (
Jason Rhinelanderc4e18002017-08-17 00:01:42 -0400240 "C new " + sz_noalias + "\n" +
241 "C new " + sz_alias + "\n"
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400242 )
243
244 with capture:
245 del a
Jason Rhinelander9866a0f2017-07-26 13:52:53 -0400246 pytest.gc_collect()
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400247 del b
Jason Rhinelander9866a0f2017-07-26 13:52:53 -0400248 pytest.gc_collect()
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400249 del d
Jason Rhinelander9866a0f2017-07-26 13:52:53 -0400250 pytest.gc_collect()
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400251 assert capture == """
252 A delete
253 B delete 4
254 D delete
255 """
256
257 with capture:
258 del c
Jason Rhinelander9866a0f2017-07-26 13:52:53 -0400259 pytest.gc_collect()
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400260 del c2
Jason Rhinelander9866a0f2017-07-26 13:52:53 -0400261 pytest.gc_collect()
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400262 assert capture == (
263 "C delete " + sz_noalias + "\n" +
264 "C delete " + sz_alias + "\n"
265 )
Dean Moldovan234f7c32017-08-17 17:03:46 +0200266
267
268def test_bind_protected_functions():
269 """Expose protected member functions to Python using a helper class"""
270 a = m.ProtectedA()
271 assert a.foo() == 42
272
273 b = m.ProtectedB()
274 assert b.foo() == 42
275
276 class C(m.ProtectedB):
277 def __init__(self):
278 m.ProtectedB.__init__(self)
279
280 def foo(self):
281 return 0
282
283 c = C()
284 assert c.foo() == 0
Wenzel Jakob4336a7d2017-08-21 22:48:28 +0200285
286
287def test_brace_initialization():
288 """ Tests that simple POD classes can be constructed using C++11 brace initialization """
289 a = m.BraceInitialization(123, "test")
290 assert a.field1 == 123
291 assert a.field2 == "test"
Wenzel Jakobc14c2762017-08-25 16:02:18 +0200292
Jason Rhinelanderadbc8112018-01-11 13:22:13 -0400293 # Tests that a non-simple class doesn't get brace initialization (if the
294 # class defines an initializer_list constructor, in particular, it would
295 # win over the expected constructor).
296 b = m.NoBraceInitialization([123, 456])
297 assert b.vec == [123, 456]
298
Wenzel Jakobc14c2762017-08-25 16:02:18 +0200299
Henry Schreiner4d9024e2020-08-16 16:02:12 -0400300@pytest.mark.xfail("env.PYPY")
Wenzel Jakobc14c2762017-08-25 16:02:18 +0200301def test_class_refcount():
302 """Instances must correctly increase/decrease the reference count of their types (#1029)"""
303 from sys import getrefcount
304
305 class PyDog(m.Dog):
306 pass
307
308 for cls in m.Dog, PyDog:
309 refcount_1 = getrefcount(cls)
310 molly = [cls("Molly") for _ in range(10)]
311 refcount_2 = getrefcount(cls)
312
313 del molly
314 pytest.gc_collect()
315 refcount_3 = getrefcount(cls)
316
317 assert refcount_1 == refcount_3
318 assert refcount_2 > refcount_1
Wenzel Jakob8ed5b8a2017-08-28 16:34:06 +0200319
320
321def test_reentrant_implicit_conversion_failure(msg):
322 # ensure that there is no runaway reentrant implicit conversion (#1035)
323 with pytest.raises(TypeError) as excinfo:
324 m.BogusImplicitConversion(0)
Jason Rhinelander71178922017-11-07 12:33:05 -0400325 assert msg(excinfo.value) == '''
326 __init__(): incompatible constructor arguments. The following argument types are supported:
327 1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
Wenzel Jakob8ed5b8a2017-08-28 16:34:06 +0200328
Jason Rhinelander71178922017-11-07 12:33:05 -0400329 Invoked with: 0
330 '''
oremanje7761e32018-09-25 14:55:18 -0700331
332
333def test_error_after_conversions():
334 with pytest.raises(TypeError) as exc_info:
335 m.test_error_after_conversions("hello")
336 assert str(exc_info.value).startswith(
337 "Unable to convert function return value to a Python type!")
Wenzel Jakobe2eca4f2018-11-09 20:14:53 +0100338
339
340def test_aligned():
341 if hasattr(m, "Aligned"):
342 p = m.Aligned().ptr()
343 assert p % 1024 == 0
Dustin Spicuzza0dfffcf2020-04-05 02:34:00 -0400344
345
Henry Schreiner4d9024e2020-08-16 16:02:12 -0400346# https://foss.heptapod.net/pypy/pypy/-/issues/2742
347@pytest.mark.xfail("env.PYPY")
Dustin Spicuzza0dfffcf2020-04-05 02:34:00 -0400348def test_final():
349 with pytest.raises(TypeError) as exc_info:
350 class PyFinalChild(m.IsFinal):
351 pass
352 assert str(exc_info.value).endswith("is not an acceptable base type")
353
354
Henry Schreiner4d9024e2020-08-16 16:02:12 -0400355# https://foss.heptapod.net/pypy/pypy/-/issues/2742
356@pytest.mark.xfail("env.PYPY")
Dustin Spicuzza0dfffcf2020-04-05 02:34:00 -0400357def test_non_final_final():
358 with pytest.raises(TypeError) as exc_info:
359 class PyNonFinalFinalChild(m.IsNonFinalFinal):
360 pass
361 assert str(exc_info.value).endswith("is not an acceptable base type")
jbarlow834d90f1a2020-07-31 17:46:12 -0700362
363
364# https://github.com/pybind/pybind11/issues/1878
365def test_exception_rvalue_abort():
366 with pytest.raises(RuntimeError):
367 m.PyPrintDestructor().throw_something()