Skip to content

Commit

Permalink
Check Python version when initializing xbuildenv [integration]
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanking13 committed Nov 24, 2024
1 parent eb09824 commit 47e1b56
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 3 deletions.
2 changes: 2 additions & 0 deletions pyodide_build/build_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ def _init_xbuild_env(*, quiet: bool = False) -> Path:
if manager.current_version is None:
manager.install()

manager.check_version_marker()

return manager.pyodide_root


Expand Down
4 changes: 2 additions & 2 deletions pyodide_build/cli/xbuildenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ def _uninstall(
"""
check_xbuildenv_root(path)
manager = CrossBuildEnvManager(path)
manager.uninstall_version(version)
typer.echo(f"Pyodide cross-build environment {version} uninstalled")
v = manager.uninstall_version(version)
typer.echo(f"Pyodide cross-build environment {v} uninstalled")


@app.command("use")
Expand Down
43 changes: 43 additions & 0 deletions pyodide_build/tests/test_xbuildenv.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import sys

import pytest

from pyodide_build.xbuildenv import CrossBuildEnvManager, _url_to_version
Expand Down Expand Up @@ -156,6 +158,11 @@ def test_install_version(
).exists()
assert (manager.symlink_dir / "xbuildenv" / "site-packages-extras").exists()

assert (manager.symlink_dir / ".build-python-version").exists()
assert (
manager.symlink_dir / ".build-python-version"
).read_text() == f"{sys.version_info.major}.{sys.version_info.minor}"

# installing the same version again should be a no-op
manager.install(version)

Expand All @@ -180,6 +187,11 @@ def test_install_url(
).exists()
assert (manager.symlink_dir / "xbuildenv" / "site-packages-extras").exists()

assert (manager.symlink_dir / ".build-python-version").exists()
assert (
manager.symlink_dir / ".build-python-version"
).read_text() == f"{sys.version_info.major}.{sys.version_info.minor}"

def test_install_force(
self,
tmp_path,
Expand Down Expand Up @@ -278,6 +290,37 @@ def test_uninstall_version(self, tmp_path):

assert set(manager.list_versions()) == set(versions) - {"0.25.0", "0.25.1"}

def test_version_marker(
self,
tmp_path,
dummy_xbuildenv_url,
monkeypatch,
monkeypatch_subprocess_run_pip,
fake_xbuildenv_releases_compatible,
):
manager = CrossBuildEnvManager(
tmp_path, str(fake_xbuildenv_releases_compatible)
)
version = "0.1.0"

manager.install(version)

assert (manager.symlink_dir / ".build-python-version").exists()
assert (
manager.symlink_dir / ".build-python-version"
).read_text() == f"{sys.version_info.major}.{sys.version_info.minor}"

# No error
assert manager.check_version_marker() is None

(manager.symlink_dir / ".build-python-version").write_text("2.7.10")

with pytest.raises(
ValueError,
match="does not match the Python version",
):
manager.check_version_marker()


@pytest.mark.parametrize(
"url, version",
Expand Down
39 changes: 38 additions & 1 deletion pyodide_build/xbuildenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
)

CDN_BASE = "https://cdn.jsdelivr.net/pyodide/v{version}/full/"
PYTHON_VERSION_MARKER_FILE = ".build-python-version"


class CrossBuildEnvManager:
Expand Down Expand Up @@ -215,6 +216,7 @@ def install(

install_marker.touch()
self.use_version(version)
self._add_version_marker()
except Exception as e:
# if the installation failed, remove the downloaded directory
shutil.rmtree(download_path)
Expand Down Expand Up @@ -366,7 +368,7 @@ def _create_package_index(self, xbuildenv_pyodide_root: Path, version: str) -> N
lockfile = PyodideLockSpec(**json.loads(lockfile_path.read_bytes()))
create_package_index(lockfile.packages, xbuildenv_pyodide_root, cdn_base)

def uninstall_version(self, version: str) -> None:
def uninstall_version(self, version: str | None) -> str:
"""
Uninstall the installed xbuildenv version.
Expand All @@ -375,6 +377,12 @@ def uninstall_version(self, version: str) -> None:
version
The version of xbuildenv to uninstall.
"""
if version is None:
version = self.current_version

if version is None:
raise ValueError("No xbuildenv version is currently in use")

version_path = self._path_for_version(version)

# if the target version is the current version, remove the symlink
Expand All @@ -389,6 +397,35 @@ def uninstall_version(self, version: str) -> None:
f"Cannot find cross-build environment version {version}, available versions: {self.list_versions()}"
)

return version

def _add_version_marker(self) -> None:
"""
Store the Python version in the xbuildenv directory, so we can check compatibility later.
"""
if not self.symlink_dir.is_dir():
raise ValueError("cross-build env directory does not exist")

version_file = self.symlink_dir / PYTHON_VERSION_MARKER_FILE
version_file.write_text(build_env.local_versions()["python"])

def check_version_marker(self):
if not self.symlink_dir.is_dir():
raise ValueError("cross-build env directory does not exist")

version_file = self.symlink_dir / PYTHON_VERSION_MARKER_FILE
if not version_file.exists():
raise ValueError("Python version marker file not found")

version_local = build_env.local_versions()["python"]
version_on_install = version_file.read_text().strip()
if version_on_install != version_local:
raise ValueError(
f"local Python version ({version_local}) does not match the Python version ({version_on_install}) "
"used to create the Pyodide cross-build environment. "
"Please reinstall the xbuildenv, by running `pyodide xbuildenv uninstall` and then `pyodide xbuildenv install`"
)


def _url_to_version(url: str) -> str:
return url.replace("://", "_").replace(".", "_").replace("/", "_")

0 comments on commit 47e1b56

Please sign in to comment.