Merge remote-tracking branch 'origin/main' into windows-torch-211

Reconcile PR #7256 (Windows torch 2.11 + release preservation, installer
comment reduction, torch 2.11 default line) with 77 commits of main install
rewrites. Base is main's newer install semantics; this branch's still-novel
contributions are layered on top.

Key decisions:
- install.ps1: kept main's rollback lifecycle (try/finally Restore-StudioVenvRollback,
  #7342) and the installed-version report (#7265); layered this branch's torch-2.11
  allowance (torch<2.12.0 on the Windows CUDA fresh-install, CPU fallback and flavor
  repairs), the release-preservation port (Get-InstalledTorchVersionRaw / kept-release
  installs / UNSLOTH_KEPT_TORCH handoff / torch-overrides freeze) and the Exit-InstallFailure
  UNSLOTH_KEPT_TORCH clear.
- install.sh: took main's newer AMD/Strix routing (per-arch index reroute #7264/#7300,
  runtime-less gfx inference #7305, KFD detection fix #7314, Radeon 8065S regex #7290,
  signal-restore trap #7342) and the #7365 unsloth pin bump; kept this branch's
  _TORCH_CEILING/_TORCHVISION_CEILING/_TORCHAUDIO_CEILING refactor widening the default
  ceiling to torch<2.12.0.
- studio/install_python_stack.py: deferred all five code conflicts to main's Strix
  inference logic (result is AST-identical to main; only comment reductions remain).
- studio/setup.ps1: took main's comment covering the whisper.cpp dictation markers
  (#7095); the UNSLOTH_KEPT_TORCH consumption handoff auto-merged intact.

Dropped as superseded by main: this branch's stale unsloth>=2026.7.4 pins (main #7365),
the older rocm7.1->rocm7.2 Strix reroute (main #7264/#7300), the narrow Radeon 80[0-9]0S
regex (main #7290), and the pre-inference has_hip_torch gate (main's rocm_torch_ready gate,
Codex P1 #7305). The two review-item fixes (grep -E in test_torch_constraint.sh,
UNSLOTH_KEPT_TORCH clear in Exit-InstallFailure) survive.
This commit is contained in:
danielhanchen 2026-07-24 11:24:55 +00:00
commit a14cc540ae
588 changed files with 58517 additions and 11322 deletions

View file

@ -0,0 +1,129 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved.
"""torch / torchcodec ABI guardrails (unslothai/unsloth#7225)."""
from __future__ import annotations
import importlib.util
import re
import sys
import types
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
PYPROJECT = REPO_ROOT / "pyproject.toml"
IMPORT_FIXES_PATH = REPO_ROOT / "unsloth" / "import_fixes.py"
def _load_import_fixes_module():
spec = importlib.util.spec_from_file_location(
"unsloth_import_fixes_under_test",
IMPORT_FIXES_PATH,
)
assert spec and spec.loader
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod
def test_pyproject_declares_torch210_audio_extra_with_python_gate():
text = PYPROJECT.read_text(encoding = "utf-8")
assert "audio-torch210 = [" in text
assert "torchcodec>=0.10.0,<0.11.0" in text
assert "python_version >= '3.10'" in text
assert "audio-torch290 = [" in text
assert "audio-torch280 = [" in text
assert "\naudio = [" not in text
def _stub_torch(monkeypatch, version: str):
torch_mod = types.ModuleType("torch")
torch_mod.__version__ = version
monkeypatch.setitem(sys.modules, "torch", torch_mod)
def test_torch210_extras_bundle_audio_torch210():
text = PYPROJECT.read_text(encoding = "utf-8")
for extra in (
"cu128-torch2100",
"cu126-ampere-torch2100",
"rocm72-torch2100",
):
match = re.search(rf"^{extra} = \[(.*?)^\]", text, re.MULTILINE | re.DOTALL)
assert match is not None, extra
assert "unsloth[audio-torch210]" in match.group(1)
def test_torchcodec_matrix_matches_notebook_validator():
from scripts import notebook_validator as nv
fixes = _load_import_fixes_module()
assert fixes._TORCH_TORCHCODEC_MINORS == nv.TORCH_TORCHCODEC
def test_torchcodec_exclusive_upper_bound():
fixes = _load_import_fixes_module()
assert fixes._torchcodec_exclusive_upper("0.10") == "<0.11.0"
assert fixes._torchcodec_exclusive_upper("0.9") == "<0.10.0"
def test_torch290_rejects_torchcodec_07(monkeypatch):
import importlib.metadata
fixes = _load_import_fixes_module()
_stub_torch(monkeypatch, "2.9.0+cu128")
monkeypatch.setattr(importlib.metadata, "version", lambda _name: "0.7.0")
hint = fixes._torchcodec_version_mismatch_hint()
assert hint is not None
assert "audio-torch210" not in hint
def test_torch280_accepts_torchcodec_07(monkeypatch):
import importlib.metadata
fixes = _load_import_fixes_module()
_stub_torch(monkeypatch, "2.8.0+cu128")
monkeypatch.setattr(importlib.metadata, "version", lambda _name: "0.7.0")
assert fixes._torchcodec_version_mismatch_hint() is None
def test_torch210_rejects_torchcodec_011(monkeypatch):
import importlib.metadata
fixes = _load_import_fixes_module()
_stub_torch(monkeypatch, "2.10.0+cu128")
monkeypatch.setattr(
importlib.metadata,
"version",
lambda _name: "0.11.0",
)
hint = fixes._torchcodec_version_mismatch_hint()
assert hint is not None
assert "torchcodec 0.11.0" in hint
assert "audio-torch210" in hint
assert "<0.11.0" in hint
assert "<11.0" not in hint
def test_torch210_accepts_torchcodec_010(monkeypatch):
import importlib.metadata
fixes = _load_import_fixes_module()
_stub_torch(monkeypatch, "2.10.0+cu128")
monkeypatch.setattr(
importlib.metadata,
"version",
lambda _name: "0.10.0+cu128",
)
assert fixes._torchcodec_version_mismatch_hint() is None
def test_import_fixes_loads_on_python39_syntax():
"""Regression: module must import on 3.9 (postponed annotations for str | None)."""
fixes = _load_import_fixes_module()
assert callable(fixes._torchcodec_version_mismatch_hint)