blob: c38a5e8ce8a6410c0ba3d116277b3bded0c7a2c4 [file] [log] [blame]
Henry Schreinerd8c7ee02020-07-20 13:35:21 -04001# -*- coding: utf-8 -*-
Dean Moldovan83e328f2017-06-09 00:44:49 +02002import pytest
3
4from pybind11_tests import class_ as m
5from pybind11_tests import UserType, ConstructorStats
6
7
8def test_repr():
9 # In Python 3.3+, repr() accesses __qualname__
10 assert "pybind11_type" in repr(type(UserType))
11 assert "UserType" in repr(UserType)
12
13
14def test_instance(msg):
15 with pytest.raises(TypeError) as excinfo:
16 m.NoConstructor()
17 assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!"
18
19 instance = m.NoConstructor.new_instance()
20
21 cstats = ConstructorStats.get(m.NoConstructor)
22 assert cstats.alive() == 1
23 del instance
24 assert cstats.alive() == 0
25
26
27def test_docstrings(doc):
28 assert doc(UserType) == "A `py::class_` type for testing"
29 assert UserType.__name__ == "UserType"
30 assert UserType.__module__ == "pybind11_tests"
31 assert UserType.get_value.__name__ == "get_value"
32 assert UserType.get_value.__module__ == "pybind11_tests"
33
34 assert doc(UserType.get_value) == """
35 get_value(self: m.UserType) -> int
36
37 Get value using a method
38 """
Jason Rhinelander391c7542017-07-25 16:47:36 -040039 assert doc(UserType.value) == "Get/set value using a property"
Dean Moldovan83e328f2017-06-09 00:44:49 +020040
41 assert doc(m.NoConstructor.new_instance) == """
42 new_instance() -> m.class_.NoConstructor
43
44 Return an instance
45 """
Dean Moldovan0bc272b2017-06-22 23:42:11 +020046
47
Jason Rhinelander71178922017-11-07 12:33:05 -040048def test_qualname(doc):
49 """Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we
50 backport the attribute) and that generated docstrings properly use it and the module name"""
51 assert m.NestBase.__qualname__ == "NestBase"
52 assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
53
54 assert doc(m.NestBase.__init__) == """
55 __init__(self: m.class_.NestBase) -> None
56 """
57 assert doc(m.NestBase.g) == """
58 g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None
59 """
60 assert doc(m.NestBase.Nested.__init__) == """
61 __init__(self: m.class_.NestBase.Nested) -> None
62 """
63 assert doc(m.NestBase.Nested.fn) == """
64 fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
65 """ # noqa: E501 line too long
66 assert doc(m.NestBase.Nested.fa) == """
67 fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
68 """ # noqa: E501 line too long
69 assert m.NestBase.__module__ == "pybind11_tests.class_"
70 assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
71
72
Dean Moldovan0bc272b2017-06-22 23:42:11 +020073def test_inheritance(msg):
74 roger = m.Rabbit('Rabbit')
75 assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
76 assert m.pet_name_species(roger) == "Rabbit is a parrot"
77
78 polly = m.Pet('Polly', 'parrot')
79 assert polly.name() + " is a " + polly.species() == "Polly is a parrot"
80 assert m.pet_name_species(polly) == "Polly is a parrot"
81
82 molly = m.Dog('Molly')
83 assert molly.name() + " is a " + molly.species() == "Molly is a dog"
84 assert m.pet_name_species(molly) == "Molly is a dog"
85
86 fred = m.Hamster('Fred')
87 assert fred.name() + " is a " + fred.species() == "Fred is a rodent"
88
89 assert m.dog_bark(molly) == "Woof!"
90
91 with pytest.raises(TypeError) as excinfo:
92 m.dog_bark(polly)
93 assert msg(excinfo.value) == """
94 dog_bark(): incompatible function arguments. The following argument types are supported:
95 1. (arg0: m.class_.Dog) -> str
96
97 Invoked with: <m.class_.Pet object at 0>
98 """
99
100 with pytest.raises(TypeError) as excinfo:
101 m.Chimera("lion", "goat")
102 assert "No constructor defined!" in str(excinfo.value)
103
104
Dustin Spicuzza1b0bf352020-07-07 06:04:06 -0400105def test_inheritance_init(msg):
106
107 # Single base
108 class Python(m.Pet):
109 def __init__(self):
110 pass
111 with pytest.raises(TypeError) as exc_info:
112 Python()
Yannick Jadoulf980d762020-07-09 00:14:41 +0200113 expected = ["m.class_.Pet.__init__() must be called when overriding __init__",
114 "Pet.__init__() must be called when overriding __init__"] # PyPy?
115 # TODO: fix PyPy error message wrt. tp_name/__qualname__?
116 assert msg(exc_info.value) in expected
Dustin Spicuzza1b0bf352020-07-07 06:04:06 -0400117
118 # Multiple bases
119 class RabbitHamster(m.Rabbit, m.Hamster):
120 def __init__(self):
121 m.Rabbit.__init__(self, "RabbitHamster")
122
123 with pytest.raises(TypeError) as exc_info:
124 RabbitHamster()
Yannick Jadoulf980d762020-07-09 00:14:41 +0200125 expected = ["m.class_.Hamster.__init__() must be called when overriding __init__",
126 "Hamster.__init__() must be called when overriding __init__"] # PyPy
127 assert msg(exc_info.value) in expected
Dustin Spicuzza1b0bf352020-07-07 06:04:06 -0400128
129
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200130def test_automatic_upcasting():
131 assert type(m.return_class_1()).__name__ == "DerivedClass1"
132 assert type(m.return_class_2()).__name__ == "DerivedClass2"
133 assert type(m.return_none()).__name__ == "NoneType"
134 # Repeat these a few times in a random order to ensure no invalid caching is applied
135 assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
136 assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
137 assert type(m.return_class_n(0)).__name__ == "BaseClass"
138 assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
139 assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
140 assert type(m.return_class_n(0)).__name__ == "BaseClass"
141 assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
142
143
144def test_isinstance():
145 objects = [tuple(), dict(), m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4
146 expected = (True, True, True, True, True, False, False)
147 assert m.check_instances(objects) == expected
148
149
150def test_mismatched_holder():
151 import re
152
153 with pytest.raises(RuntimeError) as excinfo:
154 m.mismatched_holder_1()
155 assert re.match('generic_type: type ".*MismatchDerived1" does not have a non-default '
156 'holder type while its base ".*MismatchBase1" does', str(excinfo.value))
157
158 with pytest.raises(RuntimeError) as excinfo:
159 m.mismatched_holder_2()
160 assert re.match('generic_type: type ".*MismatchDerived2" has a non-default holder type '
161 'while its base ".*MismatchBase2" does not', str(excinfo.value))
162
163
164def test_override_static():
165 """#511: problem with inheritance + overwritten def_static"""
166 b = m.MyBase.make()
167 d1 = m.MyDerived.make2()
168 d2 = m.MyDerived.make()
169
170 assert isinstance(b, m.MyBase)
171 assert isinstance(d1, m.MyDerived)
172 assert isinstance(d2, m.MyDerived)
Dean Moldovanaf2dda32017-06-26 20:34:06 +0200173
174
175def test_implicit_conversion_life_support():
176 """Ensure the lifetime of temporary objects created for implicit conversions"""
177 assert m.implicitly_convert_argument(UserType(5)) == 5
178 assert m.implicitly_convert_variable(UserType(5)) == 5
179
180 assert "outside a bound function" in m.implicitly_convert_variable_fail(UserType(5))
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400181
182
183def test_operator_new_delete(capture):
184 """Tests that class-specific operator new/delete functions are invoked"""
185
186 class SubAliased(m.AliasedHasOpNewDelSize):
187 pass
188
189 with capture:
190 a = m.HasOpNewDel()
191 b = m.HasOpNewDelSize()
192 d = m.HasOpNewDelBoth()
193 assert capture == """
194 A new 8
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400195 B new 4
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400196 D new 32
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400197 """
198 sz_alias = str(m.AliasedHasOpNewDelSize.size_alias)
199 sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias)
200 with capture:
201 c = m.AliasedHasOpNewDelSize()
202 c2 = SubAliased()
203 assert capture == (
Jason Rhinelanderc4e18002017-08-17 00:01:42 -0400204 "C new " + sz_noalias + "\n" +
205 "C new " + sz_alias + "\n"
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400206 )
207
208 with capture:
209 del a
Jason Rhinelander9866a0f2017-07-26 13:52:53 -0400210 pytest.gc_collect()
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400211 del b
Jason Rhinelander9866a0f2017-07-26 13:52:53 -0400212 pytest.gc_collect()
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400213 del d
Jason Rhinelander9866a0f2017-07-26 13:52:53 -0400214 pytest.gc_collect()
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400215 assert capture == """
216 A delete
217 B delete 4
218 D delete
219 """
220
221 with capture:
222 del c
Jason Rhinelander9866a0f2017-07-26 13:52:53 -0400223 pytest.gc_collect()
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400224 del c2
Jason Rhinelander9866a0f2017-07-26 13:52:53 -0400225 pytest.gc_collect()
Jason Rhinelandera03408c2017-07-23 00:32:58 -0400226 assert capture == (
227 "C delete " + sz_noalias + "\n" +
228 "C delete " + sz_alias + "\n"
229 )
Dean Moldovan234f7c32017-08-17 17:03:46 +0200230
231
232def test_bind_protected_functions():
233 """Expose protected member functions to Python using a helper class"""
234 a = m.ProtectedA()
235 assert a.foo() == 42
236
237 b = m.ProtectedB()
238 assert b.foo() == 42
239
240 class C(m.ProtectedB):
241 def __init__(self):
242 m.ProtectedB.__init__(self)
243
244 def foo(self):
245 return 0
246
247 c = C()
248 assert c.foo() == 0
Wenzel Jakob4336a7d2017-08-21 22:48:28 +0200249
250
251def test_brace_initialization():
252 """ Tests that simple POD classes can be constructed using C++11 brace initialization """
253 a = m.BraceInitialization(123, "test")
254 assert a.field1 == 123
255 assert a.field2 == "test"
Wenzel Jakobc14c2762017-08-25 16:02:18 +0200256
Jason Rhinelanderadbc8112018-01-11 13:22:13 -0400257 # Tests that a non-simple class doesn't get brace initialization (if the
258 # class defines an initializer_list constructor, in particular, it would
259 # win over the expected constructor).
260 b = m.NoBraceInitialization([123, 456])
261 assert b.vec == [123, 456]
262
Wenzel Jakobc14c2762017-08-25 16:02:18 +0200263
264@pytest.unsupported_on_pypy
265def test_class_refcount():
266 """Instances must correctly increase/decrease the reference count of their types (#1029)"""
267 from sys import getrefcount
268
269 class PyDog(m.Dog):
270 pass
271
272 for cls in m.Dog, PyDog:
273 refcount_1 = getrefcount(cls)
274 molly = [cls("Molly") for _ in range(10)]
275 refcount_2 = getrefcount(cls)
276
277 del molly
278 pytest.gc_collect()
279 refcount_3 = getrefcount(cls)
280
281 assert refcount_1 == refcount_3
282 assert refcount_2 > refcount_1
Wenzel Jakob8ed5b8a2017-08-28 16:34:06 +0200283
284
285def test_reentrant_implicit_conversion_failure(msg):
286 # ensure that there is no runaway reentrant implicit conversion (#1035)
287 with pytest.raises(TypeError) as excinfo:
288 m.BogusImplicitConversion(0)
Jason Rhinelander71178922017-11-07 12:33:05 -0400289 assert msg(excinfo.value) == '''
290 __init__(): incompatible constructor arguments. The following argument types are supported:
291 1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
Wenzel Jakob8ed5b8a2017-08-28 16:34:06 +0200292
Jason Rhinelander71178922017-11-07 12:33:05 -0400293 Invoked with: 0
294 '''
oremanje7761e32018-09-25 14:55:18 -0700295
296
297def test_error_after_conversions():
298 with pytest.raises(TypeError) as exc_info:
299 m.test_error_after_conversions("hello")
300 assert str(exc_info.value).startswith(
301 "Unable to convert function return value to a Python type!")
Wenzel Jakobe2eca4f2018-11-09 20:14:53 +0100302
303
304def test_aligned():
305 if hasattr(m, "Aligned"):
306 p = m.Aligned().ptr()
307 assert p % 1024 == 0
Dustin Spicuzza0dfffcf2020-04-05 02:34:00 -0400308
309
310# https://bitbucket.org/pypy/pypy/issues/2742
311@pytest.unsupported_on_pypy
312def test_final():
313 with pytest.raises(TypeError) as exc_info:
314 class PyFinalChild(m.IsFinal):
315 pass
316 assert str(exc_info.value).endswith("is not an acceptable base type")
317
318
319# https://bitbucket.org/pypy/pypy/issues/2742
320@pytest.unsupported_on_pypy
321def test_non_final_final():
322 with pytest.raises(TypeError) as exc_info:
323 class PyNonFinalFinalChild(m.IsNonFinalFinal):
324 pass
325 assert str(exc_info.value).endswith("is not an acceptable base type")