From 9e72cd9b5487e7fcd84027f87e35e78bf994ce3c Mon Sep 17 00:00:00 2001 From: Joe Rickerby Date: Sat, 1 Mar 2025 09:47:44 +0000 Subject: [PATCH] feat: Print FatalError messages using Logger (#2292) * feat: Print FatalError messages using Logger This makes them appear GHA annotations in CI logs, which makes them easier to spot. I've also added the "cibuildwheel: " prefix to those errors, I think it helps when viewing a log to know which tool is talking to you - it can be difficult to understand with build tools. * Nicer error message on invalid architecture * Fix some message formatting and test expectations --- cibuildwheel/__main__.py | 9 ++++----- cibuildwheel/architecture.py | 8 +++++++- cibuildwheel/linux.py | 12 ++++++------ cibuildwheel/logger.py | 12 ++++++------ cibuildwheel/macos.py | 4 ++-- unit_test/main_tests/main_platform_test.py | 6 +++--- 6 files changed, 28 insertions(+), 23 deletions(-) diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index c1bfc098..fa324574 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -68,7 +68,7 @@ def main() -> None: if log.step_active: log.step_end_with_error(message) else: - print(f"cibuildwheel: {message}", file=sys.stderr) + log.error(message) if global_options.print_traceback_on_error: traceback.print_exc(file=sys.stderr) @@ -253,7 +253,7 @@ def _compute_platform_auto() -> PlatformName: return "windows" else: msg = ( - 'cibuildwheel: Unable to detect platform from "sys.platform". cibuildwheel doesn\'t ' + 'Unable to detect platform from "sys.platform". cibuildwheel doesn\'t ' "support building wheels for this platform. You might be able to build for a different " "platform using the --platform argument. Check --help output for more information." ) @@ -343,9 +343,8 @@ def print_new_wheels(msg: str, output_dir: Path) -> Generator[None, None, None]: def build_in_directory(args: CommandLineArguments) -> None: platform: PlatformName = _compute_platform(args) if platform == "pyodide" and sys.platform == "win32": - msg = "cibuildwheel: Building for pyodide is not supported on Windows" - print(msg, file=sys.stderr) - sys.exit(2) + msg = "Building for pyodide is not supported on Windows" + raise errors.ConfigurationError(msg) options = compute_options(platform=platform, command_line_arguments=args, env=os.environ) diff --git a/cibuildwheel/architecture.py b/cibuildwheel/architecture.py index 1c08cc8b..7af966ad 100644 --- a/cibuildwheel/architecture.py +++ b/cibuildwheel/architecture.py @@ -8,6 +8,8 @@ from collections.abc import Set from enum import StrEnum, auto from typing import Final, Literal +from cibuildwheel import errors + from .typing import PlatformName PRETTY_NAMES: Final[dict[PlatformName, str]] = { @@ -78,7 +80,11 @@ class Architecture(StrEnum): elif arch_str == "auto32": result |= Architecture.bitness_archs(platform=platform, bitness="32") else: - result.add(Architecture(arch_str)) + try: + result.add(Architecture(arch_str)) + except ValueError as e: + msg = f"Invalid architecture '{arch_str}'" + raise errors.ConfigurationError(msg) from e return result @staticmethod diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 65886727..ecc6be6f 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -451,12 +451,12 @@ def build(options: Options, tmp_path: Path) -> None: # noqa: ARG001 except subprocess.CalledProcessError as error: msg = unwrap( f""" - cibuildwheel: {build_step.container_engine.name} not found. An - OCI exe like Docker or Podman is required to run Linux builds. - If you're building on Travis CI, add `services: [docker]` to - your .travis.yml. If you're building on Circle CI in Linux, - add a `setup_remote_docker` step to your .circleci/config.yml. - If you're building on Cirrus CI, use `docker_builder` task. + {build_step.container_engine.name} not found. An OCI exe like + Docker or Podman is required to run Linux builds. If you're + building on Travis CI, add `services: [docker]` to your + .travis.yml. If you're building on Circle CI in Linux, add a + `setup_remote_docker` step to your .circleci/config.yml. If + you're building on Cirrus CI, use `docker_builder` task. """ ) raise errors.ConfigurationError(msg) from error diff --git a/cibuildwheel/logger.py b/cibuildwheel/logger.py index 48b0c89a..ec50da8a 100644 --- a/cibuildwheel/logger.py +++ b/cibuildwheel/logger.py @@ -159,24 +159,24 @@ class Logger: def notice(self, message: str) -> None: if self.fold_mode == "github": - print(f"::notice::{message}\n", file=sys.stderr) + print(f"::notice::cibuildwheel: {message}\n", file=sys.stderr) else: c = self.colors - print(f"{c.bold}Note{c.end}: {message}\n", file=sys.stderr) + print(f"cibuildwheel: {c.bold}note{c.end}: {message}\n", file=sys.stderr) def warning(self, message: str) -> None: if self.fold_mode == "github": - print(f"::warning::{message}\n", file=sys.stderr) + print(f"::warning::cibuildwheel: {message}\n", file=sys.stderr) else: c = self.colors - print(f"{c.yellow}Warning{c.end}: {message}\n", file=sys.stderr) + print(f"cibuildwheel: {c.yellow}warning{c.end}: {message}\n", file=sys.stderr) def error(self, error: BaseException | str) -> None: if self.fold_mode == "github": - print(f"::error::{error}\n", file=sys.stderr) + print(f"::error::cibuildwheel: {error}\n", file=sys.stderr) else: c = self.colors - print(f"{c.bright_red}Error{c.end}: {error}\n", file=sys.stderr) + print(f"cibuildwheel: {c.bright_red}error{c.end}: {error}\n", file=sys.stderr) @property def step_active(self) -> bool: diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index a4b0e790..176759d0 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -265,7 +265,7 @@ def setup_python( which_python = call("which", "python", env=env, capture_stdout=True).strip() print(which_python) if which_python != str(venv_bin_path / "python"): - msg = "cibuildwheel: python available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert python above it." + msg = "python available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert python above it." raise errors.FatalError(msg) call("python", "--version", env=env) @@ -275,7 +275,7 @@ def setup_python( which_pip = call("which", "pip", env=env, capture_stdout=True).strip() print(which_pip) if which_pip != str(venv_bin_path / "pip"): - msg = "cibuildwheel: pip available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it." + msg = "pip available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it." raise errors.FatalError(msg) call("pip", "--version", env=env) diff --git a/unit_test/main_tests/main_platform_test.py b/unit_test/main_tests/main_platform_test.py index 63f80eca..7ccfab6b 100644 --- a/unit_test/main_tests/main_platform_test.py +++ b/unit_test/main_tests/main_platform_test.py @@ -41,7 +41,7 @@ def test_unknown_platform_on_ci(monkeypatch, capsys): assert exit.value.code == 2 _, err = capsys.readouterr() - assert 'cibuildwheel: Unable to detect platform from "sys.platform"' in err + assert 'Unable to detect platform from "sys.platform"' in err def test_unknown_platform(monkeypatch, capsys): @@ -52,7 +52,7 @@ def test_unknown_platform(monkeypatch, capsys): _, err = capsys.readouterr() assert exit.value.code == 2 - assert "cibuildwheel: Unsupported platform: nonexistent" in err + assert "Unsupported platform: nonexistent" in err def test_platform_argument(platform, intercepted_build_args, monkeypatch): @@ -276,4 +276,4 @@ def test_pyodide_on_windows(monkeypatch, capsys): _, err = capsys.readouterr() assert exit.value.code == 2 - assert "cibuildwheel: Building for pyodide is not supported on Windows" in err + assert "Building for pyodide is not supported on Windows" in err