diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a9b7442..09bf3486 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Fixed + - Fixed a regression in quoting of pip arguments introduced in [#185](https://github.com/pyodide/pyodide-build/pull/185). [#209](https://github.com/pyodide/pyodide-build/pull/209) +- `pyodide-build` now correctly works with file paths with spaces passed to the `PIP_CONSTRAINT` environment variable. + [#210](https://github.com/pyodide/pyodide-build/pull/210) + ## [0.30.4] - 2025/05/20 - Fixed compatibility with `virtualenv` 20.31 and later. The Pyodide virtual environment via `pyodide venv` no longer seeds diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py index 4a13080b..508d273c 100644 --- a/pyodide_build/build_env.py +++ b/pyodide_build/build_env.py @@ -15,6 +15,7 @@ from pyodide_build import __version__ from pyodide_build.common import default_xbuildenv_path, search_pyproject_toml, to_bool +from pyodide_build.logger import logger RUST_BUILD_PRELUDE = """ rustup default ${RUST_TOOLCHAIN} @@ -334,10 +335,16 @@ def _create_constraints_file() -> str: if not constraints: return "" - if len(constraints.split(maxsplit=1)) > 1: - raise ValueError( - "PIP_CONSTRAINT contains spaces so pip will misinterpret it. Make sure the path to pyodide has no spaces.\n" - "See https://github.com/pypa/pip/issues/13283" + # If a path to a file specified PIP_CONSTRAINT contains spaces, pip will misinterpret + # it as multiple files; see https://github.com/pypa/pip/issues/13283. This is fine if + # the user wants to use multiple constraints files, but if they use a single file, we + # warn them about it and ask to convert the path to a URI or to remove spaces in it. + if " " in constraints: + logger.info( + "The value of PIP_CONSTRAINT contains spaces, and pip will interpret it as " + "multiple files. If you are using a single constraints file and it has spaces " + "in its file path, please convert it to a URI instead. Please ignore this " + "message if you are using multiple constraints files." ) constraints_file = Path(constraints) diff --git a/pyodide_build/recipe/builder.py b/pyodide_build/recipe/builder.py index 8b6885ad..e2f15fbc 100755 --- a/pyodide_build/recipe/builder.py +++ b/pyodide_build/recipe/builder.py @@ -136,11 +136,17 @@ def __init__( self.build_dir = ( Path(build_dir).resolve() if build_dir else self.pkg_root / "build" ) - if len(str(self.build_dir).split(maxsplit=1)) > 1: - raise ValueError( - "PIP_CONSTRAINT contains spaces so pip will misinterpret it. Make sure the path to the package build directory has no spaces.\n" - "See https://github.com/pypa/pip/issues/13283" + # If a path to a file specified PIP_CONSTRAINT contains spaces, pip will misinterpret + # it as multiple files; see https://github.com/pypa/pip/issues/13283 + # We work around this by converting the path to a URI when needed. + if " " in str(self.build_dir): + logger.info( + "The value of PIP_CONSTRAINT contains spaces, and pip will interpret it as " + "multiple files. If you are using a single constraints file and it has spaces " + "in its file path, please convert it to a URI instead. Please ignore this " + "message if you are using multiple constraints files." ) + self.library_install_prefix = self.build_dir.parent.parent / ".libs" self.src_extract_dir = ( self.build_dir / self.fullname @@ -367,7 +373,7 @@ def _download_and_extract(self) -> None: shutil.move(self.build_dir / extract_dir_name, self.src_extract_dir) self.src_dist_dir.mkdir(parents=True, exist_ok=True) - def _create_constraints_file(self) -> str: + def _create_combined_constraints_file(self) -> str: """ Creates a pip constraints file by concatenating global constraints (PIP_CONSTRAINT) with constraints specific to this package. @@ -434,7 +440,7 @@ def _compile( ) build_env = runner.env - build_env["PIP_CONSTRAINT"] = str(self._create_constraints_file()) + build_env["PIP_CONSTRAINT"] = str(self._create_combined_constraints_file()) wheel_path = pypabuild.build( self.src_extract_dir, self.src_dist_dir, build_env, config_settings diff --git a/pyodide_build/tests/recipe/test_builder.py b/pyodide_build/tests/recipe/test_builder.py index ba80a027..aa649802 100644 --- a/pyodide_build/tests/recipe/test_builder.py +++ b/pyodide_build/tests/recipe/test_builder.py @@ -183,7 +183,7 @@ def test_create_constraints_file_no_override(tmp_path, dummy_xbuildenv): build_dir=tmp_path, ) - path = builder._create_constraints_file() + path = builder._create_combined_constraints_file() assert path == get_build_flag("PIP_CONSTRAINT") @@ -194,7 +194,7 @@ def test_create_constraints_file_override(tmp_path, dummy_xbuildenv): build_dir=tmp_path, ) - paths = builder._create_constraints_file() + paths = builder._create_combined_constraints_file() assert paths == get_build_flag("PIP_CONSTRAINT") + " " + str( tmp_path / "constraints.txt" ) diff --git a/pyodide_build/tests/test_cli.py b/pyodide_build/tests/test_cli.py index 743a26f4..14e328fb 100644 --- a/pyodide_build/tests/test_cli.py +++ b/pyodide_build/tests/test_cli.py @@ -72,7 +72,7 @@ def test_skeleton_pypi(tmp_path): skeleton.app, ["pypi", test_pkg, "--recipe-dir", str(tmp_path)] ) assert result.exit_code != 0 - assert "already exists" in str(result.stdout) + assert "already exists" in str(result.stderr) assert isinstance(result.exception, SystemExit)