chore: faster and stricter mypy (#2968)

* chore: faster mypy

This makes mypy around 26% faster from a cold cache.

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>

* chore: enable more mypy error codes

Turn on possibly-undefined, exhaustive-match, and other strict flags, and
fix what they report. Two real bugs: pyodide never set `repaired_wheel`
when it reused a compatible wheel, so the test step failed with a
NameError; the OCI shell read loop spun forever if the shell exited.

Assisted-by: ClaudeCode:claude-opus-5

* test: carry default OCI runtime into podman vfs test config

Podman ignores its usual config files when CONTAINERS_CONF is set, so it
falls back to the first runtime found on PATH. On current GitHub Ubuntu
runner images that is crun 1.14.1, which cannot parse the OCI spec v1.2.x
config that podman 5.8.4 generates ("crun: unknown version specified").
Query the default runtime path and set it in the generated config.

Assisted-by: ClaudeCode:claude-fable-5

* fix: annotate vfs config dict so mypy passes on Linux

mypy on macOS marks the rest of the function unreachable after the
darwin pytest.skip, so the strict index error only appears on Linux.

Assisted-by: ClaudeCode:claude-fable-5

* chore: minor cleanup of variable name

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>

* test: cover container shell exiting during call

Assisted-by: ClaudeCode:claude-opus-5

---------

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
This commit is contained in:
Henry Schreiner
2026-08-17 19:02:37 -04:00
committed by GitHub
parent 96ba88f3aa
commit 148ea702ac
9 changed files with 68 additions and 13 deletions
+2
View File
@@ -318,6 +318,8 @@ for value in schema["properties"].values():
case {"type": "string_table_array"}:
del value["type"]
value["oneOf"] = string_table_array
case _:
pass
overrides = yaml.safe_load(
"""
+3 -3
View File
@@ -76,9 +76,9 @@ class WindowsVersions:
response.raise_for_status()
api_info = response.json()
for resource in api_info["resources"]:
if resource["@type"] == "PackageBaseAddress/3.0.0":
endpoint = resource["@id"]
endpoint = next(
r["@id"] for r in api_info["resources"] if r["@type"] == "PackageBaseAddress/3.0.0"
)
ARCH_DICT = {"32": "win32", "64": "win_amd64", "ARM64": "win_arm64"}
PACKAGE_DICT = {"32": "pythonx86", "64": "python", "ARM64": "pythonarm64"}
+6 -2
View File
@@ -546,9 +546,14 @@ class OCIContainer:
else:
output_io = sys.stdout.buffer
while True:
return_code = None
while return_code is None:
line = self.bash_stdout.readline()
if not line:
msg = "Failed to read the return code, the container shell has exited"
raise RuntimeError(msg)
if line.endswith(bytes(end_of_message, encoding="utf8") + b"\n"):
# fmt: off
footer_offset = (
@@ -563,7 +568,6 @@ class OCIContainer:
# add the last line to output, without the footer
output_io.write(line[0:footer_offset])
output_io.flush()
break
else:
output_io.write(line)
output_io.flush()
+2 -4
View File
@@ -540,7 +540,7 @@ def build(options: Options, tmp_path: Path) -> None:
f"that is compatible with {config.identifier}. "
"Skipping build step..."
)
test_wheel = compatible_wheel
repaired_wheel = compatible_wheel
else:
if build_options.before_build:
log.step("Running before_build...")
@@ -632,8 +632,6 @@ def build(options: Options, tmp_path: Path) -> None:
run_audit(tmp_dir=tmp_path, build_options=build_options, wheel=repaired_wheel)
test_wheel = repaired_wheel
if build_options.test_command and build_options.test_selector(config.identifier):
if not config.is_simulator:
log.step("Skipping tests on non-simulator SDK")
@@ -693,7 +691,7 @@ def build(options: Options, tmp_path: Path) -> None:
platform_tag,
"--target",
testbed_path / "iOSTestbed" / "app_packages",
f"{test_wheel}{build_options.test_extras}",
f"{repaired_wheel}{build_options.test_extras}",
*build_options.test_requires,
env=test_env,
)
+1 -1
View File
@@ -473,7 +473,7 @@ def build(options: Options, tmp_path: Path) -> None:
print(
f"\nFound previously built wheel {compatible_wheel.name}, that's compatible with {config.identifier}. Skipping build step..."
)
built_wheel = compatible_wheel
repaired_wheel = compatible_wheel
else:
if build_options.before_build:
log.step("Running before_build...")
+2
View File
@@ -60,6 +60,8 @@ class Analyzer(ast.NodeVisitor):
case ast.keyword(arg="python_requires", value=ast.Constant(value=str() as version)):
if unnested or name_main_unnested:
self.requires_python = version
case _:
pass
def setup_py_python_requires(content: str) -> str | None:
+1 -1
View File
@@ -12,7 +12,7 @@ def define_env(env: Any) -> None: # noqa: ANN401
"Hook function for mkdocs-macros"
@env.macro # type: ignore[untyped-decorator]
def subprocess_run(*args: str) -> str:
def subprocess_run(*args: str) -> str: # type: ignore[misc]
"Run a subprocess and return the stdout"
env = os.environ.copy()
scripts = sysconfig.get_path("scripts")
+22 -1
View File
@@ -116,10 +116,27 @@ files = [
"bin/*.py",
"noxfile.py",
]
disallow_any_decorated = true
disallow_any_unimported = true
disallow_untyped_globals = true
disallow_redefinition = true
warn_unused_configs = true
strict = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
enable_error_code = [
"deprecated",
"exhaustive-match",
"ignore-without-code",
"mutable-override",
"possibly-undefined",
"redundant-expr",
"redundant-self",
"truthy-bool",
"truthy-iterable",
"unimported-reveal",
"unused-awaitable",
]
warn_unreachable = false
native_parser = true
[[tool.mypy.overrides]]
module = [
@@ -130,6 +147,10 @@ module = [
]
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = ["cibuildwheel.bashlex_eval"]
disable_error_code = ["no-any-unimported"]
[tool.pylint]
py-version = "3.11"
+29 -1
View File
@@ -29,6 +29,7 @@ from cibuildwheel.oci_container import (
TYPE_CHECKING = False
if TYPE_CHECKING:
from collections.abc import Iterator
from typing import Any
# Test utilities
@@ -84,6 +85,18 @@ def test_no_lf(container_engine: OCIContainerEngineConfig) -> None:
assert container.call(["printf", "hello"], capture_output=True) == "hello"
def test_abnormal_exit(container_engine: OCIContainerEngineConfig) -> None:
container = OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
)
with container:
# kill the shell without a newline, so the write below still goes
# through the same buffer and the call fails on read, not on write
container.bash_stdin.write(b"exit")
with pytest.raises(RuntimeError):
container.call(["echo", "hello"])
def test_debug_info(container_engine: OCIContainerEngineConfig) -> None:
container = OCIContainer(
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
@@ -139,6 +152,7 @@ def test_container_removed(container_engine: OCIContainerEngineConfig) -> None:
) as container:
assert container.name is not None
container_name = container.name
docker_containers_listing = ""
for _ in range(timeout):
docker_containers_listing = subprocess.run(
f"{container.engine.name} container ls",
@@ -330,7 +344,7 @@ def test_podman_vfs(
# This requires that we write configuration files and point to them
# with environment variables before we run podman
# https://github.com/containers/common/blob/main/docs/containers.conf.5.md
vfs_containers_conf_data = {
vfs_containers_conf_data: dict[str, dict[str, Any]] = {
"containers": {
"default_capabilities": [
"CHOWN",
@@ -348,6 +362,20 @@ def test_podman_vfs(
},
"engine": {"cgroup_manager": "cgroupfs", "events_logger": "file"},
}
# Setting CONTAINERS_CONF makes podman ignore its usual config files, so
# carry over the default OCI runtime; the fallback found on PATH can be
# too old for the OCI spec version podman generates (e.g. Ubuntu 24.04's
# crun 1.14.1 with podman 5.x).
oci_runtime = subprocess.run(
["podman", "info", "--format", "{{.Host.OCIRuntime.Path}}"],
check=True,
capture_output=True,
text=True,
).stdout.strip()
runtime_name = Path(oci_runtime).name
vfs_containers_conf_data["engine"]["runtime"] = runtime_name
vfs_containers_conf_data["engine"]["runtimes"] = {runtime_name: [oci_runtime]}
# https://github.com/containers/storage/blob/main/docs/containers-storage.conf.5.md
storage_root = vfs_path / ".local/share/containers/vfs-storage"
run_root = vfs_path / ".local/share/containers/vfs-runroot"