File indexing completed on 2025-01-18 10:17:54
0001 import sys
0002
0003 import pytest
0004
0005 import env
0006 from pybind11_tests import ConstructorStats
0007 from pybind11_tests import methods_and_attributes as m
0008
0009 NO_GETTER_MSG = (
0010 "unreadable attribute" if sys.version_info < (3, 11) else "object has no getter"
0011 )
0012 NO_SETTER_MSG = (
0013 "can't set attribute" if sys.version_info < (3, 11) else "object has no setter"
0014 )
0015 NO_DELETER_MSG = (
0016 "can't delete attribute" if sys.version_info < (3, 11) else "object has no deleter"
0017 )
0018
0019
0020 def test_methods_and_attributes():
0021 instance1 = m.ExampleMandA()
0022 instance2 = m.ExampleMandA(32)
0023
0024 instance1.add1(instance2)
0025 instance1.add2(instance2)
0026 instance1.add3(instance2)
0027 instance1.add4(instance2)
0028 instance1.add5(instance2)
0029 instance1.add6(32)
0030 instance1.add7(32)
0031 instance1.add8(32)
0032 instance1.add9(32)
0033 instance1.add10(32)
0034
0035 assert str(instance1) == "ExampleMandA[value=320]"
0036 assert str(instance2) == "ExampleMandA[value=32]"
0037 assert str(instance1.self1()) == "ExampleMandA[value=320]"
0038 assert str(instance1.self2()) == "ExampleMandA[value=320]"
0039 assert str(instance1.self3()) == "ExampleMandA[value=320]"
0040 assert str(instance1.self4()) == "ExampleMandA[value=320]"
0041 assert str(instance1.self5()) == "ExampleMandA[value=320]"
0042
0043 assert instance1.internal1() == 320
0044 assert instance1.internal2() == 320
0045 assert instance1.internal3() == 320
0046 assert instance1.internal4() == 320
0047 assert instance1.internal5() == 320
0048
0049 assert instance1.overloaded() == "()"
0050 assert instance1.overloaded(0) == "(int)"
0051 assert instance1.overloaded(1, 1.0) == "(int, float)"
0052 assert instance1.overloaded(2.0, 2) == "(float, int)"
0053 assert instance1.overloaded(3, 3) == "(int, int)"
0054 assert instance1.overloaded(4.0, 4.0) == "(float, float)"
0055 assert instance1.overloaded_const(-3) == "(int) const"
0056 assert instance1.overloaded_const(5, 5.0) == "(int, float) const"
0057 assert instance1.overloaded_const(6.0, 6) == "(float, int) const"
0058 assert instance1.overloaded_const(7, 7) == "(int, int) const"
0059 assert instance1.overloaded_const(8.0, 8.0) == "(float, float) const"
0060 assert instance1.overloaded_float(1, 1) == "(float, float)"
0061 assert instance1.overloaded_float(1, 1.0) == "(float, float)"
0062 assert instance1.overloaded_float(1.0, 1) == "(float, float)"
0063 assert instance1.overloaded_float(1.0, 1.0) == "(float, float)"
0064
0065 assert instance1.value == 320
0066 instance1.value = 100
0067 assert str(instance1) == "ExampleMandA[value=100]"
0068
0069 cstats = ConstructorStats.get(m.ExampleMandA)
0070 assert cstats.alive() == 2
0071 del instance1, instance2
0072 assert cstats.alive() == 0
0073 assert cstats.values() == ["32"]
0074 assert cstats.default_constructions == 1
0075 assert cstats.copy_constructions == 2
0076 assert cstats.move_constructions >= 2
0077 assert cstats.copy_assignments == 0
0078 assert cstats.move_assignments == 0
0079
0080
0081 def test_copy_method():
0082 """Issue #443: calling copied methods fails in Python 3"""
0083
0084 m.ExampleMandA.add2c = m.ExampleMandA.add2
0085 m.ExampleMandA.add2d = m.ExampleMandA.add2b
0086 a = m.ExampleMandA(123)
0087 assert a.value == 123
0088 a.add2(m.ExampleMandA(-100))
0089 assert a.value == 23
0090 a.add2b(m.ExampleMandA(20))
0091 assert a.value == 43
0092 a.add2c(m.ExampleMandA(6))
0093 assert a.value == 49
0094 a.add2d(m.ExampleMandA(-7))
0095 assert a.value == 42
0096
0097
0098 def test_properties():
0099 instance = m.TestProperties()
0100
0101 assert instance.def_readonly == 1
0102 with pytest.raises(AttributeError):
0103 instance.def_readonly = 2
0104
0105 instance.def_readwrite = 2
0106 assert instance.def_readwrite == 2
0107
0108 assert instance.def_property_readonly == 2
0109 with pytest.raises(AttributeError):
0110 instance.def_property_readonly = 3
0111
0112 instance.def_property = 3
0113 assert instance.def_property == 3
0114
0115 with pytest.raises(AttributeError) as excinfo:
0116 dummy = instance.def_property_writeonly
0117 assert NO_GETTER_MSG in str(excinfo.value)
0118
0119 instance.def_property_writeonly = 4
0120 assert instance.def_property_readonly == 4
0121
0122 with pytest.raises(AttributeError) as excinfo:
0123 dummy = instance.def_property_impossible
0124 assert NO_GETTER_MSG in str(excinfo.value)
0125
0126 with pytest.raises(AttributeError) as excinfo:
0127 instance.def_property_impossible = 5
0128 assert NO_SETTER_MSG in str(excinfo.value)
0129
0130
0131 def test_static_properties():
0132 assert m.TestProperties.def_readonly_static == 1
0133 with pytest.raises(AttributeError) as excinfo:
0134 m.TestProperties.def_readonly_static = 2
0135 assert NO_SETTER_MSG in str(excinfo.value)
0136
0137 m.TestProperties.def_readwrite_static = 2
0138 assert m.TestProperties.def_readwrite_static == 2
0139
0140 with pytest.raises(AttributeError) as excinfo:
0141 dummy = m.TestProperties.def_writeonly_static
0142 assert NO_GETTER_MSG in str(excinfo.value)
0143
0144 m.TestProperties.def_writeonly_static = 3
0145 assert m.TestProperties.def_readonly_static == 3
0146
0147 assert m.TestProperties.def_property_readonly_static == 3
0148 with pytest.raises(AttributeError) as excinfo:
0149 m.TestProperties.def_property_readonly_static = 99
0150 assert NO_SETTER_MSG in str(excinfo.value)
0151
0152 m.TestProperties.def_property_static = 4
0153 assert m.TestProperties.def_property_static == 4
0154
0155 with pytest.raises(AttributeError) as excinfo:
0156 dummy = m.TestProperties.def_property_writeonly_static
0157 assert NO_GETTER_MSG in str(excinfo.value)
0158
0159 m.TestProperties.def_property_writeonly_static = 5
0160 assert m.TestProperties.def_property_static == 5
0161
0162
0163 instance = m.TestProperties()
0164
0165 m.TestProperties.def_readwrite_static = 0
0166 assert m.TestProperties.def_readwrite_static == 0
0167 assert instance.def_readwrite_static == 0
0168
0169 instance.def_readwrite_static = 2
0170 assert m.TestProperties.def_readwrite_static == 2
0171 assert instance.def_readwrite_static == 2
0172
0173 with pytest.raises(AttributeError) as excinfo:
0174 dummy = instance.def_property_writeonly_static
0175 assert NO_GETTER_MSG in str(excinfo.value)
0176
0177 instance.def_property_writeonly_static = 4
0178 assert instance.def_property_static == 4
0179
0180
0181 assert m.TestPropertiesOverride().def_readonly == 99
0182 assert m.TestPropertiesOverride.def_readonly_static == 99
0183
0184
0185 del m.TestPropertiesOverride.def_readonly_static
0186 assert (
0187 hasattr(m.TestPropertiesOverride, "def_readonly_static")
0188 and m.TestPropertiesOverride.def_readonly_static
0189 is m.TestProperties.def_readonly_static
0190 )
0191 assert "def_readonly_static" not in m.TestPropertiesOverride.__dict__
0192 properties_override = m.TestPropertiesOverride()
0193 with pytest.raises(AttributeError) as excinfo:
0194 del properties_override.def_readonly
0195 assert NO_DELETER_MSG in str(excinfo.value)
0196
0197
0198 def test_static_cls():
0199 """Static property getter and setters expect the type object as the their only argument"""
0200
0201 instance = m.TestProperties()
0202 assert m.TestProperties.static_cls is m.TestProperties
0203 assert instance.static_cls is m.TestProperties
0204
0205 def check_self(self):
0206 assert self is m.TestProperties
0207
0208 m.TestProperties.static_cls = check_self
0209 instance.static_cls = check_self
0210
0211
0212 def test_metaclass_override():
0213 """Overriding pybind11's default metaclass changes the behavior of `static_property`"""
0214
0215 assert type(m.ExampleMandA).__name__ == "pybind11_type"
0216 assert type(m.MetaclassOverride).__name__ == "type"
0217
0218 assert m.MetaclassOverride.readonly == 1
0219 assert (
0220 type(m.MetaclassOverride.__dict__["readonly"]).__name__
0221 == "pybind11_static_property"
0222 )
0223
0224
0225 m.MetaclassOverride.readonly = 2
0226 assert m.MetaclassOverride.readonly == 2
0227 assert isinstance(m.MetaclassOverride.__dict__["readonly"], int)
0228
0229
0230 def test_no_mixed_overloads():
0231 from pybind11_tests import detailed_error_messages_enabled
0232
0233 with pytest.raises(RuntimeError) as excinfo:
0234 m.ExampleMandA.add_mixed_overloads1()
0235 assert str(
0236 excinfo.value
0237 ) == "overloading a method with both static and instance methods is not supported; " + (
0238 "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more details"
0239 if not detailed_error_messages_enabled
0240 else "error while attempting to bind static method ExampleMandA.overload_mixed1"
0241 "(arg0: float) -> str"
0242 )
0243
0244 with pytest.raises(RuntimeError) as excinfo:
0245 m.ExampleMandA.add_mixed_overloads2()
0246 assert str(
0247 excinfo.value
0248 ) == "overloading a method with both static and instance methods is not supported; " + (
0249 "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more details"
0250 if not detailed_error_messages_enabled
0251 else "error while attempting to bind instance method ExampleMandA.overload_mixed2"
0252 "(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)"
0253 " -> str"
0254 )
0255
0256
0257 @pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
0258 def test_property_return_value_policies(access):
0259 if not access.startswith("static"):
0260 obj = m.TestPropRVP()
0261 else:
0262 obj = m.TestPropRVP
0263
0264 ref = getattr(obj, access + "_ref")
0265 assert ref.value == 1
0266 ref.value = 2
0267 assert getattr(obj, access + "_ref").value == 2
0268 ref.value = 1
0269
0270 copy = getattr(obj, access + "_copy")
0271 assert copy.value == 1
0272 copy.value = 2
0273 assert getattr(obj, access + "_copy").value == 1
0274
0275 copy = getattr(obj, access + "_func")
0276 assert copy.value == 1
0277 copy.value = 2
0278 assert getattr(obj, access + "_func").value == 1
0279
0280
0281 def test_property_rvalue_policy():
0282 """When returning an rvalue, the return value policy is automatically changed from
0283 `reference(_internal)` to `move`. The following would not work otherwise."""
0284
0285 instance = m.TestPropRVP()
0286 o = instance.rvalue
0287 assert o.value == 1
0288
0289 os = m.TestPropRVP.static_rvalue
0290 assert os.value == 1
0291
0292
0293
0294 @pytest.mark.xfail("env.PYPY")
0295 def test_dynamic_attributes():
0296 instance = m.DynamicClass()
0297 assert not hasattr(instance, "foo")
0298 assert "foo" not in dir(instance)
0299
0300
0301 instance.foo = 42
0302 assert hasattr(instance, "foo")
0303 assert instance.foo == 42
0304 assert "foo" in dir(instance)
0305
0306
0307 assert "foo" in instance.__dict__
0308 instance.__dict__ = {"bar": True}
0309 assert not hasattr(instance, "foo")
0310 assert hasattr(instance, "bar")
0311
0312 with pytest.raises(TypeError) as excinfo:
0313 instance.__dict__ = []
0314 assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'"
0315
0316 cstats = ConstructorStats.get(m.DynamicClass)
0317 assert cstats.alive() == 1
0318 del instance
0319 assert cstats.alive() == 0
0320
0321
0322 class PythonDerivedDynamicClass(m.DynamicClass):
0323 pass
0324
0325 for cls in m.CppDerivedDynamicClass, PythonDerivedDynamicClass:
0326 derived = cls()
0327 derived.foobar = 100
0328 assert derived.foobar == 100
0329
0330 assert cstats.alive() == 1
0331 del derived
0332 assert cstats.alive() == 0
0333
0334
0335
0336 @pytest.mark.xfail("env.PYPY")
0337 def test_cyclic_gc():
0338
0339 instance = m.DynamicClass()
0340 instance.circular_reference = instance
0341
0342 cstats = ConstructorStats.get(m.DynamicClass)
0343 assert cstats.alive() == 1
0344 del instance
0345 assert cstats.alive() == 0
0346
0347
0348 i1 = m.DynamicClass()
0349 i2 = m.DynamicClass()
0350 i1.cycle = i2
0351 i2.cycle = i1
0352
0353 assert cstats.alive() == 2
0354 del i1, i2
0355 assert cstats.alive() == 0
0356
0357
0358 def test_bad_arg_default(msg):
0359 from pybind11_tests import detailed_error_messages_enabled
0360
0361 with pytest.raises(RuntimeError) as excinfo:
0362 m.bad_arg_def_named()
0363 assert msg(excinfo.value) == (
0364 "arg(): could not convert default argument 'a: UnregisteredType' in function "
0365 "'should_fail' into a Python object (type not registered yet?)"
0366 if detailed_error_messages_enabled
0367 else "arg(): could not convert default argument into a Python object (type not registered "
0368 "yet?). #define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more information."
0369 )
0370
0371 with pytest.raises(RuntimeError) as excinfo:
0372 m.bad_arg_def_unnamed()
0373 assert msg(excinfo.value) == (
0374 "arg(): could not convert default argument 'UnregisteredType' in function "
0375 "'should_fail' into a Python object (type not registered yet?)"
0376 if detailed_error_messages_enabled
0377 else "arg(): could not convert default argument into a Python object (type not registered "
0378 "yet?). #define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more information."
0379 )
0380
0381
0382 def test_accepts_none(msg):
0383 a = m.NoneTester()
0384 assert m.no_none1(a) == 42
0385 assert m.no_none2(a) == 42
0386 assert m.no_none3(a) == 42
0387 assert m.no_none4(a) == 42
0388 assert m.no_none5(a) == 42
0389 assert m.ok_none1(a) == 42
0390 assert m.ok_none2(a) == 42
0391 assert m.ok_none3(a) == 42
0392 assert m.ok_none4(a) == 42
0393 assert m.ok_none5(a) == 42
0394
0395 with pytest.raises(TypeError) as excinfo:
0396 m.no_none1(None)
0397 assert "incompatible function arguments" in str(excinfo.value)
0398 with pytest.raises(TypeError) as excinfo:
0399 m.no_none2(None)
0400 assert "incompatible function arguments" in str(excinfo.value)
0401 with pytest.raises(TypeError) as excinfo:
0402 m.no_none3(None)
0403 assert "incompatible function arguments" in str(excinfo.value)
0404 with pytest.raises(TypeError) as excinfo:
0405 m.no_none4(None)
0406 assert "incompatible function arguments" in str(excinfo.value)
0407 with pytest.raises(TypeError) as excinfo:
0408 m.no_none5(None)
0409 assert "incompatible function arguments" in str(excinfo.value)
0410
0411
0412 with pytest.raises(TypeError) as excinfo:
0413 assert m.ok_none1(None) == -1
0414 assert (
0415 msg(excinfo.value)
0416 == """
0417 ok_none1(): incompatible function arguments. The following argument types are supported:
0418 1. (arg0: m.methods_and_attributes.NoneTester) -> int
0419
0420 Invoked with: None
0421 """
0422 )
0423
0424
0425 assert m.ok_none2(None) == -1
0426 assert m.ok_none3(None) == -1
0427 assert m.ok_none4(None) == -1
0428 assert m.ok_none5(None) == -1
0429
0430 with pytest.raises(TypeError) as excinfo:
0431 m.no_none_kwarg(None)
0432 assert "incompatible function arguments" in str(excinfo.value)
0433 with pytest.raises(TypeError) as excinfo:
0434 m.no_none_kwarg(a=None)
0435 assert "incompatible function arguments" in str(excinfo.value)
0436 with pytest.raises(TypeError) as excinfo:
0437 m.no_none_kwarg_kw_only(None)
0438 assert "incompatible function arguments" in str(excinfo.value)
0439 with pytest.raises(TypeError) as excinfo:
0440 m.no_none_kwarg_kw_only(a=None)
0441 assert "incompatible function arguments" in str(excinfo.value)
0442
0443
0444 def test_casts_none():
0445 """#2778: implicit casting from None to object (not pointer)"""
0446 a = m.NoneCastTester()
0447 assert m.ok_obj_or_none(a) == -1
0448 a = m.NoneCastTester(4)
0449 assert m.ok_obj_or_none(a) == 4
0450 a = m.NoneCastTester(None)
0451 assert m.ok_obj_or_none(a) == -1
0452 assert m.ok_obj_or_none(None) == -1
0453
0454
0455 def test_str_issue(msg):
0456 """#283: __str__ called on uninitialized instance when constructor arguments invalid"""
0457
0458 assert str(m.StrIssue(3)) == "StrIssue[3]"
0459
0460 with pytest.raises(TypeError) as excinfo:
0461 str(m.StrIssue("no", "such", "constructor"))
0462 assert (
0463 msg(excinfo.value)
0464 == """
0465 __init__(): incompatible constructor arguments. The following argument types are supported:
0466 1. m.methods_and_attributes.StrIssue(arg0: int)
0467 2. m.methods_and_attributes.StrIssue()
0468
0469 Invoked with: 'no', 'such', 'constructor'
0470 """
0471 )
0472
0473
0474 def test_unregistered_base_implementations():
0475 a = m.RegisteredDerived()
0476 a.do_nothing()
0477 assert a.rw_value == 42
0478 assert a.ro_value == 1.25
0479 a.rw_value += 5
0480 assert a.sum() == 48.25
0481 a.increase_value()
0482 assert a.rw_value == 48
0483 assert a.ro_value == 1.5
0484 assert a.sum() == 49.5
0485 assert a.rw_value_prop == 48
0486 a.rw_value_prop += 1
0487 assert a.rw_value_prop == 49
0488 a.increase_value()
0489 assert a.ro_value_prop == 1.75
0490
0491
0492 def test_ref_qualified():
0493 """Tests that explicit lvalue ref-qualified methods can be called just like their
0494 non ref-qualified counterparts."""
0495
0496 r = m.RefQualified()
0497 assert r.value == 0
0498 r.refQualified(17)
0499 assert r.value == 17
0500 assert r.constRefQualified(23) == 40
0501
0502
0503 def test_overload_ordering():
0504 "Check to see if the normal overload order (first defined) and prepend overload order works"
0505 assert m.overload_order("string") == 1
0506 assert m.overload_order(0) == 4
0507
0508 assert "1. overload_order(arg0: int) -> int" in m.overload_order.__doc__
0509 assert "2. overload_order(arg0: str) -> int" in m.overload_order.__doc__
0510 assert "3. overload_order(arg0: str) -> int" in m.overload_order.__doc__
0511 assert "4. overload_order(arg0: int) -> int" in m.overload_order.__doc__
0512
0513 with pytest.raises(TypeError) as err:
0514 m.overload_order(1.1)
0515
0516 assert "1. (arg0: int) -> int" in str(err.value)
0517 assert "2. (arg0: str) -> int" in str(err.value)
0518 assert "3. (arg0: str) -> int" in str(err.value)
0519 assert "4. (arg0: int) -> int" in str(err.value)
0520
0521
0522 def test_rvalue_ref_param():
0523 r = m.RValueRefParam()
0524 assert r.func1("123") == 3
0525 assert r.func2("1234") == 4
0526 assert r.func3("12345") == 5
0527 assert r.func4("123456") == 6