File indexing completed on 2025-01-18 10:17:54
0001 import pytest
0002
0003 import env
0004 from pybind11_tests import local_bindings as m
0005
0006
0007 def test_load_external():
0008 """Load a `py::module_local` type that's only registered in an external module"""
0009 import pybind11_cross_module_tests as cm
0010
0011 assert m.load_external1(cm.ExternalType1(11)) == 11
0012 assert m.load_external2(cm.ExternalType2(22)) == 22
0013
0014 with pytest.raises(TypeError) as excinfo:
0015 assert m.load_external2(cm.ExternalType1(21)) == 21
0016 assert "incompatible function arguments" in str(excinfo.value)
0017
0018 with pytest.raises(TypeError) as excinfo:
0019 assert m.load_external1(cm.ExternalType2(12)) == 12
0020 assert "incompatible function arguments" in str(excinfo.value)
0021
0022
0023 def test_local_bindings():
0024 """Tests that duplicate `py::module_local` class bindings work across modules"""
0025
0026
0027 import pybind11_cross_module_tests as cm
0028
0029 i1 = m.LocalType(5)
0030 assert i1.get() == 4
0031 assert i1.get3() == 8
0032
0033 i2 = cm.LocalType(10)
0034 assert i2.get() == 11
0035 assert i2.get2() == 12
0036
0037 assert not hasattr(i1, "get2")
0038 assert not hasattr(i2, "get3")
0039
0040
0041 assert m.local_value(i1) == 5
0042 assert cm.local_value(i2) == 10
0043
0044
0045
0046 assert m.local_value(i2) == 10
0047 assert cm.local_value(i1) == 5
0048
0049
0050 def test_nonlocal_failure():
0051 """Tests that attempting to register a non-local type in multiple modules fails"""
0052 import pybind11_cross_module_tests as cm
0053
0054 with pytest.raises(RuntimeError) as excinfo:
0055 cm.register_nonlocal()
0056 assert (
0057 str(excinfo.value) == 'generic_type: type "NonLocalType" is already registered!'
0058 )
0059
0060
0061 def test_duplicate_local():
0062 """Tests expected failure when registering a class twice with py::local in the same module"""
0063 with pytest.raises(RuntimeError) as excinfo:
0064 m.register_local_external()
0065 import pybind11_tests
0066
0067 assert str(excinfo.value) == (
0068 'generic_type: type "LocalExternal" is already registered!'
0069 if hasattr(pybind11_tests, "class_")
0070 else "test_class not enabled"
0071 )
0072
0073
0074 def test_stl_bind_local():
0075 import pybind11_cross_module_tests as cm
0076
0077 v1, v2 = m.LocalVec(), cm.LocalVec()
0078 v1.append(m.LocalType(1))
0079 v1.append(m.LocalType(2))
0080 v2.append(cm.LocalType(1))
0081 v2.append(cm.LocalType(2))
0082
0083
0084 v1.append(cm.LocalType(3))
0085 v2.append(m.LocalType(3))
0086
0087 assert [i.get() for i in v1] == [0, 1, 2]
0088 assert [i.get() for i in v2] == [2, 3, 4]
0089
0090 v3, v4 = m.NonLocalVec(), cm.NonLocalVec2()
0091 v3.append(m.NonLocalType(1))
0092 v3.append(m.NonLocalType(2))
0093 v4.append(m.NonLocal2(3))
0094 v4.append(m.NonLocal2(4))
0095
0096 assert [i.get() for i in v3] == [1, 2]
0097 assert [i.get() for i in v4] == [13, 14]
0098
0099 d1, d2 = m.LocalMap(), cm.LocalMap()
0100 d1["a"] = v1[0]
0101 d1["b"] = v1[1]
0102 d2["c"] = v2[0]
0103 d2["d"] = v2[1]
0104 assert {i: d1[i].get() for i in d1} == {"a": 0, "b": 1}
0105 assert {i: d2[i].get() for i in d2} == {"c": 2, "d": 3}
0106
0107
0108 def test_stl_bind_global():
0109 import pybind11_cross_module_tests as cm
0110
0111 with pytest.raises(RuntimeError) as excinfo:
0112 cm.register_nonlocal_map()
0113 assert (
0114 str(excinfo.value) == 'generic_type: type "NonLocalMap" is already registered!'
0115 )
0116
0117 with pytest.raises(RuntimeError) as excinfo:
0118 cm.register_nonlocal_vec()
0119 assert (
0120 str(excinfo.value) == 'generic_type: type "NonLocalVec" is already registered!'
0121 )
0122
0123 with pytest.raises(RuntimeError) as excinfo:
0124 cm.register_nonlocal_map2()
0125 assert (
0126 str(excinfo.value) == 'generic_type: type "NonLocalMap2" is already registered!'
0127 )
0128
0129
0130 def test_mixed_local_global():
0131 """Local types take precedence over globally registered types: a module with a `module_local`
0132 type can be registered even if the type is already registered globally. With the module,
0133 casting will go to the local type; outside the module casting goes to the global type."""
0134 import pybind11_cross_module_tests as cm
0135
0136 m.register_mixed_global()
0137 m.register_mixed_local()
0138
0139 a = []
0140 a.append(m.MixedGlobalLocal(1))
0141 a.append(m.MixedLocalGlobal(2))
0142 a.append(m.get_mixed_gl(3))
0143 a.append(m.get_mixed_lg(4))
0144
0145 assert [x.get() for x in a] == [101, 1002, 103, 1004]
0146
0147 cm.register_mixed_global_local()
0148 cm.register_mixed_local_global()
0149 a.append(m.MixedGlobalLocal(5))
0150 a.append(m.MixedLocalGlobal(6))
0151 a.append(cm.MixedGlobalLocal(7))
0152 a.append(cm.MixedLocalGlobal(8))
0153 a.append(m.get_mixed_gl(9))
0154 a.append(m.get_mixed_lg(10))
0155 a.append(cm.get_mixed_gl(11))
0156 a.append(cm.get_mixed_lg(12))
0157
0158 assert [x.get() for x in a] == [
0159 101,
0160 1002,
0161 103,
0162 1004,
0163 105,
0164 1006,
0165 207,
0166 2008,
0167 109,
0168 1010,
0169 211,
0170 2012,
0171 ]
0172
0173
0174 def test_internal_locals_differ():
0175 """Makes sure the internal local type map differs across the two modules"""
0176 import pybind11_cross_module_tests as cm
0177
0178 assert m.local_cpp_types_addr() != cm.local_cpp_types_addr()
0179
0180
0181 @pytest.mark.xfail("env.PYPY and sys.pypy_version_info < (7, 3, 2)")
0182 def test_stl_caster_vs_stl_bind(msg):
0183 """One module uses a generic vector caster from `<pybind11/stl.h>` while the other
0184 exports `std::vector<int>` via `py:bind_vector` and `py::module_local`"""
0185 import pybind11_cross_module_tests as cm
0186
0187 v1 = cm.VectorInt([1, 2, 3])
0188 assert m.load_vector_via_caster(v1) == 6
0189 assert cm.load_vector_via_binding(v1) == 6
0190
0191 v2 = [1, 2, 3]
0192 assert m.load_vector_via_caster(v2) == 6
0193 with pytest.raises(TypeError) as excinfo:
0194 cm.load_vector_via_binding(v2)
0195 assert (
0196 msg(excinfo.value)
0197 == """
0198 load_vector_via_binding(): incompatible function arguments. The following argument types are supported:
0199 1. (arg0: pybind11_cross_module_tests.VectorInt) -> int
0200
0201 Invoked with: [1, 2, 3]
0202 """
0203 )
0204
0205
0206 def test_cross_module_calls():
0207 import pybind11_cross_module_tests as cm
0208
0209 v1 = m.LocalVec()
0210 v1.append(m.LocalType(1))
0211 v2 = cm.LocalVec()
0212 v2.append(cm.LocalType(2))
0213
0214
0215
0216 assert m.return_self(v1) is v1
0217 assert cm.return_self(v2) is v2
0218 assert m.return_self(v2) is v2
0219 assert cm.return_self(v1) is v1
0220
0221 assert m.LocalVec is not cm.LocalVec
0222
0223
0224 assert type(m.return_copy(v1)) is m.LocalVec
0225 assert type(m.return_copy(v2)) is m.LocalVec
0226 assert type(cm.return_copy(v1)) is cm.LocalVec
0227 assert type(cm.return_copy(v2)) is cm.LocalVec
0228
0229
0230 mycat = m.Cat("Fluffy")
0231 mydog = cm.Dog("Rover")
0232 assert mycat.get_name() == "Fluffy"
0233 assert mydog.name() == "Rover"
0234 assert m.Cat.__base__.__name__ == "Pet"
0235 assert cm.Dog.__base__.__name__ == "Pet"
0236 assert m.Cat.__base__ is not cm.Dog.__base__
0237 assert m.pet_name(mycat) == "Fluffy"
0238 assert m.pet_name(mydog) == "Rover"
0239 assert cm.pet_name(mycat) == "Fluffy"
0240 assert cm.pet_name(mydog) == "Rover"
0241
0242 assert m.MixGL is not cm.MixGL
0243 a = m.MixGL(1)
0244 b = cm.MixGL(2)
0245 assert m.get_gl_value(a) == 11
0246 assert m.get_gl_value(b) == 12
0247 assert cm.get_gl_value(a) == 101
0248 assert cm.get_gl_value(b) == 102
0249
0250 c, d = m.MixGL2(3), cm.MixGL2(4)
0251 with pytest.raises(TypeError) as excinfo:
0252 m.get_gl_value(c)
0253 assert "incompatible function arguments" in str(excinfo.value)
0254 with pytest.raises(TypeError) as excinfo:
0255 m.get_gl_value(d)
0256 assert "incompatible function arguments" in str(excinfo.value)