Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:17:54

0001 import sys
0002 
0003 import pytest
0004 
0005 import env  # noqa: F401
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  # unused var
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  # noqa: F841 unused var
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  # unused var
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     # Static property read and write via instance
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  # noqa: F841 unused var
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     # It should be possible to override properties in derived classes
0181     assert m.TestPropertiesOverride().def_readonly == 99
0182     assert m.TestPropertiesOverride.def_readonly_static == 99
0183 
0184     # Only static attributes can be deleted
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     # Regular `type` replaces the property instead of calling `__set__()`
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  # restore original value for static properties
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 # https://foss.heptapod.net/pypy/pypy/-/issues/2447
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     # Dynamically add attribute
0301     instance.foo = 42
0302     assert hasattr(instance, "foo")
0303     assert instance.foo == 42
0304     assert "foo" in dir(instance)
0305 
0306     # __dict__ should be accessible and replaceable
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     # Derived classes should work as well
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 # https://foss.heptapod.net/pypy/pypy/-/issues/2447
0336 @pytest.mark.xfail("env.PYPY")
0337 def test_cyclic_gc():
0338     # One object references itself
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     # Two object reference each other
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     # The first one still raises because you can't pass None as a lvalue reference arg:
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     # The rest take the argument as pointer or holder, and accept None:
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