"""The venv node code imports from is built and kept in step with a manifest.""" import shutil import subprocess from pathlib import Path import pytest from fluksio.flow import modules from fluksio.flow.store import FlowStore pytestmark = pytest.mark.skipif( shutil.which("uv") is None, reason="module management needs uv" ) @pytest.fixture def venv(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path: directory = tmp_path / "user-venv" monkeypatch.setattr(modules, "VENV_DIR", directory) return directory def test_an_empty_manifest_gives_a_venv_of_its_own(venv: Path, tmp_path: Path): store = FlowStore(tmp_path / "flows") store.write_requirements("") modules.sync("") assert Path(modules.venv_python()).exists() assert modules.venv_python().startswith(str(venv)) information = modules.info(store) assert information.applied is True assert information.python_version def test_a_manifest_already_applied_is_not_installed_again( venv: Path, tmp_path: Path, monkeypatch: pytest.MonkeyPatch ): store = FlowStore(tmp_path / "flows") store.write_requirements("") modules.sync("") marker = (venv / ".applied").read_text() # Recorded rather than refused: reconcile swallows what it fails on, so an # exception raised in here would never reach the test. calls: list[object] = [] monkeypatch.setattr(subprocess, "run", lambda *args, **kwargs: calls.append(args)) modules.reconcile(store) assert calls == [] assert (venv / ".applied").read_text() == marker def test_a_missing_uv_is_a_failed_apply_rather_than_a_crash( venv: Path, monkeypatch: pytest.MonkeyPatch ): def no_uv(*args: object, **kwargs: object) -> None: raise FileNotFoundError(2, "No such file or directory: 'uv'") monkeypatch.setattr(subprocess, "run", no_uv) ok, output = modules.sync("") # The route turns this into a 400 with the output; an exception would be a # 500 with nothing in it. assert ok is False assert "uv could not run" in output def test_a_manifest_that_does_not_resolve_leaves_the_venv_alone(venv: Path): modules.sync("") ok, output = modules.sync("fluksio-no-such-package-anywhere==9.9.9") assert ok is False assert output # The marker still describes the manifest that actually installed. assert (venv / ".applied").read_text() == modules._digest("")