File: test_cpp_conduit.py

package info (click to toggle)
pybind11 3.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,448 kB
  • sloc: cpp: 27,239; python: 13,512; ansic: 4,244; makefile: 204; sh: 36
file content (183 lines) | stat: -rw-r--r-- 6,154 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# Copyright (c) 2024 The pybind Community.

from __future__ import annotations

import importlib
import sys

import pytest

import env
from pybind11_tests import cpp_conduit as home_planet


def import_warns_freethreaded(name):
    if name not in sys.modules and not getattr(sys, "_is_gil_enabled", lambda: True)():
        with pytest.warns(
            RuntimeWarning, match=f"has been enabled to load module '{name}'"
        ):
            return importlib.import_module(name)

    return importlib.import_module(name)


exo_planet_c_api = import_warns_freethreaded("exo_planet_c_api")
exo_planet_pybind11 = import_warns_freethreaded("exo_planet_pybind11")
home_planet_very_lonely_traveler = import_warns_freethreaded(
    "home_planet_very_lonely_traveler"
)


def test_traveler_getattr_actually_exists():
    t_h = home_planet.Traveler("home")
    assert t_h.any_name == "Traveler GetAttr: any_name luggage: home"


def test_premium_traveler_getattr_actually_exists():
    t_h = home_planet.PremiumTraveler("home", 7)
    assert t_h.secret_name == "PremiumTraveler GetAttr: secret_name points: 7"


def test_call_cpp_conduit_success():
    t_h = home_planet.Traveler("home")
    cap = t_h._pybind11_conduit_v1_(
        home_planet.PYBIND11_PLATFORM_ABI_ID,
        home_planet.cpp_type_info_capsule_Traveler,
        b"raw_pointer_ephemeral",
    )
    assert cap.__class__.__name__ == "PyCapsule" or (
        # Note: this will become unnecessary in the next GraalPy release
        env.GRAALPY and cap.__class__.__name__ == "capsule"
    )


def test_call_cpp_conduit_platform_abi_id_mismatch():
    t_h = home_planet.Traveler("home")
    cap = t_h._pybind11_conduit_v1_(
        home_planet.PYBIND11_PLATFORM_ABI_ID + b"MISMATCH",
        home_planet.cpp_type_info_capsule_Traveler,
        b"raw_pointer_ephemeral",
    )
    assert cap is None


def test_call_cpp_conduit_cpp_type_info_capsule_mismatch():
    t_h = home_planet.Traveler("home")
    cap = t_h._pybind11_conduit_v1_(
        home_planet.PYBIND11_PLATFORM_ABI_ID,
        home_planet.cpp_type_info_capsule_int,
        b"raw_pointer_ephemeral",
    )
    assert cap is None


def test_call_cpp_conduit_pointer_kind_invalid():
    t_h = home_planet.Traveler("home")
    with pytest.raises(
        RuntimeError, match='^Invalid pointer_kind: "raw_pointer_ephemreal"$'
    ):
        t_h._pybind11_conduit_v1_(
            home_planet.PYBIND11_PLATFORM_ABI_ID,
            home_planet.cpp_type_info_capsule_Traveler,
            b"raw_pointer_ephemreal",
        )


def test_home_only_basic():
    t_h = home_planet.Traveler("home")
    assert t_h.luggage == "home"
    assert home_planet.get_luggage(t_h) == "home"


def test_home_only_premium():
    p_h = home_planet.PremiumTraveler("home", 2)
    assert p_h.luggage == "home"
    assert home_planet.get_luggage(p_h) == "home"
    assert home_planet.get_points(p_h) == 2


def test_exo_only_basic():
    t_e = exo_planet_pybind11.Traveler("exo")
    assert t_e.luggage == "exo"
    assert exo_planet_pybind11.get_luggage(t_e) == "exo"


def test_exo_only_premium():
    p_e = exo_planet_pybind11.PremiumTraveler("exo", 3)
    assert p_e.luggage == "exo"
    assert exo_planet_pybind11.get_luggage(p_e) == "exo"
    assert exo_planet_pybind11.get_points(p_e) == 3


def test_home_passed_to_exo_basic():
    t_h = home_planet.Traveler("home")
    assert exo_planet_pybind11.get_luggage(t_h) == "home"


def test_exo_passed_to_home_basic():
    t_e = exo_planet_pybind11.Traveler("exo")
    assert home_planet.get_luggage(t_e) == "exo"


def test_home_passed_to_exo_premium():
    p_h = home_planet.PremiumTraveler("home", 2)
    assert exo_planet_pybind11.get_luggage(p_h) == "home"
    assert exo_planet_pybind11.get_points(p_h) == 2


def test_exo_passed_to_home_premium():
    p_e = exo_planet_pybind11.PremiumTraveler("exo", 3)
    assert home_planet.get_luggage(p_e) == "exo"
    assert home_planet.get_points(p_e) == 3


@pytest.mark.parametrize(
    "traveler_type", [home_planet.Traveler, exo_planet_pybind11.Traveler]
)
def test_exo_planet_c_api_traveler(traveler_type):
    t = traveler_type("socks")
    assert exo_planet_c_api.GetLuggage(t) == "socks"


@pytest.mark.parametrize(
    "premium_traveler_type",
    [home_planet.PremiumTraveler, exo_planet_pybind11.PremiumTraveler],
)
def test_exo_planet_c_api_premium_traveler(premium_traveler_type):
    pt = premium_traveler_type("gucci", 5)
    assert exo_planet_c_api.GetLuggage(pt) == "gucci"
    assert exo_planet_c_api.GetPoints(pt) == 5


def test_home_planet_wrap_very_lonely_traveler():
    # This does not exercise the cpp_conduit feature, but is here to
    # demonstrate that the cpp_conduit feature does not solve
    # cross-extension base-and-derived class interoperability issues.
    # Here is the proof that the following works for extensions with
    # matching `PYBIND11_INTERNALS_ID`s:
    #     test_cpp_conduit.cpp:
    #         py::class_<LonelyTraveler>
    #     home_planet_very_lonely_traveler.cpp:
    #         py::class_<VeryLonelyTraveler, LonelyTraveler>
    # See test_exo_planet_pybind11_wrap_very_lonely_traveler() for the negative
    # test.
    assert home_planet.LonelyTraveler is not None  # Verify that the base class exists.
    home_planet_very_lonely_traveler.wrap_very_lonely_traveler()
    # Ensure that the derived class exists.
    assert home_planet_very_lonely_traveler.VeryLonelyTraveler is not None


def test_exo_planet_pybind11_wrap_very_lonely_traveler():
    # See comment under test_home_planet_wrap_very_lonely_traveler() first.
    # Here the `PYBIND11_INTERNALS_ID`s don't match between:
    #     test_cpp_conduit.cpp:
    #         py::class_<LonelyTraveler>
    #     exo_planet_pybind11.cpp:
    #         py::class_<VeryLonelyTraveler, LonelyTraveler>
    assert home_planet.LonelyTraveler is not None  # Verify that the base class exists.
    with pytest.raises(
        RuntimeError,
        match='^generic_type: type "VeryLonelyTraveler" referenced unknown base type '
        '"pybind11_tests::test_cpp_conduit::LonelyTraveler"$',
    ):
        exo_planet_pybind11.wrap_very_lonely_traveler()