Files
wehub-resource-sync e93507a09c
Lockfile supply-chain audit / lockfile supply-chain audit (push) Has been cancelled
Windows Studio GGUF CI / GPU prebuilt resolves without Visual Studio (push) Has been cancelled
Windows Studio GGUF CI / setup.ps1 unit tests (VS 2026 / CMake guard) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2022) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-2025-vs2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-latest) (push) Has been cancelled
Windows Studio Update CI / Studio Updating Tests (push) Has been cancelled
Wheel CI / Wheel build + content sanity + import smoke (push) Has been cancelled
Lint CI / Source lint (Python + shell + YAML + JSON + safety nets) (push) Has been cancelled
MLX CI on Mac M1 / dispatch (push) Has been cancelled
Security audit / advisory audit (pip + npm + cargo) (push) Has been cancelled
Security audit / pip scan-packages :: extras (push) Has been cancelled
Security audit / pip scan-packages :: studio (push) Has been cancelled
Security audit / pip scan-packages :: hf-stack (push) Has been cancelled
Security audit / npm scan-packages (Studio frontend tarballs) (push) Has been cancelled
Security audit / workflow-trigger lint (pull_request_target / cache-poisoning) (push) Has been cancelled
Security audit / pytest tests/security (push) Has been cancelled
Security audit / npm provenance + new install-script diff (push) Has been cancelled
Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Backend CI / (Python 3.10) (push) Has been cancelled
Backend CI / (Python 3.11) (push) Has been cancelled
Backend CI / (Python 3.12) (push) Has been cancelled
Backend CI / (Python 3.13) (push) Has been cancelled
Backend CI / Repo tests (CPU) (push) Has been cancelled
Frontend CI / Frontend build + bundle sanity (push) Has been cancelled
Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Mac Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Mac Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-14) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15-intel) (push) Has been cancelled
Mac Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26-intel) (push) Has been cancelled
Mac Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Tauri CI / Tauri Linux debug build (no codesign) (push) Has been cancelled
Mac Studio Update CI / Studio Updating Tests (push) Has been cancelled
Studio UI CI / Chat UI Tests (push) Has been cancelled
Windows Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Windows Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Update CI / Studio Updating Tests (push) Has been cancelled
Core / Core (HF=default + TRL=default) (push) Has been cancelled
Core / Core (HF=4.57.6 + TRL<1) (push) Has been cancelled
Core / Core (HF=latest + TRL=latest) (push) Has been cancelled
Core / llama.cpp build + smoke (push) Has been cancelled
Windows Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Windows Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Windows Studio GGUF CI / JSON, images (push) Has been cancelled
Windows Studio GGUF CI / Studio install + inference without Visual Studio (push) Has been cancelled
Studio export capability / capability (macos-latest) (push) Has been cancelled
Studio export capability / capability (ubuntu-latest) (push) Has been cancelled
Studio export capability / capability (windows-latest) (push) Has been cancelled
Cross-platform parity / parity (macos-latest) (push) Has been cancelled
Cross-platform parity / parity (windows-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Studio load-orchestrator CI / test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:59:56 +08:00

232 lines
7.6 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
from __future__ import annotations
import functools
import json
import logging
import platform
import shutil
import subprocess
import sys
import urllib.error
import urllib.request
from typing import Callable
from utils.native_path_leases import child_env_without_native_path_secret
from utils.subprocess_compat import windows_hidden_subprocess_kwargs
_logger = logging.getLogger(__name__)
FLASH_ATTN_RELEASE_BASE_URL = "https://github.com/Dao-AILab/flash-attention/releases/download"
@functools.lru_cache(maxsize = 1)
def has_blackwell_gpu() -> bool:
"""Return True if any visible NVIDIA GPU has compute capability >= 10.0 (Blackwell).
Cached for the process lifetime; tests mocking nvidia-smi must call
``has_blackwell_gpu.cache_clear()`` first.
"""
# Detection disabled for now: Dao-AILab ships Blackwell (sm_100+) flash-attn
# wheels and url_exists() already gates resolution, so we no longer skip
# flash-attn on Blackwell. The nvidia-smi probe below is kept for possible
# future arch-based gating; drop this early return to re-enable it.
return False
exe = shutil.which("nvidia-smi")
if not exe:
return False
try:
result = subprocess.run(
[exe, "--query-gpu=compute_cap", "--format=csv,noheader"],
stdout = subprocess.PIPE,
stderr = subprocess.DEVNULL,
text = True,
timeout = 10,
env = child_env_without_native_path_secret(),
)
except (OSError, subprocess.TimeoutExpired):
return False
if result.returncode != 0:
return False
for line in result.stdout.splitlines():
cap = line.strip()
if not cap:
continue
major_part = cap.split(".", 1)[0]
try:
major = int(major_part)
except ValueError:
continue
if major >= 10:
return True
return False
def linux_wheel_platform_tag() -> str | None:
machine = platform.machine().lower()
if sys.platform.startswith("linux"):
if machine in {"x86_64", "amd64"}:
return "linux_x86_64"
if machine in {"aarch64", "arm64"}:
return "linux_aarch64"
# No prebuilt wheels published for macOS or Windows
return None
def probe_torch_wheel_env(*, timeout: int | None = None) -> dict[str, str] | None:
platform_tag = linux_wheel_platform_tag()
if platform_tag is None:
return None
try:
probe = subprocess.run(
[
sys.executable,
"-c",
(
"import json, sys, re, torch; "
"parts = torch.__version__.split('+', 1)[0].split('.')[:2]; "
"minor = re.sub(r'[^0-9].*', '', parts[1]) if len(parts) > 1 else '0'; "
"torch_mm = parts[0] + '.' + minor; "
"print(json.dumps({"
"'python_tag': f'cp{sys.version_info.major}{sys.version_info.minor}', "
"'torch_mm': torch_mm, "
"'cuda_major': str(int(str(torch.version.cuda).split('.', 1)[0])) if torch.version.cuda else '', "
"'hip_version': str(torch.version.hip) if getattr(torch.version, 'hip', None) else '', "
"'cxx11abi': str(torch._C._GLIBCXX_USE_CXX11_ABI).upper()"
"}))"
),
],
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
text = True,
timeout = timeout,
env = child_env_without_native_path_secret(),
**windows_hidden_subprocess_kwargs(),
)
except subprocess.TimeoutExpired:
return None
if probe.returncode != 0:
return None
try:
env = json.loads(probe.stdout.strip())
except json.JSONDecodeError:
return None
env["platform_tag"] = platform_tag
return env
# torch 2.11 has no native prebuilt wheels for flash-attn / causal-conv1d / mamba
# yet, but their torch 2.10 CUDA wheels load and pass the projects' own test suites
# on torch 2.11 (verified on B200: FA2 fwd/bwd, causal-conv1d, and mamba selective
# scan all match reference). Reuse the torch 2.10 wheels on torch 2.11 so a 2.11
# install still gets these prebuilt accelerators instead of building from source.
_PREBUILT_WHEEL_TORCH_MM = {"2.11": "2.10"}
def prebuilt_wheel_torch_mm(torch_mm: str) -> str:
"""Map a torch major.minor to the one whose prebuilt accelerator wheels to use."""
return _PREBUILT_WHEEL_TORCH_MM.get(torch_mm, torch_mm)
def direct_wheel_url(
*,
filename_prefix: str,
package_version: str,
release_tag: str,
release_base_url: str,
env: dict[str, str] | None,
) -> str | None:
if env is None or not env.get("cuda_major"):
return None
filename = (
f"{filename_prefix}-{package_version}"
f"+cu{env['cuda_major']}torch{prebuilt_wheel_torch_mm(env['torch_mm'])}"
f"cxx11abi{env['cxx11abi']}-{env['python_tag']}-{env['python_tag']}"
f"-{env['platform_tag']}.whl"
)
return f"{release_base_url}/{release_tag}/{filename}"
def flash_attn_package_version(torch_mm: str) -> str | None:
if torch_mm == "2.10":
return "2.8.1"
try:
major, minor = (int(part) for part in torch_mm.split(".", 1))
except ValueError:
return None
if major == 2 and 4 <= minor <= 9:
return "2.8.3"
return None
def flash_attn_wheel_url(env: dict[str, str] | None) -> str | None:
if env is None:
return None
package_version = flash_attn_package_version(prebuilt_wheel_torch_mm(env["torch_mm"]))
if package_version is None:
return None
return direct_wheel_url(
filename_prefix = "flash_attn",
package_version = package_version,
release_tag = f"v{package_version}",
release_base_url = FLASH_ATTN_RELEASE_BASE_URL,
env = env,
)
def install_wheel(
wheel_url: str,
*,
python_executable: str,
use_uv: bool,
uv_needs_system: bool = False,
run: Callable[..., subprocess.CompletedProcess[str]] = subprocess.run,
) -> list[tuple[str, subprocess.CompletedProcess[str]]]:
attempts: list[tuple[str, subprocess.CompletedProcess[str]]] = []
# Try uv first if available, then fall back to pip
if use_uv and shutil.which("uv"):
uv_cmd = ["uv", "pip", "install"]
if uv_needs_system:
uv_cmd.append("--system")
uv_cmd.extend(["--python", python_executable, "--no-deps", wheel_url])
result = run(
uv_cmd,
stdout = subprocess.PIPE,
stderr = subprocess.STDOUT,
text = True,
env = child_env_without_native_path_secret(),
)
attempts.append(("uv", result))
if result.returncode == 0:
return attempts
pip_cmd = [python_executable, "-m", "pip", "install", "--no-deps", wheel_url]
result = run(
pip_cmd,
stdout = subprocess.PIPE,
stderr = subprocess.STDOUT,
text = True,
env = child_env_without_native_path_secret(),
)
attempts.append(("pip", result))
return attempts
def url_exists(url: str) -> bool:
try:
request = urllib.request.Request(url, method = "HEAD")
with urllib.request.urlopen(request, timeout = 10):
return True
except urllib.error.HTTPError as exc:
_logger.debug("url_exists(%s): HTTP %s", url, exc.code)
except (urllib.error.URLError, TimeoutError) as exc:
_logger.debug("url_exists(%s): %s", url, exc)
return False