From 9a1893760d4819492eef5ca959aa9200c64d5ff6 Mon Sep 17 00:00:00 2001 From: Tatlatat Date: Tue, 2 Jun 2026 10:23:20 +0700 Subject: [PATCH] fix(cookbook): skip pip --user fallback inside virtualenvs (#388) (#889) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dependency-install fallback chain unconditionally ran 'pip install --user', which fails inside a virtualenv (and as root in LXC/containers) with 'Can not perform a --user install. User site-packages are not visible in this virtualenv.' — even though the function's docstring already noted --user is invalid in venvs. Guard the --user fallback with a venv check so it only runs outside a venv (where --user is actually valid for PEP-668 system Pythons). Derive the venv probe interpreter from the install command (python for 'pip', python3 for 'pip3'/'python3 -m pip') so the check runs in pip's own environment. System PEP-668 installs keep the --user fallback; venv/LXC-root installs no longer hit the --user error. Updated the unit test for the new chain. Closes #388 --- routes/cookbook_helpers.py | 18 +++++++++++++++--- tests/test_cookbook_helpers.py | 5 +++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/routes/cookbook_helpers.py b/routes/cookbook_helpers.py index ffa2f0f..c646864 100644 --- a/routes/cookbook_helpers.py +++ b/routes/cookbook_helpers.py @@ -152,13 +152,25 @@ def _pip_install_fallback_chain(package: str, *, python_cmd: str = "python3 -m p """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. + many venvs, so only attempt the --user fallback when NOT inside a venv. """ 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}" + # Derive the python executable for the venv detection check. + # Must use the same interpreter that pip belongs to; hardcoding + # python3 breaks when pip lives in a venv that only has "python". + if " -m pip" in python_cmd: + python_exe = python_cmd.replace(" -m pip", "") + elif python_cmd.strip() == "pip": + python_exe = "python" + elif python_cmd.strip() == "pip3": + python_exe = "python3" + else: + python_exe = "python3" + venv_check = f'{python_exe} -c "import sys; sys.exit(0 if sys.prefix != sys.base_prefix else 1)"' + # venv_check exits 0 (true) when IN a venv; --user is only valid outside one. + return f"{base} || {{ {venv_check} || {user}; }}" def _cached_model_scan_script(model_dirs: list[str] | None = None) -> str: diff --git a/tests/test_cookbook_helpers.py b/tests/test_cookbook_helpers.py index ef1b2a5..5ce6650 100644 --- a/tests/test_cookbook_helpers.py +++ b/tests/test_cookbook_helpers.py @@ -92,8 +92,9 @@ def test_pip_install_fallback_chain_prefers_venv_safe_install(): 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" + 'pip install -q hf_transfer 2>/dev/null || { ' + 'python -c "import sys; sys.exit(0 if sys.prefix != sys.base_prefix else 1)"' + ' || pip install --user --break-system-packages -q hf_transfer 2>/dev/null; }' )