Pin uv and uvx to the PM interpreter instead of ambient Python discovery. A matching dependency stamp cannot prove that installed files still exist. Repair now rebuilds the recorded workspace and lock in a fresh generation, checks startup imports, and publishes the selection only after success. Run startup recovery before dependency activation. Keep manual PM repair reachable when the selected environment is damaged. Preserve plugin selection, retry ownership, and the previous generation on failure. Remove the separate pip, ensurepip, per-extra, and install-time quarantine ladders. Keep orphan launcher restoration. Verification: 717 targeted tests passed on native Windows ARM64, with 56 skipped. Ruff, diff checks, and the source-scoped compat check passed. A disposable real Hermes install recovered deleted YAML and dotenv files, then printed CLI help with exit 0. Its lock and stamp stayed unchanged. The full suite and a release build were not run for this change.
36 lines
1.6 KiB
Python
36 lines
1.6 KiB
Python
"""Workspace commands preserve PM's toolchain instead of consulting PATH."""
|
|
import importlib
|
|
import shutil
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
from pm import workspace
|
|
from pm.package import InstallError
|
|
|
|
|
|
def test_workspace_uv_preserves_managed_tool_and_interpreter(monkeypatch, tmp_path):
|
|
ensure = importlib.import_module("pm.ensure")
|
|
monkeypatch.setattr(ensure, "uv", lambda **kwargs: ("managed/uv", {"UV_PYTHON": "managed/python"}))
|
|
monkeypatch.setattr(workspace, "_generate_pyproject", lambda *args: (tmp_path, False))
|
|
def reject_path(*args, **kwargs):
|
|
raise AssertionError("workspace commands must not resolve tools from PATH")
|
|
monkeypatch.setattr(shutil, "which", reject_path)
|
|
calls = []
|
|
def run(cmd, **kwargs):
|
|
calls.append((cmd, kwargs["env"]))
|
|
return subprocess.CompletedProcess(cmd, 0, "", "")
|
|
monkeypatch.setattr(workspace.subprocess, "run", run)
|
|
workspace.lock_and_sync([], venv_dir=tmp_path / "venv", root=tmp_path)
|
|
assert [cmd[1] for cmd, _ in calls] == ["lock", "sync"]
|
|
assert all(cmd[0] == "managed/uv" and env["UV_PYTHON"] == "managed/python" for cmd, env in calls)
|
|
|
|
|
|
def test_workspace_uv_missing_toolchain_never_falls_back(monkeypatch, tmp_path):
|
|
ensure = importlib.import_module("pm.ensure")
|
|
monkeypatch.setattr(ensure, "uv", lambda **kwargs: (None, {}))
|
|
monkeypatch.setattr(workspace, "_generate_pyproject", lambda *args: (tmp_path, False))
|
|
monkeypatch.setattr(shutil, "which", lambda name: "developer/uv")
|
|
with pytest.raises(InstallError, match="PM's uv and Python"):
|
|
workspace.lock_and_sync([], venv_dir=tmp_path / "venv", root=tmp_path)
|