From 6f21f84a714eecaee517dc96beea9646d943beec Mon Sep 17 00:00:00 2001 From: Matthieu Darbois Date: Thu, 14 Nov 2024 17:40:59 +0100 Subject: [PATCH] fix: capture `stderr` in `utils.call` when `capture_stdout` is `True` (#2076) --- cibuildwheel/macos.py | 24 ++++++++++++------------ cibuildwheel/pyodide.py | 22 +++++++++++----------- cibuildwheel/util.py | 30 +++++++++++++++++++++++++----- cibuildwheel/windows.py | 8 ++++---- 4 files changed, 52 insertions(+), 32 deletions(-) diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index f830dbcc..fcc88dac 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -278,23 +278,23 @@ def setup_python( # Apply our environment after pip is ready env = environment.as_dictionary(prev_environment=env) - # check what pip version we're on - if not use_uv: - assert (venv_bin_path / "pip").exists() - call("which", "pip", env=env) - call("pip", "--version", env=env) - which_pip = call("which", "pip", env=env, capture_stdout=True).strip() - 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." - raise errors.FatalError(msg) - # check what Python version we're on - call("which", "python", env=env) - call("python", "--version", env=env) 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." raise errors.FatalError(msg) + call("python", "--version", env=env) + + # check what pip version we're on + if not use_uv: + assert (venv_bin_path / "pip").exists() + 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." + raise errors.FatalError(msg) + call("pip", "--version", env=env) config_is_arm64 = python_configuration.identifier.endswith("arm64") config_is_universal2 = python_configuration.identifier.endswith("universal2") diff --git a/cibuildwheel/pyodide.py b/cibuildwheel/pyodide.py index 3b721a10..147203cf 100644 --- a/cibuildwheel/pyodide.py +++ b/cibuildwheel/pyodide.py @@ -136,22 +136,22 @@ def setup_python( env = environment.as_dictionary(prev_environment=env) - # check what pip version we're on - assert (venv_bin_path / "pip").exists() - call("which", "pip", env=env) - call("pip", "--version", env=env) - which_pip = call("which", "pip", env=env, capture_stdout=True).strip() - if which_pip != str(venv_bin_path / "pip"): - msg = "pip available on PATH doesn't match our venv instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it." - raise errors.FatalError(msg) - # check what Python version we're on - call("which", "python", env=env) - call("python", "--version", env=env) which_python = call("which", "python", env=env, capture_stdout=True).strip() + print(which_python) if which_python != str(venv_bin_path / "python"): msg = "python available on PATH doesn't match our venv 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) + + # check what pip version we're on + assert (venv_bin_path / "pip").exists() + which_pip = call("which", "pip", env=env, capture_stdout=True).strip() + print(which_pip) + if which_pip != str(venv_bin_path / "pip"): + msg = "pip available on PATH doesn't match our venv 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) log.step("Installing build tools...") call( diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index d456511b..3e68ea73 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -38,6 +38,7 @@ from platformdirs import user_cache_path from ._compat import tomllib from .architecture import Architecture +from .errors import FatalError from .typing import PathOrStr, PlatformName __all__ = [ @@ -139,13 +140,32 @@ def call( args_ = [str(arg) for arg in args] # print the command executing for the logs print("+ " + " ".join(shlex.quote(a) for a in args_)) - kwargs: dict[str, Any] = {} - if capture_stdout: - kwargs["universal_newlines"] = True - kwargs["stdout"] = subprocess.PIPE - result = subprocess.run(args_, check=True, shell=IS_WIN, env=env, cwd=cwd, **kwargs) + # workaround platform behaviour differences outlined + # in https://github.com/python/cpython/issues/52803 + path_env = env if env is not None else os.environ + path = path_env.get("PATH", None) + executable = shutil.which(args_[0], path=path) + if executable is None: + msg = f"Couldn't find {args_[0]!r} in PATH {path!r}" + raise FatalError(msg) + args_[0] = executable + try: + result = subprocess.run( + args_, + check=True, + shell=IS_WIN, + env=env, + cwd=cwd, + capture_output=capture_stdout, + text=capture_stdout, + ) + except subprocess.CalledProcessError as e: + if capture_stdout: + sys.stderr.write(e.stderr) + raise if not capture_stdout: return None + sys.stderr.write(result.stderr) return typing.cast(str, result.stdout) diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py index 449be810..8f5633d6 100644 --- a/cibuildwheel/windows.py +++ b/cibuildwheel/windows.py @@ -302,22 +302,22 @@ def setup_python( env = environment.as_dictionary(prev_environment=env) # check what Python version we're on - call("where", "python", env=env) - call("python", "--version", env=env) - call("python", "-c", "\"import struct; print(struct.calcsize('P') * 8)\"", env=env) where_python = call("where", "python", env=env, capture_stdout=True).splitlines()[0].strip() + print(where_python) if where_python != str(venv_path / "Scripts" / "python.exe"): 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) + call("python", "-c", "\"import struct; print(struct.calcsize('P') * 8)\"", env=env) # check what pip version we're on if not use_uv: assert (venv_path / "Scripts" / "pip.exe").exists() where_pip = call("where", "pip", env=env, capture_stdout=True).splitlines()[0].strip() + print(where_pip) if where_pip.strip() != str(venv_path / "Scripts" / "pip.exe"): 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) log.step("Installing build tools...")