cu130onlytorch2110: pin the trio to +cu130 like the cu126/cu128 extras

A bare torch==2.11.0 range lets a configured CUDA-12 extra index win the
resolve: PEP 440 ranks the local build 2.11.0+cu126 above the unlabelled
2.11.0, so the cu130 extra could silently install cu126 wheels. An
===2.11.0 arbitrary-equality pin has the opposite problem: it rejects the
+cu130 local builds that an install from the official cu130 index
produces. Pinning ==2.11.0+cu130 matches the cu126/cu128 sibling extras
exactly: it accepts only the cu130 builds (all three wheels exist on
download.pytorch.org/whl/cu130) and fails the resolve loudly when no
cu130 index is configured instead of installing the wrong flavor.

_auto_install now appends the cu130 extra index for CUDA 13.0 the same
way it does for 12.6/12.8, and the extras test parametrizes cu130
alongside its siblings.
This commit is contained in:
Daniel Han 2026-07-12 11:36:04 +00:00
commit ed275cbd25
3 changed files with 20 additions and 35 deletions

View file

@ -363,17 +363,16 @@ cu128onlytorch2110 = [
"xformers @ https://download.pytorch.org/whl/cu128/xformers-0.0.35-py39-none-win_amd64.whl ; (sys_platform == 'win32')",
]
cu130onlytorch2110 = [
# No +cu130 local pin needed: torch 2.11's DEFAULT PyPI wheel is already CUDA
# 13.0, so a bare resolve lands on a cu130 torch that matches the cu130
# xformers below even without a dedicated index. Arbitrary equality (===)
# rather than a range: PEP 440 ranks a local build (2.11.0+cu126/+cu128)
# ABOVE the unlabelled 2.11.0, so with any CUDA-12 extra index configured a
# range would silently pair a CUDA-12 torch trio with the cu130 xformers
# (pip verified: torch>=2.11,<2.12 + --extra-index-url .../cu126 installs
# 2.11.0+cu126; torch===2.11.0 installs the unlabelled cu130 default).
"torch===2.11.0",
"torchvision===0.26.0",
"torchaudio===2.11.0",
# Pinned to the +cu130 local build like the cu126/cu128 extras: a bare range
# lets a configured CUDA-12 extra index win (PEP 440 ranks 2.11.0+cu126 above
# the unlabelled 2.11.0), and a ===2.11.0 pin would force-replace the trio on
# machines installed from the official cu130 index (whose wheels carry the
# +cu130 local tag). The exact +cu130 pins accept the official cu130-index
# install as-is and fail loudly anywhere the cu130 index is missing;
# _auto_install.py appends the matching index for every torch2110 CUDA extra.
"torch==2.11.0+cu130",
"torchvision==0.26.0+cu130",
"torchaudio==2.11.0+cu130",
"xformers @ https://download.pytorch.org/whl/cu130/xformers-0.0.35-py39-none-manylinux_2_28_x86_64.whl ; ('linux' in sys_platform)",
"xformers @ https://download.pytorch.org/whl/cu130/xformers-0.0.35-py39-none-win_amd64.whl ; (sys_platform == 'win32')",
]

View file

@ -3,8 +3,9 @@
torch 2.11's DEFAULT PyPI wheel is CUDA 13.0 (torch 2.10 defaulted to CUDA 12.x).
So the CUDA-12 `cuXXXonlytorch2110` extras must pin the torch trio to the matching
`+cuXXX` local build; a bare `torch>=2.11` there would resolve a cu130 torch from
PyPI alongside the cu126/cu128 xformers wheel and fail at import. The cu130 extra
needs no local pin because the bare default already lands on cu130.
PyPI alongside the cu126/cu128 xformers wheel and fail at import. The cu130 extra is
pinned to +cu130 too: a bare or ===-pinned spec either lets a foreign CUDA index
outrank the intended wheel or force-replaces official cu130-index installs.
Hermetic: only parses pyproject.toml, no network or install.
"""
@ -39,7 +40,7 @@ def _reqs(specs: list[str]) -> dict[str, Requirement]:
return out
@pytest.mark.parametrize("cuda", ["cu126", "cu128"])
@pytest.mark.parametrize("cuda", ["cu126", "cu128", "cu130"])
def test_cuda12_torch2110_pins_matching_local_build(cuda: str):
# Each of torch/torchvision/torchaudio must pin the exact +cuXXX local build
# so it can only resolve from the matching PyTorch CUDA index, never the
@ -54,20 +55,3 @@ def test_cuda12_torch2110_pins_matching_local_build(cuda: str):
xf = reqs["xformers"]
assert xf.url and f"/whl/{cuda}/" in xf.url, f"xformers not on the {cuda} index: {xf.url}"
def test_cu130_torch2110_uses_arbitrary_equality():
# cu130 matches torch 2.11's PyPI default, so no +cu130 local pin is needed
# (it could fail to resolve from PyPI's unlabelled default wheel). But a
# RANGE is not enough either: PEP 440 ranks a local build (2.11.0+cu126)
# above the unlabelled 2.11.0, so with any CUDA-12 extra index configured a
# range silently pairs a CUDA-12 trio with the cu130 xformers. Arbitrary
# equality (===) matches only the unlabelled release, excluding every
# +cuXXX local candidate.
expected = {"torch": "2.11.0", "torchvision": "0.26.0", "torchaudio": "2.11.0"}
reqs = _reqs(_extra("cu130onlytorch2110"))
for pkg in _TORCH_TRIO:
spec = str(reqs[pkg].specifier)
assert spec == f"==={expected[pkg]}", (
f"cu130onlytorch2110: {pkg} must pin ==={expected[pkg]} "
f"(excludes +cuXXX local builds), got '{spec}'"
)

View file

@ -41,8 +41,10 @@ else: raise RuntimeError(f"Torch = {v} too new!")
if v > V('2.6.9') and cuda not in ("11.8", "12.6", "12.8", "13.0"): raise RuntimeError(f"CUDA = {cuda} not supported!")
if v >= V('2.10.0') and cuda not in ("12.6", "12.8", "13.0"): raise RuntimeError(f"Torch 2.10 requires CUDA 12.6, 12.8, or 13.0! Got CUDA = {cuda}")
x = x.format(cuda.replace(".", ""), "-ampere" if False else "") # is_ampere is broken due to flash-attn
# The cu126/cu128 torch2110 extras pin torch==2.11.0+cuNNN, a local build that only
# resolves from the matching PyTorch CUDA index (torch 2.11's default PyPI wheel is
# CUDA 13.0), so add that index for exactly those CUDA-12 torch 2.11 environments.
extra_index = f' --extra-index-url https://download.pytorch.org/whl/cu{cuda.replace(".", "")}' if (x.endswith('-torch2110') and cuda in ("12.6", "12.8")) else ''
# The CUDA torch2110 extras pin the torch trio to the exact +cuNNN local build,
# which only resolves from the matching PyTorch CUDA index (a bare spec would let
# a configured foreign CUDA index outrank the intended wheel, since PEP 440 ranks
# any local build above the unlabelled release), so add that index for every
# CUDA torch 2.11 environment.
extra_index = f' --extra-index-url https://download.pytorch.org/whl/cu{cuda.replace(".", "")}' if (x.endswith('-torch2110') and cuda in ("12.6", "12.8", "13.0")) else ''
print(f'pip install --upgrade pip setuptools wheel && pip install --no-deps git+https://github.com/unslothai/unsloth-zoo.git && pip install "unsloth[{x}] @ git+https://github.com/unslothai/unsloth.git" --no-build-isolation{extra_index}')