diff --git a/install.ps1 b/install.ps1 index a525d4df56..524fd85774 100644 --- a/install.ps1 +++ b/install.ps1 @@ -2420,6 +2420,13 @@ exit 0 } } + $installedPackageVersion = (& $VenvPython -c "from importlib.metadata import version; import sys; print(version(sys.argv[1]))" $PackageName 2>$null | Out-String).Trim() + if ($LASTEXITCODE -eq 0 -and $installedPackageVersion) { + step $PackageName "$installedPackageVersion installed" + } else { + substep "[WARN] installed $PackageName version could not be determined" "Yellow" + } + # ── Enforce the installed torch flavor matches the detected GPU build ── # PEP 440 ignores the +cpu/+cuXXX/+rocm local label in a version range, so uv # keeps a stale torch==X+cpu against a CUDA index and setup.ps1 then loops on diff --git a/install.sh b/install.sh index 0acccdf049..445bab616a 100755 --- a/install.sh +++ b/install.sh @@ -3396,6 +3396,15 @@ else fi fi +_installed_package_version=$("$_VENV_PY" -c \ + 'from importlib.metadata import version; import sys; print(version(sys.argv[1]))' \ + "$PACKAGE_NAME" 2>/dev/null || true) +if [ -n "$_installed_package_version" ]; then + step "$PACKAGE_NAME" "$_installed_package_version installed" +else + substep "[WARN] installed $PACKAGE_NAME version could not be determined" "$C_WARN" +fi + # ── Enforce the installed torch flavor matches the detected GPU build ── # PEP 440 ignores the +cpu/+cuXXX/+rocm local label in a version range, so uv # keeps a stale torch==X+cpu against a GPU index and the venv silently trains on diff --git a/tests/test_installer_unsloth_version.py b/tests/test_installer_unsloth_version.py new file mode 100644 index 0000000000..5ee1cfac71 --- /dev/null +++ b/tests/test_installer_unsloth_version.py @@ -0,0 +1,75 @@ +"""Regression coverage for installer version reporting.""" + +from __future__ import annotations + +import re +import shutil +import subprocess +import sys +from importlib.metadata import version +from pathlib import Path + +import pytest + +REPO_ROOT = Path(__file__).resolve().parents[1] +INSTALL_SH = REPO_ROOT / "install.sh" +INSTALL_PS1 = REPO_ROOT / "install.ps1" + + +def _extract(pattern: str, source: str) -> str: + match = re.search(pattern, source, flags = re.DOTALL | re.MULTILINE) + assert match is not None, f"installer block not found: {pattern}" + return match.group(0) + + +@pytest.mark.skipif(shutil.which("sh") is None, reason = "POSIX shell is unavailable") +def test_posix_installer_reports_installed_distribution_version(): + source = INSTALL_SH.read_text(encoding = "utf-8") + reporter = _extract( + r"_installed_package_version=\$\(.*?^fi", + source, + ) + result = subprocess.run( + [ + "sh", + "-c", + ( + 'step() { printf "%s %s\\n" "$1" "$2"; }\n' + 'substep() { printf "WARN %s\\n" "$1"; }\n' + f"_VENV_PY={sys.executable!r}\n" + "PACKAGE_NAME=pytest\n" + f"{reporter}" + ), + ], + check = True, + capture_output = True, + text = True, + ) + assert result.stdout.strip() == f"pytest {version('pytest')} installed" + + +@pytest.mark.skipif(shutil.which("pwsh") is None, reason = "PowerShell is unavailable") +def test_windows_version_reporter_uses_distribution_metadata(): + source = INSTALL_PS1.read_text(encoding = "utf-8") + reporter = _extract( + r" \$installedPackageVersion = .*?^ if .*?^ \} else \{.*?^ \}", + source, + ) + result = subprocess.run( + [ + "pwsh", + "-NoProfile", + "-NonInteractive", + "-Command", + ( + 'function step { param($Label, $Value) Write-Output "$Label $Value" }; ' + 'function substep { param($Message, $Color) Write-Output "WARN $Message" }; ' + f"$VenvPython = '{sys.executable}'; $PackageName = 'pytest'; " + f"{reporter}" + ), + ], + check = True, + capture_output = True, + text = True, + ) + assert result.stdout.strip() == f"pytest {version('pytest')} installed"