* Studio: allow torch 2.11.x on the CUDA install path The CUDA torch repair path (_ensure_cuda_torch) installs torch/torchvision/ torchaudio from an exclusive --index-url, so _CUDA_TORCH_PKG_SPEC decides exactly which torch the Studio venv gets. It was capped at torch<2.11.0, so on a cu128/cu130 host the venv resolved torch 2.10.x even though the CUDA indexes now publish torch 2.11.0. That left the Studio venv a torch minor behind the torch 2.11.0 Docker base image, so the CUDA dedup step would relink base libs under a mismatched torch. Raise the upper bound to <2.12.0 (torchvision <0.27.0, torchaudio <2.12.0) so the CUDA install path lands on torch 2.11.x, matching the rocm7.2 spec and the base image. The torchao selector already maps torch 2.11 -> torchao 0.17.0, and _ensure_flash_attn degrades gracefully when no prebuilt wheel matches (Blackwell skips it outright; non-Blackwell prints a warning and continues), so no other pin needs to move. Add test_cuda_torch_spec.py to lock the bound (torch 2.11.x in, 2.12.x out) and assert the CUDA and rocm7.2 upper bounds stay in lockstep. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * test: use zip(strict=True) so a spec length mismatch fails loudly * install.sh: widen the CUDA torch ceiling to <2.12.0 so a fresh install matches the base Raising _CUDA_TORCH_PKG_SPEC alone was not enough: that spec only feeds _ensure_cuda_torch(), the ROCm-poisoning repair path that early-returns on a normal NVIDIA host. A fresh CUDA install (including the studio Docker build, which runs `bash install.sh --local`) takes its torch from install.sh's TORCH_CONSTRAINT, which was still capped at torch>=2.4,<2.11.0, so cu12x/cu13x resolved torch 2.10.x and the venv landed a minor behind the torch 2.11.0 base image. Extend the existing `case "$TORCH_INDEX_URL"` block (which already relaxes rocm7.2) with a `*/cu[0-9]*` branch that widens the ceiling to <2.12.0, keeping the >=2.4 floor so an older CUDA index (e.g. cu118) that tops out below 2.11 still resolves. The CPU wheel and older ROCm tags stay on <2.11.0 (the glob does not match /cpu). torchvision/torchaudio are bare on this install line and resolve their compatible companions via wheel metadata, matching the rocm7.2 pattern. Add behavioral tests (Python + shell) exercising the case block: cu118/124/126/ 128/130 widen to <2.12.0, rocm7.2 stays 2.11.x, and /cpu plus older ROCm keep the default <2.11.0. * install.sh: key the CUDA torch widening off the index leaf, not the full URL The `*/cu[0-9]*` glob matched a `cu<digit>` segment anywhere in TORCH_INDEX_URL, so a custom UNSLOTH_PYTORCH_MIRROR whose base path contains e.g. cu128 but whose final leaf is cpu or an older ROCm tag would still widen TORCH_CONSTRAINT to <2.12.0, contradicting the block's own comment and letting a CPU / older-ROCm mirror resolve torch 2.11.x. Match on _torch_index_leaf (the final path segment the backend classification just above already computes) so only a real cu*/ rocm7.2 leaf is affected; cpu and older ROCm keep the default <2.11.0. Update the Python + shell tests to mirror the leaf-anchored case and add regression cases for a mirror base that contains cu128 but resolves to a cpu / rocm7.1 leaf. * install: freeze the torch trio during the with-deps unsloth installs Released unsloth wheels can pin an older torch than Step 1 installed (unsloth 2026.7.2 declares torch<2.11.0), so the with-deps resolve from PyPI silently downgrades the pinned +cuXXX torch trio to PyPI's default wheel. The flavor guard cannot catch every such swap: PyPI's torch 2.10 default is itself cu128-flavored, so the cuXXX tag comparison still matches while the version silently drops. Freeze the just-installed trio with uv --overrides (overrides replace dependency requirements during resolution), keeping torch 2.11.0+cuXXX in place while unsloth's other dependencies resolve normally. Verified on the cu128 path: without the override torch drops 2.11.0+cu128 -> 2.10.0; with it the trio survives and unsloth 2026.7.2 + unsloth-zoo install cleanly. * install: fold UV_OVERRIDE env files into the torch-trio overrides file The CLI --overrides flag is the command-line form of UV_OVERRIDE, so passing it replaced any overrides file already exported for the process; macOS arm64 exports UV_OVERRIDE=overrides-darwin-arm64.txt for the same generic install path and would have lost those pins. Concatenate any UV_OVERRIDE files into the temp trio file so both keep applying. * install: extend the torch-trio overrides guard to migrated installs Four follow-ups to the Step-2 --overrides guard, all empirically verified: 1. The migrated-environment with-deps unsloth install resolved unsloth>=2026.7.2 (which pins torch<2.11.0) without the overrides file, so a migrated CUDA venv on torch 2.11 was silently downgraded -- the exact bug this branch fixes on the fresh path. The overrides build is now a function (_build_unsloth_torch_overrides, reading the trio installed at call time) invoked by both with-deps paths; the migrated no-torch path installs --no-deps and stays unguarded. 2. The overrides temp file is now cleaned by the EXIT trap (same pattern as _UV_OVERRIDE_TMPDIR, pre-initialized empty so an inherited value can never reach the trap's rm); previously any Step-2 failure leaked it. 3. Folding UV_OVERRIDE files used cat, which joins the last requirement of a file lacking a trailing newline onto the next file's first requirement (reproduced: idna==3.10certifi==2025.1.31 makes uv fail parsing). 4. Inherited torch/torchvision/torchaudio override lines are now filtered out when folding: uv intersects duplicate overrides rather than last-wins (verified on uv 0.10.12: direct conflict is unsatisfiable, transitive conflict silently backtracks), so a conflicting inherited trio pin would break the resolve the generated exact pins protect. Both 3 and 4 are handled by a single newline-terminating awk filter that preserves non-trio overrides (torchmetrics, torchao, ...). test_unsloth_torch_override.sh extended: migrated-path coverage, trap assertion, and a functional fold test (14 checks). * installer: tighten comments * install: keep the existing torch release when re-running the installer Re-running `curl -fsSL https://unsloth.ai/install.sh | sh` over an existing install rebuilds the venv for clean state, which silently moved users to the newest torch in range (2.10 -> 2.11 once the constraint widened). A torch the user already validated must survive an unsloth update. Before the old venv is moved aside for rollback, its torch version is probed (last stdout line only, so sitecustomize noise cannot corrupt it). After the index leaf is chosen, _previous_torch_pin turns that version into a torch==X.Y.Z pin, but only when it cannot do harm: - cu*/cpu leaves only; rocm leaves keep their floors (rocm7.2 must land 2.11 for the Strix _grouped_mm fix) and the Radeon wheel-matching path is untouched. - The wheel's flavor tag must match the freshly chosen leaf, so a flavor change (cpu -> cuda, cu126 -> cu130) still installs the correct new build. - The base must look like a release, so probe noise never becomes a pin. - UNSLOTH_TORCH_UPGRADE=1 opts out and restores the old always-newest behavior; the substep line advertises it. The supported range is kept in _PREV_FALLBACK_CONSTRAINT: if the exact release is not resolvable from the chosen index (custom mirrors prune old wheels), the install warns and falls back to the newest supported release instead of failing the whole run. The later flavor-mismatch repair reuses TORCH_CONSTRAINT, so a mid-install clobber is repaired back to the kept release rather than the newest one. Verified end to end: a venv seeded with torch 2.10.0+cu130 re-run through the full installer finishes with torch 2.10.0+cu130 (previously 2.11.0+cu130). Tests: tests/sh/test_previous_torch_pin.sh covers keep/flavor-change/rocm/ noise/opt-out plus wiring (probe ordering before venv replacement, fallback present, SKIP_TORCH gate). * install: constrain kept torch pins to the supported window Review caught that _previous_torch_pin pinned the previous venv's torch on flavor match alone, so a release outside the installer's active range (a 2.3.x manual install below the >=2.4 floor, or a 2.12.x manual upgrade above the ceiling) replaced the bounds computed just above it and a rerun kept a torch the installer otherwise deliberately excludes. New _torch_release_in_window checks the probed base against the active TORCH_CONSTRAINT ("torch>=A.B[,<C.D.F]") at major.minor granularity, which is exact for the windows this script uses (ceilings are always X.Y.0; a non-.0 ceiling would only make it conservative). Anything unparseable answers no, so probe noise or a malformed window fails toward the supported range instead of becoming a pin. _previous_torch_pin takes the active constraint as a third argument and refuses out-of-window releases; the in-window keep behavior is unchanged. Tests: out-of-window rows (2.3.x floor, 2.12.x ceiling, boundary keeps, cpu and macOS windows, malformed/empty windows) plus direct _torch_release_in_window coverage. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
299 lines
12 KiB
Bash
299 lines
12 KiB
Bash
#!/bin/bash
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
|
# Tests for TORCH_CONSTRAINT variable in install.sh and tokenizers in no-torch-runtime.txt.
|
|
# Follows the same assertion pattern as test_mac_intel_compat.sh.
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
INSTALL_SH="$SCRIPT_DIR/../../install.sh"
|
|
INSTALL_PS1="$SCRIPT_DIR/../../install.ps1"
|
|
NO_TORCH_RT="$SCRIPT_DIR/../../studio/backend/requirements/no-torch-runtime.txt"
|
|
PASS=0
|
|
FAIL=0
|
|
|
|
assert_eq() {
|
|
_label="$1"; _expected="$2"; _actual="$3"
|
|
if [ "$_actual" = "$_expected" ]; then
|
|
echo " PASS: $_label"
|
|
PASS=$((PASS + 1))
|
|
else
|
|
echo " FAIL: $_label (expected '$_expected', got '$_actual')"
|
|
FAIL=$((FAIL + 1))
|
|
fi
|
|
}
|
|
|
|
assert_contains() {
|
|
_label="$1"; _haystack="$2"; _needle="$3"
|
|
if echo "$_haystack" | grep -qF "$_needle"; then
|
|
echo " PASS: $_label"
|
|
PASS=$((PASS + 1))
|
|
else
|
|
echo " FAIL: $_label (expected to find '$_needle')"
|
|
FAIL=$((FAIL + 1))
|
|
fi
|
|
}
|
|
|
|
assert_not_contains() {
|
|
_label="$1"; _haystack="$2"; _needle="$3"
|
|
if echo "$_haystack" | grep -qF "$_needle"; then
|
|
echo " FAIL: $_label (found '$_needle' but should not)"
|
|
FAIL=$((FAIL + 1))
|
|
else
|
|
echo " PASS: $_label"
|
|
PASS=$((PASS + 1))
|
|
fi
|
|
}
|
|
|
|
# ── Helper: create a mock python that reports a given minor version ──
|
|
make_mock_python() {
|
|
_minor="$1"
|
|
_venv_dir="$2"
|
|
mkdir -p "$_venv_dir/bin"
|
|
cat > "$_venv_dir/bin/python" <<MOCK_EOF
|
|
#!/bin/bash
|
|
if echo "\$@" | grep -q "sys.version_info.minor"; then
|
|
echo "$_minor"
|
|
else
|
|
echo "0"
|
|
fi
|
|
MOCK_EOF
|
|
chmod +x "$_venv_dir/bin/python"
|
|
}
|
|
|
|
# ── Helper: run the TORCH_CONSTRAINT snippet with given params ──
|
|
run_constraint_snippet() {
|
|
_skip_torch="$1"
|
|
_os="$2"
|
|
_arch="$3"
|
|
_py_minor="$4"
|
|
_venv_dir="$5"
|
|
|
|
make_mock_python "$_py_minor" "$_venv_dir"
|
|
|
|
bash -c "
|
|
SKIP_TORCH=\"$_skip_torch\"
|
|
OS=\"$_os\"
|
|
_ARCH=\"$_arch\"
|
|
VENV_DIR=\"$_venv_dir\"
|
|
TORCH_CONSTRAINT=\"torch>=2.4,<2.11.0\"
|
|
if [ \"\$SKIP_TORCH\" = false ] && [ \"\$OS\" = \"macos\" ] && [ \"\$_ARCH\" = \"arm64\" ]; then
|
|
_PY_MINOR=\$(\"\$VENV_DIR/bin/python\" -c \"import sys; print(sys.version_info.minor)\" 2>/dev/null || echo \"0\")
|
|
if [ \"\$_PY_MINOR\" -ge 13 ] 2>/dev/null; then
|
|
TORCH_CONSTRAINT=\"torch>=2.6,<2.11.0\"
|
|
fi
|
|
fi
|
|
echo \"\$TORCH_CONSTRAINT\"
|
|
" 2>/dev/null
|
|
}
|
|
|
|
# ======================================================================
|
|
# Structural checks
|
|
# ======================================================================
|
|
echo "=== Structural: TORCH_CONSTRAINT in install.sh ==="
|
|
|
|
_SH_CONTENT=$(cat "$INSTALL_SH")
|
|
|
|
_count=$(grep -c 'TORCH_CONSTRAINT="torch>=2.4,<2.11.0"' "$INSTALL_SH" || true)
|
|
assert_eq "default TORCH_CONSTRAINT assignment exists" "1" "$_count"
|
|
|
|
_count=$(grep -c 'TORCH_CONSTRAINT="torch>=2.6,<2.11.0"' "$INSTALL_SH" || true)
|
|
assert_eq "tightened TORCH_CONSTRAINT assignment exists" "1" "$_count"
|
|
|
|
_count=$(grep -c '"\$TORCH_CONSTRAINT"' "$INSTALL_SH" || true)
|
|
_has_var=$([ "$_count" -ge 1 ] && echo "yes" || echo "no")
|
|
assert_eq "\$TORCH_CONSTRAINT used in pip install" "yes" "$_has_var"
|
|
|
|
# Hardcoded torch>=2.4,<2.11.0 should only appear once (the default assignment)
|
|
_hardcoded=$(grep -c '"torch>=2.4,<2.11.0"' "$INSTALL_SH" || true)
|
|
assert_eq "hardcoded torch>=2.4 appears exactly once" "1" "$_hardcoded"
|
|
|
|
# A fresh CUDA install widens the ceiling to <2.12.0 so cu12x/cu13x land torch
|
|
# 2.11.x (matches the base image and _CUDA_TORCH_PKG_SPEC).
|
|
_cuda_widen=$(grep -c 'TORCH_CONSTRAINT="torch>=2.4,<2.12.0"' "$INSTALL_SH" || true)
|
|
assert_eq "CUDA TORCH_CONSTRAINT widened to <2.12.0" "1" "$_cuda_widen"
|
|
|
|
# Widening keys off the final leaf (_torch_index_leaf), not the full URL, so a
|
|
# mirror base path with cu*/rocm7.2 but a cpu/older-rocm leaf is not mis-widened.
|
|
_cuda_case=$(grep -c 'cu\[0-9\]\*)' "$INSTALL_SH" || true)
|
|
_has_cuda_case=$([ "$_cuda_case" -ge 1 ] && echo "yes" || echo "no")
|
|
assert_eq "cu* index case adjusts TORCH_CONSTRAINT" "yes" "$_has_cuda_case"
|
|
_leaf_case=$(grep -c 'case "\$_torch_index_leaf" in' "$INSTALL_SH" || true)
|
|
_has_leaf_constraint=$([ "$_leaf_case" -ge 2 ] && echo "yes" || echo "no")
|
|
assert_eq "constraint case anchors on _torch_index_leaf" "yes" "$_has_leaf_constraint"
|
|
|
|
echo ""
|
|
echo "=== Structural: tokenizers in no-torch-runtime.txt ==="
|
|
|
|
# Package-name boundary is anything not valid in a PEP 508 name, or EOL.
|
|
# Covers `tokenizers`, `tokenizers<=0.23.0`, `tokenizers[extra]`,
|
|
# `tokenizers; python_version<"3.13"`, etc., but NOT `tokenizers-foo`.
|
|
_TOK_RE='^tokenizers([^a-zA-Z0-9._-]|$)'
|
|
|
|
_has_tokenizers=$(grep -cE "$_TOK_RE" "$NO_TORCH_RT" || true)
|
|
assert_eq "tokenizers package listed" "1" "$_has_tokenizers"
|
|
|
|
# Regression guard for #5359: the tokenizers line must carry an upper
|
|
# bound that excludes 0.23.1+. transformers in the allowed 4.56..5.3
|
|
# window rejects 0.23.1 at import time with
|
|
# `tokenizers<=0.23.0,>=0.22.0 is required, but found 0.23.1`.
|
|
# Accept both `<=0.23.0` and the functionally equivalent `<0.23.1`.
|
|
# Two-stage grep: pick lines that start with the tokenizers package
|
|
# name (PEP 508 name boundary), then require a safe upper bound.
|
|
_has_safe_pin=$(grep -E "$_TOK_RE" "$NO_TORCH_RT" \
|
|
| grep -cE '(<=[[:space:]]*0\.23\.0|<[[:space:]]*0\.23\.1)' \
|
|
|| true)
|
|
assert_eq "tokenizers pinned with upper bound excluding 0.23.1+" "1" "$_has_safe_pin"
|
|
|
|
# tokenizers before transformers
|
|
_tok_line=$(grep -nE "$_TOK_RE" "$NO_TORCH_RT" | head -1 | cut -d: -f1)
|
|
_tf_line=$(grep -n '^transformers' "$NO_TORCH_RT" | head -1 | cut -d: -f1)
|
|
_tok_first=$([ "$_tok_line" -lt "$_tf_line" ] && echo "yes" || echo "no")
|
|
assert_eq "tokenizers before transformers" "yes" "$_tok_first"
|
|
|
|
# torch itself NOT in no-torch file
|
|
_has_torch=$(grep -c '^torch$' "$NO_TORCH_RT" || true)
|
|
assert_eq "torch not in no-torch-runtime.txt" "0" "$_has_torch"
|
|
|
|
echo ""
|
|
echo "=== Structural: install.ps1 unchanged ==="
|
|
|
|
_PS1_CONTENT=$(cat "$INSTALL_PS1")
|
|
_ps1_has_var=$(echo "$_PS1_CONTENT" | grep -c 'TORCH_CONSTRAINT\|TorchConstraint' || true)
|
|
assert_eq "install.ps1 has no TORCH_CONSTRAINT variable" "0" "$_ps1_has_var"
|
|
|
|
_ps1_hardcoded=$(echo "$_PS1_CONTENT" | grep -c '"torch>=2.4,<2.11.0"' || true)
|
|
_ps1_has_hc=$([ "$_ps1_hardcoded" -ge 1 ] && echo "yes" || echo "no")
|
|
assert_eq "install.ps1 has hardcoded torch constraint" "yes" "$_ps1_has_hc"
|
|
|
|
# ======================================================================
|
|
# Runtime: mocked platform/version combos
|
|
# ======================================================================
|
|
echo ""
|
|
echo "=== Runtime: TORCH_CONSTRAINT with mocked inputs ==="
|
|
|
|
TMPDIR_BASE=$(mktemp -d)
|
|
trap 'rm -rf "$TMPDIR_BASE"' EXIT
|
|
|
|
# 1. arm64 macOS py3.13 -> tightened
|
|
_result=$(run_constraint_snippet false macos arm64 13 "$TMPDIR_BASE/v1")
|
|
assert_eq "arm64+macos+py313 -> tightened" "torch>=2.6,<2.11.0" "$_result"
|
|
|
|
# 2. arm64 macOS py3.14 -> tightened (future-proofed)
|
|
_result=$(run_constraint_snippet false macos arm64 14 "$TMPDIR_BASE/v2")
|
|
assert_eq "arm64+macos+py314 -> tightened" "torch>=2.6,<2.11.0" "$_result"
|
|
|
|
# 3. arm64 macOS py3.12 -> default
|
|
_result=$(run_constraint_snippet false macos arm64 12 "$TMPDIR_BASE/v3")
|
|
assert_eq "arm64+macos+py312 -> default" "torch>=2.4,<2.11.0" "$_result"
|
|
|
|
# 4. arm64 macOS py3.11 -> default
|
|
_result=$(run_constraint_snippet false macos arm64 11 "$TMPDIR_BASE/v4")
|
|
assert_eq "arm64+macos+py311 -> default" "torch>=2.4,<2.11.0" "$_result"
|
|
|
|
# 5. Linux x86_64 py3.13 -> default (Linux unaffected)
|
|
_result=$(run_constraint_snippet false linux x86_64 13 "$TMPDIR_BASE/v5")
|
|
assert_eq "linux+x86_64+py313 -> default" "torch>=2.4,<2.11.0" "$_result"
|
|
|
|
# 6. Linux aarch64 py3.13 -> default (guard checks OS=macos)
|
|
_result=$(run_constraint_snippet false linux aarch64 13 "$TMPDIR_BASE/v6")
|
|
assert_eq "linux+aarch64+py313 -> default" "torch>=2.4,<2.11.0" "$_result"
|
|
|
|
# 7. Intel Mac x86_64 py3.12 -> default (arch mismatch)
|
|
_result=$(run_constraint_snippet false macos x86_64 12 "$TMPDIR_BASE/v7")
|
|
assert_eq "macos+x86_64+py312 -> default" "torch>=2.4,<2.11.0" "$_result"
|
|
|
|
# 8. SKIP_TORCH=true arm64 macOS py3.13 -> block skipped, default
|
|
_result=$(run_constraint_snippet true macos arm64 13 "$TMPDIR_BASE/v8")
|
|
assert_eq "SKIP_TORCH=true -> default" "torch>=2.4,<2.11.0" "$_result"
|
|
|
|
# 9. WSL py3.13 -> default
|
|
_result=$(run_constraint_snippet false wsl x86_64 13 "$TMPDIR_BASE/v9")
|
|
assert_eq "wsl+py313 -> default" "torch>=2.4,<2.11.0" "$_result"
|
|
|
|
# 10. py_minor=0 (failed query fallback) -> default
|
|
_result=$(run_constraint_snippet false macos arm64 0 "$TMPDIR_BASE/v10")
|
|
assert_eq "py_minor=0 fallback -> default" "torch>=2.4,<2.11.0" "$_result"
|
|
|
|
# 11. Boundary: py_minor=12 -> NOT tightened
|
|
_result=$(run_constraint_snippet false macos arm64 12 "$TMPDIR_BASE/v11")
|
|
assert_eq "boundary py_minor=12 -> default" "torch>=2.4,<2.11.0" "$_result"
|
|
|
|
# 12. Boundary: py_minor=13 -> tightened
|
|
_result=$(run_constraint_snippet false macos arm64 13 "$TMPDIR_BASE/v12")
|
|
assert_eq "boundary py_minor=13 -> tightened" "torch>=2.6,<2.11.0" "$_result"
|
|
|
|
# 13. Intel Mac py3.13 -> default (arch=x86_64, not arm64)
|
|
_result=$(run_constraint_snippet false macos x86_64 13 "$TMPDIR_BASE/v13")
|
|
assert_eq "macos+x86_64+py313 -> default" "torch>=2.4,<2.11.0" "$_result"
|
|
|
|
# ======================================================================
|
|
# Mock uv integration
|
|
# ======================================================================
|
|
echo ""
|
|
echo "=== Mock uv: verify constraint passed to uv ==="
|
|
|
|
# arm64 + py313 -> uv receives torch>=2.6
|
|
_UV_LOG="$TMPDIR_BASE/uv_log_tight.txt"
|
|
make_mock_python 13 "$TMPDIR_BASE/uv_venv1"
|
|
cat > "$TMPDIR_BASE/mock_uv_tight" <<UVEOF
|
|
#!/bin/bash
|
|
echo "\$@" >> $_UV_LOG
|
|
UVEOF
|
|
chmod +x "$TMPDIR_BASE/mock_uv_tight"
|
|
|
|
bash -c "
|
|
SKIP_TORCH=false
|
|
OS=\"macos\"
|
|
_ARCH=\"arm64\"
|
|
VENV_DIR=\"$TMPDIR_BASE/uv_venv1\"
|
|
TORCH_CONSTRAINT=\"torch>=2.4,<2.11.0\"
|
|
if [ \"\$SKIP_TORCH\" = false ] && [ \"\$OS\" = \"macos\" ] && [ \"\$_ARCH\" = \"arm64\" ]; then
|
|
_PY_MINOR=\$(\"\$VENV_DIR/bin/python\" -c \"import sys; print(sys.version_info.minor)\" 2>/dev/null || echo \"0\")
|
|
if [ \"\$_PY_MINOR\" -ge 13 ] 2>/dev/null; then
|
|
TORCH_CONSTRAINT=\"torch>=2.6,<2.11.0\"
|
|
fi
|
|
fi
|
|
\"$TMPDIR_BASE/mock_uv_tight\" pip install --python \"\$VENV_DIR/bin/python\" \"\$TORCH_CONSTRAINT\" torchvision torchaudio
|
|
" 2>/dev/null
|
|
_uv_got=$(cat "$_UV_LOG" 2>/dev/null || echo "")
|
|
assert_contains "mock uv arm64+py313 receives torch>=2.6" "$_uv_got" "torch>=2.6,<2.11.0"
|
|
|
|
# arm64 + py312 -> uv receives torch>=2.4
|
|
_UV_LOG2="$TMPDIR_BASE/uv_log_default.txt"
|
|
make_mock_python 12 "$TMPDIR_BASE/uv_venv2"
|
|
cat > "$TMPDIR_BASE/mock_uv_default" <<UVEOF
|
|
#!/bin/bash
|
|
echo "\$@" >> $_UV_LOG2
|
|
UVEOF
|
|
chmod +x "$TMPDIR_BASE/mock_uv_default"
|
|
|
|
bash -c "
|
|
SKIP_TORCH=false
|
|
OS=\"macos\"
|
|
_ARCH=\"arm64\"
|
|
VENV_DIR=\"$TMPDIR_BASE/uv_venv2\"
|
|
TORCH_CONSTRAINT=\"torch>=2.4,<2.11.0\"
|
|
if [ \"\$SKIP_TORCH\" = false ] && [ \"\$OS\" = \"macos\" ] && [ \"\$_ARCH\" = \"arm64\" ]; then
|
|
_PY_MINOR=\$(\"\$VENV_DIR/bin/python\" -c \"import sys; print(sys.version_info.minor)\" 2>/dev/null || echo \"0\")
|
|
if [ \"\$_PY_MINOR\" -ge 13 ] 2>/dev/null; then
|
|
TORCH_CONSTRAINT=\"torch>=2.6,<2.11.0\"
|
|
fi
|
|
fi
|
|
\"$TMPDIR_BASE/mock_uv_default\" pip install --python \"\$VENV_DIR/bin/python\" \"\$TORCH_CONSTRAINT\" torchvision torchaudio
|
|
" 2>/dev/null
|
|
_uv_got2=$(cat "$_UV_LOG2" 2>/dev/null || echo "")
|
|
assert_contains "mock uv arm64+py312 receives torch>=2.4" "$_uv_got2" "torch>=2.4,<2.11.0"
|
|
|
|
# ======================================================================
|
|
# Summary
|
|
# ======================================================================
|
|
echo ""
|
|
echo "=== Results ==="
|
|
echo " PASS: $PASS"
|
|
echo " FAIL: $FAIL"
|
|
if [ "$FAIL" -gt 0 ]; then
|
|
echo "FAILED"
|
|
exit 1
|
|
fi
|
|
echo "ALL PASSED"
|