Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 11 additions & 4 deletions pyodide_build/build_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose you'd have to split and take the first entry if you're keeping the following code? constraints might contain two files, so Path(constraints) wouldn't refer to a file.

Expand Down
18 changes: 12 additions & 6 deletions pyodide_build/recipe/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions pyodide_build/tests/recipe/test_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")


Expand All @@ -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"
)
Expand Down
2 changes: 1 addition & 1 deletion pyodide_build/tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)


Expand Down