Skip to content

Commit 5c0940c

Browse files
committed
Switch to a dict-based test-execution configuration
1 parent 3a35df1 commit 5c0940c

File tree

10 files changed

+126
-66
lines changed

10 files changed

+126
-66
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,13 @@ jobs:
7979
- os: macos-15
8080
python_version: '3.13'
8181
test_select: ios
82-
# Github Actions macOS-15 runner has disk performance issues; so it
83-
# has problems using any simulator that isn't pre-warmed.
84-
# Unfortunately, the simulator that it picks by default isn't
85-
# pre-warmed. So - we need to explicitly select a simulator.
86-
test_execution_args: '--simulator "iPhone 16e,OS=18.5"'
82+
# Exercise iOS on a non-default simulator.
83+
test_execution: 'args: --simulator "iPhone 16e,OS=18.5"'
8784
- os: macos-15-intel
8885
python_version: '3.13'
8986
test_select: android
9087
# Exercise Android on a non-default simulator
91-
test_execution_args: '--managed minVersion'
88+
test_execution: 'args: --managed minVersion'
9289
- os: macos-15
9390
python_version: '3.13'
9491
test_select: android
@@ -161,7 +158,7 @@ jobs:
161158
CIBW_ARCHS_MACOS: x86_64 universal2 arm64
162159
CIBW_BUILD_FRONTEND: ${{ matrix.test_select && 'build' || 'build[uv]' }}
163160
CIBW_PLATFORM: ${{ matrix.test_select }}
164-
CIBW_TEST_EXECUTION_ARGS: ${{ matrix.test_execution_args }}
161+
CIBW_TEST_EXECUTION: ${{ matrix.test_execution }}
165162

166163
- name: Run a sample build (GitHub Action, only)
167164
uses: ./
@@ -187,7 +184,7 @@ jobs:
187184
uses: ./
188185
env:
189186
CIBW_PLATFORM: ${{ matrix.test_select }}
190-
CIBW_TEST_EXECUTION_ARGS: ${{ matrix.test_execution_args }}
187+
CIBW_TEST_EXECUTION: ${{ matrix.test_execution }}
191188
with:
192189
package-dir: sample_proj
193190
output-dir: wheelhouse_config_file
@@ -212,7 +209,7 @@ jobs:
212209

213210
- name: Test cibuildwheel
214211
env:
215-
CIBW_TEST_EXECUTION_ARGS: ${{ matrix.test_execution_args }}
212+
CIBW_TEST_EXECUTION: ${{ matrix.test_execution }}
216213
run: |
217214
uv run --no-sync bin/run_tests.py --test-select=${{ matrix.test_select || 'native' }} ${{ (runner.os == 'Linux' && runner.arch == 'X64') && '--run-podman' || '' }}
218215

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,13 @@ The following diagram summarises the steps that cibuildwheel takes on each platf
159159
| | [`test-groups`](https://cibuildwheel.pypa.io/en/stable/options/#test-groups) | Specify test dependencies from your project's `dependency-groups` |
160160
| | [`test-skip`](https://cibuildwheel.pypa.io/en/stable/options/#test-skip) | Skip running tests on some builds |
161161
| | [`test-environment`](https://cibuildwheel.pypa.io/en/stable/options/#test-environment) | Set environment variables for the test environment |
162-
| | [`test-execution-args`](https://cibuildwheel.pypa.io/en/stable/options/#test-execution-args) | Define additional arguments that will be passed to the command that runs the tests. |
162+
| | [`test-execution`](https://cibuildwheel.pypa.io/en/stable/options/#test-execution) | Controls how the tests will be executed. |
163163
| **Debugging** | [`debug-keep-container`](https://cibuildwheel.pypa.io/en/stable/options/#debug-keep-container) | Keep the container after running for debugging. |
164164
| | [`debug-traceback`](https://cibuildwheel.pypa.io/en/stable/options/#debug-traceback) | Print full traceback when errors occur. |
165165
| | [`build-verbosity`](https://cibuildwheel.pypa.io/en/stable/options/#build-verbosity) | Increase/decrease the output of the build |
166166

167167

168-
<!--[[[end]]] (sum: gNUxwlNyTE) -->
168+
<!--[[[end]]] (sum: /aL2w4bcMB) -->
169169

170170
These options can be specified in a pyproject.toml file, or as environment variables, see [configuration docs](https://cibuildwheel.pypa.io/en/latest/configuration/).
171171

bin/generate_schema.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,20 @@
224224
test-environment:
225225
description: Set environment variables for the test environment
226226
type: string_table
227-
test-execution-args:
228-
description: Additional arguments for the test runner to use when configuring the test environment
229-
type: string_array
227+
test-execution:
228+
description: Additional configuration for the test runner
229+
oneOf:
230+
- type: string
231+
pattern: 'args:'
232+
- type: object
233+
additionalProperties: false
234+
required: [args]
235+
properties:
236+
args:
237+
type: array
238+
items:
239+
type: string
240+
230241
"""
231242

232243
schema = yaml.safe_load(starter)
@@ -307,7 +318,7 @@
307318
test-sources: {"$ref": "#/$defs/inherit"}
308319
test-requires: {"$ref": "#/$defs/inherit"}
309320
test-environment: {"$ref": "#/$defs/inherit"}
310-
test-execution-args: {"$ref": "#/$defs/inherit"}
321+
test-execution: {"$ref": "#/$defs/inherit"}
311322
"""
312323
)
313324

cibuildwheel/options.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from .selector import BuildSelector, EnableGroup, TestSelector, selector_matches
2525
from .typing import PLATFORMS, PlatformName
2626
from .util import resources
27-
from .util.helpers import format_safe, strtobool, unwrap
27+
from .util.helpers import format_safe, parse_key_value_string, strtobool, unwrap
2828
from .util.packaging import DependencyConstraints
2929

3030
MANYLINUX_ARCHS: Final[tuple[str, ...]] = (
@@ -92,6 +92,20 @@ class GlobalOptions:
9292
allow_empty: bool
9393

9494

95+
@dataclasses.dataclass(frozen=True)
96+
class TestExecutionConfig:
97+
args: Sequence[str] = ()
98+
99+
@classmethod
100+
def from_config_string(cls, config_string: str) -> Self:
101+
config_dict = parse_key_value_string(config_string, ["args"])
102+
args = config_dict.get("args") or []
103+
return cls(args=args)
104+
105+
def options_summary(self) -> str | dict[str, str]:
106+
return {"args": repr(self.args)}
107+
108+
95109
@dataclasses.dataclass(frozen=True, kw_only=True)
96110
class BuildOptions:
97111
globals: GlobalOptions
@@ -110,7 +124,7 @@ class BuildOptions:
110124
test_extras: str
111125
test_groups: list[str]
112126
test_environment: ParsedEnvironment
113-
test_execution_args: list[str] | None
127+
test_execution: TestExecutionConfig
114128
build_verbosity: int
115129
build_frontend: BuildFrontendConfig
116130
config_settings: str
@@ -762,11 +776,19 @@ def _compute_build_options(self, identifier: str | None) -> BuildOptions:
762776
msg = f"Malformed environment option {test_environment_config!r}"
763777
raise errors.ConfigurationError(msg) from e
764778

765-
test_execution_args = shlex.split(
766-
self.reader.get(
767-
"test-execution-args", option_format=ListFormat(sep=" ", quote=shlex.quote)
768-
)
779+
test_execution_str = self.reader.get(
780+
"test-execution",
781+
env_plat=False,
782+
option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False),
769783
)
784+
if not test_execution_str or test_execution_str == "default":
785+
test_execution = TestExecutionConfig()
786+
else:
787+
try:
788+
test_execution = TestExecutionConfig.from_config_string(test_execution_str)
789+
except ValueError as e:
790+
msg = f"Failed to parse test execution config. {e}"
791+
raise errors.ConfigurationError(msg) from e
770792

771793
test_requires = self.reader.get(
772794
"test-requires", option_format=ListFormat(sep=" ")
@@ -875,7 +897,7 @@ def _compute_build_options(self, identifier: str | None) -> BuildOptions:
875897
test_command=test_command,
876898
test_sources=test_sources,
877899
test_environment=test_environment,
878-
test_execution_args=test_execution_args,
900+
test_execution=test_execution,
879901
test_requires=[*test_requires, *test_requirements_from_groups],
880902
test_extras=test_extras,
881903
test_groups=test_groups,

cibuildwheel/platforms/android.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -641,10 +641,9 @@ def test_wheel(state: BuildState, wheel: Path) -> None:
641641
# By default, run on a testbed managed emulator running the newest supported
642642
# Android version. However, if the user specifies a --managed or --connected
643643
# test execution argument, that argument takes precedence.
644-
if state.options.test_execution_args and (
645-
"--managed" in state.options.test_execution_args
646-
or "--connected" in state.options.test_execution_args
647-
):
644+
test_execution_args = state.options.test_execution.args
645+
646+
if any(arg.startswith(("--managed", "--connected")) for arg in test_execution_args):
648647
emulator_args = []
649648
else:
650649
emulator_args = ["--managed", "maxVersion"]
@@ -659,7 +658,7 @@ def test_wheel(state: BuildState, wheel: Path) -> None:
659658
cwd_dir,
660659
*emulator_args,
661660
*(["-v"] if state.options.build_verbosity > 0 else []),
662-
*(state.options.test_execution_args or []),
661+
*test_execution_args,
663662
"--",
664663
*test_args,
665664
env=state.build_env,

cibuildwheel/platforms/ios.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import dataclasses
44
import os
5+
import platform
56
import shlex
67
import shutil
78
import subprocess
@@ -653,12 +654,35 @@ def build(options: Options, tmp_path: Path) -> None:
653654
)
654655
raise errors.FatalError(msg)
655656

657+
test_execution_args = build_options.test_execution.args
658+
659+
# 2025-10: The GitHub Actions macos-15 runner has a known issue where
660+
# the default simulator won't start due to a disk performance issue;
661+
# see https://github.com/actions/runner-images/issues/12777 for details.
662+
# In the meantime, if it looks like we're running on a GitHub Actions
663+
# macos-15 runner, use a simulator that is known to work, unless the
664+
# user explicitly specifies a simulator.
665+
os_version, _, arch = platform.mac_ver()
666+
if (
667+
"GITHUB_ACTIONS" in os.environ
668+
and os_version.startswith("15.")
669+
and arch == "arm64"
670+
and not any(
671+
arg.startswith("--simulator") for arg in test_execution_args
672+
)
673+
):
674+
test_execution_args = [
675+
"--simulator",
676+
"iPhone 16e,OS=18.5",
677+
*test_execution_args,
678+
]
679+
656680
call(
657681
"python",
658682
testbed_path,
659683
"run",
660684
*(["--verbose"] if build_options.build_verbosity > 0 else []),
661-
*(build_options.test_execution_args or []),
685+
*test_execution_args,
662686
"--",
663687
*final_command,
664688
env=test_env,

cibuildwheel/resources/cibuildwheel.schema.json

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -569,20 +569,30 @@
569569
],
570570
"title": "CIBW_TEST_ENVIRONMENT"
571571
},
572-
"test-execution-args": {
573-
"description": "Additional arguments for the test runner to use when configuring the test environment",
572+
"test-execution": {
573+
"description": "Additional configuration for the test runner",
574574
"oneOf": [
575575
{
576-
"type": "string"
576+
"type": "string",
577+
"pattern": "args:"
577578
},
578579
{
579-
"type": "array",
580-
"items": {
581-
"type": "string"
580+
"type": "object",
581+
"additionalProperties": false,
582+
"required": [
583+
"args"
584+
],
585+
"properties": {
586+
"args": {
587+
"type": "array",
588+
"items": {
589+
"type": "string"
590+
}
591+
}
582592
}
583593
}
584594
],
585-
"title": "CIBW_TEST_EXECUTION_ARGS"
595+
"title": "CIBW_TEST_EXECUTION"
586596
},
587597
"overrides": {
588598
"type": "array",
@@ -654,7 +664,7 @@
654664
"test-environment": {
655665
"$ref": "#/$defs/inherit"
656666
},
657-
"test-execution-args": {
667+
"test-execution": {
658668
"$ref": "#/$defs/inherit"
659669
}
660670
}
@@ -767,8 +777,8 @@
767777
"test-environment": {
768778
"$ref": "#/properties/test-environment"
769779
},
770-
"test-execution-args": {
771-
"$ref": "#/properties/test-execution-args"
780+
"test-execution": {
781+
"$ref": "#/properties/test-execution"
772782
}
773783
}
774784
}
@@ -898,8 +908,8 @@
898908
"test-environment": {
899909
"$ref": "#/properties/test-environment"
900910
},
901-
"test-execution-args": {
902-
"$ref": "#/properties/test-execution-args"
911+
"test-execution": {
912+
"$ref": "#/properties/test-execution"
903913
}
904914
}
905915
},
@@ -961,8 +971,8 @@
961971
"test-environment": {
962972
"$ref": "#/properties/test-environment"
963973
},
964-
"test-execution-args": {
965-
"$ref": "#/properties/test-execution-args"
974+
"test-execution": {
975+
"$ref": "#/properties/test-execution"
966976
}
967977
}
968978
},
@@ -1037,8 +1047,8 @@
10371047
"test-environment": {
10381048
"$ref": "#/properties/test-environment"
10391049
},
1040-
"test-execution-args": {
1041-
"$ref": "#/properties/test-execution-args"
1050+
"test-execution": {
1051+
"$ref": "#/properties/test-execution"
10421052
}
10431053
}
10441054
},
@@ -1100,8 +1110,8 @@
11001110
"test-environment": {
11011111
"$ref": "#/properties/test-environment"
11021112
},
1103-
"test-execution-args": {
1104-
"$ref": "#/properties/test-execution-args"
1113+
"test-execution": {
1114+
"$ref": "#/properties/test-execution"
11051115
}
11061116
}
11071117
},
@@ -1163,8 +1173,8 @@
11631173
"test-environment": {
11641174
"$ref": "#/properties/test-environment"
11651175
},
1166-
"test-execution-args": {
1167-
"$ref": "#/properties/test-execution-args"
1176+
"test-execution": {
1177+
"$ref": "#/properties/test-execution"
11681178
}
11691179
}
11701180
},
@@ -1226,8 +1236,8 @@
12261236
"test-environment": {
12271237
"$ref": "#/properties/test-environment"
12281238
},
1229-
"test-execution-args": {
1230-
"$ref": "#/properties/test-execution-args"
1239+
"test-execution": {
1240+
"$ref": "#/properties/test-execution"
12311241
}
12321242
}
12331243
}

cibuildwheel/resources/defaults.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ test-requires = []
2525
test-extras = []
2626
test-groups = []
2727
test-environment = {}
28-
test-execution-args = []
28+
test-execution = {}
2929

3030
container-engine = "docker"
3131

0 commit comments

Comments
 (0)