Fix cookbook pip installs in venvs (#723)

This commit is contained in:
hawktuahs
2026-06-02 08:01:59 +05:30
committed by GitHub
parent e152a339d1
commit a2f6183c4a
3 changed files with 34 additions and 6 deletions

View File

@@ -148,6 +148,19 @@ def _local_tooling_path_export(executable: str) -> str:
return f'export PATH="{esc}:$PATH"'
def _pip_install_fallback_chain(package: str, *, python_cmd: str = "python3 -m pip", upgrade: bool = False) -> str:
"""Build a bash pip install fallback chain.
Try the active interpreter/environment first. `--user` is invalid inside
many venvs, so keep the user-site fallback for PEP-668 system Pythons only
after the venv-safe attempt has failed.
"""
upgrade_flag = " -U" if upgrade else ""
base = f"{python_cmd} install -q{upgrade_flag} {package} 2>/dev/null"
user = f"{python_cmd} install --user --break-system-packages -q{upgrade_flag} {package} 2>/dev/null"
return f"{base} || {user}"
def _cached_model_scan_script(model_dirs: list[str] | None = None) -> str:
"""Build the standalone Python scanner used by /api/model/cached."""
lines = [

View File

@@ -38,7 +38,7 @@ from routes.cookbook_helpers import (
_ps_squote, _bash_squote, _validate_serve_cmd, _parse_serve_phase,
_safe_env_prefix, _local_tooling_path_export, _append_serve_preflight_exit_lines,
_append_serve_exit_code_lines, _cached_model_scan_script,
ModelDownloadRequest, ServeRequest,
_pip_install_fallback_chain, ModelDownloadRequest, ServeRequest,
)
_HF_TOKEN_STATUS_SNIPPET = (
@@ -432,12 +432,12 @@ def setup_cookbook_routes() -> APIRouter:
# throughput. Retries set disable_hf_transfer to fall back to the plain,
# slower-but-reliable downloader (resumes cleanly from the .incomplete files).
# Use `python3 -m pip` not `pip` — macOS has no bare `pip` command.
lines.append("command -v hf >/dev/null 2>&1 || python3 -m pip install --user --break-system-packages -q -U huggingface_hub 2>/dev/null || python3 -m pip install -q -U huggingface_hub 2>/dev/null")
lines.append(f"command -v hf >/dev/null 2>&1 || {_pip_install_fallback_chain('huggingface_hub', upgrade=True)}")
if req.disable_hf_transfer:
lines.append("export HF_HUB_ENABLE_HF_TRANSFER=0")
lines.append("export HF_HUB_DOWNLOAD_MAX_WORKERS=4")
else:
lines.append("python3 -c 'import hf_transfer' 2>/dev/null || python3 -m pip install --user --break-system-packages -q hf_transfer 2>/dev/null || python3 -m pip install -q hf_transfer 2>/dev/null")
lines.append(f"python3 -c 'import hf_transfer' 2>/dev/null || {_pip_install_fallback_chain('hf_transfer')}")
lines.append("python3 -c 'import hf_transfer' 2>/dev/null && export HF_HUB_ENABLE_HF_TRANSFER=1")
lines.append("export HF_HUB_DOWNLOAD_MAX_WORKERS=8")
@@ -533,8 +533,8 @@ def setup_cookbook_routes() -> APIRouter:
runner_lines.append('export PATH="$HOME/.local/bin:$PATH"')
# Install hf CLI + hf_transfer best-effort so future runs get the fast path.
# Use --break-system-packages on PEP-668 systems (Arch, newer Debian) so it doesn't bail.
runner_lines.append("command -v hf >/dev/null 2>&1 || pip install --user --break-system-packages -q -U huggingface_hub 2>/dev/null || pip install -q -U huggingface_hub 2>/dev/null")
runner_lines.append("python3 -c 'import hf_transfer' 2>/dev/null || pip install --user --break-system-packages -q hf_transfer 2>/dev/null || pip install -q hf_transfer 2>/dev/null")
runner_lines.append(f"command -v hf >/dev/null 2>&1 || {_pip_install_fallback_chain('huggingface_hub', python_cmd='pip', upgrade=True)}")
runner_lines.append(f"python3 -c 'import hf_transfer' 2>/dev/null || {_pip_install_fallback_chain('hf_transfer', python_cmd='pip')}")
runner_lines.append("python3 -c 'import hf_transfer' 2>/dev/null && export HF_HUB_ENABLE_HF_TRANSFER=1")
runner_lines.append("export HF_HUB_DOWNLOAD_MAX_WORKERS=8")
# Surface whether the HF token actually reached THIS server, so a gated
@@ -975,7 +975,7 @@ def setup_cookbook_routes() -> APIRouter:
runner_lines.append(' # If the native build failed, fall back to the Python bindings.')
runner_lines.append(' if ! command -v llama-server &>/dev/null && ! python3 -c "import llama_cpp" 2>/dev/null; then')
runner_lines.append(' echo "llama-server build failed — installing Python bindings as fallback..."')
runner_lines.append(' pip install --user --break-system-packages -q llama-cpp-python 2>/dev/null || pip install -q llama-cpp-python 2>/dev/null || true')
runner_lines.append(f" {_pip_install_fallback_chain('llama-cpp-python', python_cmd='pip')} || true")
runner_lines.append(' fi')
runner_lines.append('fi')
elif "ollama" in req.cmd:

View File

@@ -10,6 +10,7 @@ from routes.cookbook_helpers import (
_append_serve_exit_code_lines,
_append_serve_preflight_exit_lines,
_local_tooling_path_export,
_pip_install_fallback_chain,
_safe_env_prefix,
_validate_gpus,
_validate_repo_id,
@@ -82,6 +83,20 @@ def test_local_tooling_path_export_preserves_spaces_and_expands_path():
assert line.endswith(':$PATH"') # $PATH stays expandable in double quotes
def test_pip_install_fallback_chain_prefers_venv_safe_install():
chain = _pip_install_fallback_chain("huggingface_hub", upgrade=True)
assert chain.startswith("python3 -m pip install -q -U huggingface_hub")
assert "|| python3 -m pip install --user --break-system-packages -q -U huggingface_hub" in chain
def test_pip_install_fallback_chain_allows_custom_python_command():
chain = _pip_install_fallback_chain("hf_transfer", python_cmd="pip", upgrade=False)
assert chain == (
"pip install -q hf_transfer 2>/dev/null || "
"pip install --user --break-system-packages -q hf_transfer 2>/dev/null"
)
def test_serve_preflight_failure_keeps_tmux_pane_visible():
"""Dependency preflight failures should remain visible in tmux output.