mirror of
https://github.com/unslothai/unsloth.git
synced 2026-07-09 15:58:41 +00:00
fix/uv-bytecode-timeout (#6166)
* fix/uv-bytecode-timeout * make sure that win installer upgrades uv for bytecode timeout * Clarify uv bytecode timeout comment in install.sh and install.ps1 * Read installer scripts as UTF-8 in parity test so it runs on Windows * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Prefer freshly installed uv when an older one shadows it on PATH --------- Co-authored-by: Daniel Han <danielhanchen@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
95a2627bf6
commit
e59ce0db04
3 changed files with 104 additions and 15 deletions
57
install.ps1
57
install.ps1
|
|
@ -1177,14 +1177,38 @@ shell.Run cmd, 0, False
|
|||
if ($SkipTorch) { $InitialGpuBranch = "no_torch" }
|
||||
Write-TauriDiag -GpuBranch $InitialGpuBranch -TorchIndexFamily "none" -PythonVersionForDiag $DiagPythonVersion
|
||||
|
||||
# ── Install uv if not present ──
|
||||
# ── Install uv ──
|
||||
Write-TauriLog "STEP" "Installing uv package manager"
|
||||
if (-not (Get-Command uv -ErrorAction SilentlyContinue)) {
|
||||
substep "installing uv package manager..."
|
||||
$UvMinVersion = "0.7.22"
|
||||
function Test-UvVersionOk {
|
||||
$cmd = Get-Command uv -ErrorAction SilentlyContinue
|
||||
if (-not $cmd) { return $false }
|
||||
try {
|
||||
$raw = (& uv --version 2>$null | Select-Object -First 1)
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
if ($raw -notmatch 'uv\s+([0-9]+(?:\.[0-9]+)+)') { return $false }
|
||||
try {
|
||||
return ([version]$Matches[1] -ge [version]$UvMinVersion)
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
if (-not (Test-UvVersionOk)) {
|
||||
if (Get-Command uv -ErrorAction SilentlyContinue) {
|
||||
substep "updating uv package manager..."
|
||||
} else {
|
||||
substep "installing uv package manager..."
|
||||
}
|
||||
if ($script:WingetAvailable) {
|
||||
$prevEAP = $ErrorActionPreference
|
||||
$ErrorActionPreference = "Continue"
|
||||
try { winget install --id=astral-sh.uv -e --source winget --accept-package-agreements --accept-source-agreements } catch {}
|
||||
try { winget upgrade --id=astral-sh.uv -e --source winget --accept-package-agreements --accept-source-agreements } catch {}
|
||||
if (-not (Test-UvVersionOk)) {
|
||||
try { winget install --id=astral-sh.uv -e --source winget --accept-package-agreements --accept-source-agreements } catch {}
|
||||
}
|
||||
$ErrorActionPreference = $prevEAP
|
||||
Refresh-SessionPath
|
||||
}
|
||||
|
|
@ -1192,19 +1216,40 @@ shell.Run cmd, 0, False
|
|||
# use Astral's official PowerShell installer. This is the only
|
||||
# supported path on hosts without winget (Windows ARM64 runners,
|
||||
# corporate machines without the Store, etc.).
|
||||
if (-not (Get-Command uv -ErrorAction SilentlyContinue)) {
|
||||
if (-not (Test-UvVersionOk)) {
|
||||
substep "installing uv via https://astral.sh/uv/install.ps1..." "Yellow"
|
||||
Invoke-Expression (Invoke-RestMethod -Uri "https://astral.sh/uv/install.ps1")
|
||||
Refresh-SessionPath
|
||||
}
|
||||
}
|
||||
|
||||
if (-not (Get-Command uv -ErrorAction SilentlyContinue)) {
|
||||
# A freshly installed uv can sit later on PATH than an older one (active
|
||||
# venv, Scoop/pipx shim). Prefer a just-installed uv from a known location.
|
||||
if (-not (Test-UvVersionOk)) {
|
||||
$origPath = $env:PATH
|
||||
foreach ($d in @($env:UV_INSTALL_DIR, $env:XDG_BIN_HOME,
|
||||
(Join-Path $env:USERPROFILE ".local\bin"),
|
||||
(Join-Path $env:LOCALAPPDATA "Microsoft\WinGet\Links"))) {
|
||||
if ($d -and (Test-Path $d)) {
|
||||
$env:PATH = "$d;$origPath"
|
||||
if (Test-UvVersionOk) { break }
|
||||
$env:PATH = $origPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not (Test-UvVersionOk)) {
|
||||
step "uv" "could not be installed" "Red"
|
||||
substep "Install it from https://docs.astral.sh/uv/" "Yellow"
|
||||
return (Exit-InstallFailure "uv could not be installed")
|
||||
}
|
||||
|
||||
# When bytecode compilation is enabled, large installs can exceed uv's 60s
|
||||
# default on slow machines. Default to 180s, preserving overrides ("0" disables).
|
||||
if (-not $env:UV_COMPILE_BYTECODE_TIMEOUT) {
|
||||
$env:UV_COMPILE_BYTECODE_TIMEOUT = "180"
|
||||
}
|
||||
|
||||
# ── Create venv (migrate old layout if possible, otherwise fresh) ──
|
||||
# Pass the resolved executable path to uv so it does not re-resolve
|
||||
# a version string back to a conda interpreter.
|
||||
|
|
|
|||
|
|
@ -1456,7 +1456,11 @@ fi
|
|||
|
||||
# ── Install uv ──
|
||||
tauri_log "STEP" "Installing uv package manager"
|
||||
UV_MIN_VERSION="0.7.14"
|
||||
UV_MIN_VERSION="0.7.22"
|
||||
|
||||
# When bytecode compilation is enabled, large installs can exceed uv's 60s default on slow machines. Default to 180s, preserving overrides ("0" disables).
|
||||
: "${UV_COMPILE_BYTECODE_TIMEOUT:=180}"
|
||||
export UV_COMPILE_BYTECODE_TIMEOUT
|
||||
|
||||
version_ge() {
|
||||
# returns 0 if $1 >= $2
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class TestNoTorchBackendAutoInInstallSh:
|
|||
"""
|
||||
|
||||
def test_no_torch_backend_auto_outside_fallback(self):
|
||||
lines = INSTALL_SH.read_text().splitlines()
|
||||
lines = INSTALL_SH.read_text(encoding = "utf-8").splitlines()
|
||||
# Fallback block: from "GPU detection failed" to the next "fi".
|
||||
fallback_start = None
|
||||
fallback_end = None
|
||||
|
|
@ -48,7 +48,7 @@ class TestNoTorchBackendAutoInInstallSh:
|
|||
|
||||
def test_fallback_uses_torch_backend_auto(self):
|
||||
"""The fallback branch should use --torch-backend=auto as recovery."""
|
||||
text = INSTALL_SH.read_text()
|
||||
text = INSTALL_SH.read_text(encoding = "utf-8")
|
||||
assert (
|
||||
"GPU detection failed" in text
|
||||
), "install.sh should have a fallback branch for when GPU detection fails"
|
||||
|
|
@ -58,13 +58,13 @@ class TestInstallShHasGpuDetection:
|
|||
"""install.sh must contain the get_torch_index_url function."""
|
||||
|
||||
def test_function_exists(self):
|
||||
text = INSTALL_SH.read_text()
|
||||
text = INSTALL_SH.read_text(encoding = "utf-8")
|
||||
assert (
|
||||
"get_torch_index_url()" in text
|
||||
), "install.sh is missing the get_torch_index_url() function"
|
||||
|
||||
def test_torch_index_url_assigned(self):
|
||||
text = INSTALL_SH.read_text()
|
||||
text = INSTALL_SH.read_text(encoding = "utf-8")
|
||||
assert (
|
||||
"TORCH_INDEX_URL=$(get_torch_index_url)" in text
|
||||
), "install.sh should assign TORCH_INDEX_URL from get_torch_index_url()"
|
||||
|
|
@ -115,8 +115,8 @@ class TestCudaMappingParity:
|
|||
|
||||
def test_same_cuda_suffixes(self):
|
||||
"""Both scripts should produce the same ordered list of CUDA index suffixes."""
|
||||
sh_text = INSTALL_SH.read_text()
|
||||
ps1_text = INSTALL_PS1.read_text()
|
||||
sh_text = INSTALL_SH.read_text(encoding = "utf-8")
|
||||
ps1_text = INSTALL_PS1.read_text(encoding = "utf-8")
|
||||
|
||||
sh_thresholds = self._extract_cuda_thresholds_sh(sh_text)
|
||||
ps1_thresholds = self._extract_cuda_thresholds_ps1(ps1_text)
|
||||
|
|
@ -134,13 +134,53 @@ class TestPyTorchMirrorEnvVar:
|
|||
"""Both install scripts must support the UNSLOTH_PYTORCH_MIRROR env var."""
|
||||
|
||||
def test_install_sh_has_mirror_var(self):
|
||||
text = INSTALL_SH.read_text()
|
||||
text = INSTALL_SH.read_text(encoding = "utf-8")
|
||||
assert (
|
||||
"UNSLOTH_PYTORCH_MIRROR" in text
|
||||
), "install.sh should reference UNSLOTH_PYTORCH_MIRROR"
|
||||
|
||||
def test_install_ps1_has_mirror_var(self):
|
||||
text = INSTALL_PS1.read_text()
|
||||
text = INSTALL_PS1.read_text(encoding = "utf-8")
|
||||
assert (
|
||||
"UNSLOTH_PYTORCH_MIRROR" in text
|
||||
), "install.ps1 should reference UNSLOTH_PYTORCH_MIRROR"
|
||||
|
||||
|
||||
class TestUvBytecodeCompileTimeout:
|
||||
"""Installers should relax uv bytecode compilation timeout by default."""
|
||||
|
||||
@staticmethod
|
||||
def _version_tuple(version: str) -> tuple[int, ...]:
|
||||
return tuple(int(part) for part in version.split("."))
|
||||
|
||||
def test_install_sh_uses_uv_version_with_timeout_env(self):
|
||||
text = INSTALL_SH.read_text(encoding = "utf-8")
|
||||
match = re.search(r'^UV_MIN_VERSION="([^"]+)"$', text, re.MULTILINE)
|
||||
assert match, "install.sh should declare UV_MIN_VERSION"
|
||||
assert self._version_tuple(match.group(1)) >= self._version_tuple("0.7.22")
|
||||
|
||||
def test_install_ps1_uses_uv_version_with_timeout_env(self):
|
||||
text = INSTALL_PS1.read_text(encoding = "utf-8")
|
||||
match = re.search(r'^\s*\$UvMinVersion = "([^"]+)"$', text, re.MULTILINE)
|
||||
assert match, "install.ps1 should declare $UvMinVersion"
|
||||
assert self._version_tuple(match.group(1)) >= self._version_tuple("0.7.22")
|
||||
assert "function Test-UvVersionOk" in text
|
||||
assert "if (-not (Test-UvVersionOk))" in text
|
||||
|
||||
def test_install_sh_preserves_timeout_override(self):
|
||||
text = INSTALL_SH.read_text(encoding = "utf-8")
|
||||
assert (
|
||||
': "${UV_COMPILE_BYTECODE_TIMEOUT:=180}"' in text
|
||||
), "install.sh should default UV_COMPILE_BYTECODE_TIMEOUT without overwriting callers"
|
||||
assert (
|
||||
"export UV_COMPILE_BYTECODE_TIMEOUT" in text
|
||||
), "install.sh should export UV_COMPILE_BYTECODE_TIMEOUT for uv subprocesses"
|
||||
|
||||
def test_install_ps1_preserves_timeout_override(self):
|
||||
text = INSTALL_PS1.read_text(encoding = "utf-8")
|
||||
assert (
|
||||
"if (-not $env:UV_COMPILE_BYTECODE_TIMEOUT)" in text
|
||||
), "install.ps1 should preserve caller UV_COMPILE_BYTECODE_TIMEOUT overrides"
|
||||
assert (
|
||||
'$env:UV_COMPILE_BYTECODE_TIMEOUT = "180"' in text
|
||||
), "install.ps1 should default UV_COMPILE_BYTECODE_TIMEOUT"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue