-
Notifications
You must be signed in to change notification settings - Fork 263
/
Copy pathconftest.py
150 lines (127 loc) · 5.22 KB
/
conftest.py
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
import json
import subprocess
from collections.abc import Generator
import pytest
from filelock import FileLock
from cibuildwheel.architecture import Architecture
from cibuildwheel.ci import detect_ci_provider
from cibuildwheel.options import CommandLineArguments, Options
from cibuildwheel.venv import find_uv
from .utils import EMULATED_ARCHS, platform
def pytest_addoption(parser: pytest.Parser) -> None:
parser.addoption(
"--run-emulation",
action="store",
default=None,
help="run emulation tests",
choices=("all", *EMULATED_ARCHS),
)
parser.addoption("--run-podman", action="store_true", default=False, help="run podman tests")
parser.addoption(
"--run-cp38-universal2",
action="store_true",
default=False,
help="macOS cp38 uses the universal2 installer",
)
def docker_warmup(request: pytest.FixtureRequest) -> None:
machine = request.config.getoption("--run-emulation", default=None)
if machine is None:
archs = {arch.value for arch in Architecture.auto_archs("linux")}
elif machine == "all":
archs = set(EMULATED_ARCHS)
else:
archs = {machine}
# Only include architectures where there are missing pre-installed interpreters
archs &= {"x86_64", "i686", "aarch64"}
if not archs:
return
options = Options(
platform="linux",
command_line_arguments=CommandLineArguments.defaults(),
env={},
defaults=True,
)
build_options = options.build_options(None)
assert build_options.manylinux_images is not None
assert build_options.musllinux_images is not None
images = [build_options.manylinux_images[arch] for arch in archs] + [
build_options.musllinux_images[arch] for arch in archs
]
# exclude GraalPy as it's not a target for cibuildwheel
command = (
"manylinux-interpreters ensure $(manylinux-interpreters list 2>/dev/null | grep -v graalpy) &&"
"cpython3.13 -m pip download -d /tmp setuptools wheel pytest"
)
for image in images:
container_id = subprocess.run(
["docker", "create", image, "bash", "-c", command],
text=True,
check=True,
stdout=subprocess.PIPE,
).stdout.strip()
try:
subprocess.run(["docker", "start", container_id], check=True, stdout=subprocess.DEVNULL)
exit_code = subprocess.run(
["docker", "wait", container_id], text=True, check=True, stdout=subprocess.PIPE
).stdout.strip()
assert exit_code == "0"
subprocess.run(
["docker", "commit", container_id, image], check=True, stdout=subprocess.DEVNULL
)
finally:
subprocess.run(["docker", "rm", container_id], check=True, stdout=subprocess.DEVNULL)
@pytest.fixture(scope="session", autouse=True)
def docker_warmup_fixture(
request: pytest.FixtureRequest, tmp_path_factory: pytest.TempPathFactory, worker_id: str
) -> None:
# if we're in CI testing linux, let's warm-up docker images
if detect_ci_provider() is None or platform != "linux":
return None
if request.config.getoption("--run-emulation", default=None) is not None:
# emulation tests only run one test in CI, caching the image only slows down the test
return None
if worker_id == "master":
# not executing with multiple workers
# it might be unsafe to write to tmp_path_factory.getbasetemp().parent
return docker_warmup(request)
# get the temp directory shared by all workers
root_tmp_dir = tmp_path_factory.getbasetemp().parent
fn = root_tmp_dir / "warmup.done"
with FileLock(str(fn) + ".lock"):
if not fn.is_file():
docker_warmup(request)
fn.write_text("done")
return None
@pytest.fixture(params=["pip", "build", "uv"])
def build_frontend_env_nouv(request: pytest.FixtureRequest) -> dict[str, str]:
frontend = request.param
if platform == "pyodide" and frontend in {"pip", "uv"}:
pytest.skip("Can't use pip or uv as build frontend for pyodide platform")
if frontend == "uv" and find_uv() is None:
pytest.skip("Can't find uv")
return {"CIBW_BUILD_FRONTEND": frontend}
@pytest.fixture
def build_frontend_env(build_frontend_env_nouv: dict[str, str]) -> dict[str, str]:
frontend = build_frontend_env_nouv["CIBW_BUILD_FRONTEND"]
if frontend != "build" or platform == "pyodide" or find_uv() is None:
return build_frontend_env_nouv
return {"CIBW_BUILD_FRONTEND": "build[uv]"}
@pytest.fixture
def docker_cleanup() -> Generator[None, None, None]:
def get_images() -> set[str]:
if detect_ci_provider() is None or platform != "linux":
return set()
images = subprocess.run(
["docker", "image", "ls", "--format", "{{json .ID}}"],
text=True,
check=True,
stdout=subprocess.PIPE,
).stdout
return {json.loads(image.strip()) for image in images.splitlines() if image.strip()}
images_before = get_images()
try:
yield
finally:
images_after = get_images()
for image in images_after - images_before:
subprocess.run(["docker", "rmi", image], check=False)