diff --git a/routes/shell_routes.py b/routes/shell_routes.py index ffa230c..cd9a5d9 100644 --- a/routes/shell_routes.py +++ b/routes/shell_routes.py @@ -127,6 +127,24 @@ def _docker_row_status(*, on_remote, in_container, installed, default_hint): return DockerRowStatus(applicable=True, install_hint=default_hint) +def _pip_dist_name(pkg: dict) -> str: + """Distribution name for importlib.metadata lookups. + + The Cookbook package catalog carries both the import name (``name``, e.g. + ``llama_cpp``) and the pip spec (``pip``, e.g. ``llama-cpp-python[server]``). + The distribution is NOT always the import name with underscores swapped for + dashes — ``llama_cpp`` ships in the ``llama-cpp-python`` distribution — so + derive it from the pip spec (stripping any ``[extras]`` and version markers) + and fall back to the munged import name only when no pip spec is declared. + """ + pip = (pkg.get("pip") or "").strip() + if pip: + base = re.split(r"[\[<>=!~;\s]", pip, maxsplit=1)[0].strip() + if base: + return base + return (pkg.get("name") or "").replace("_", "-") + + def _package_installed_from_probe(name: str, probe: dict) -> bool: """Return whether an optional dependency is usable by Cookbook. @@ -945,7 +963,7 @@ def setup_shell_routes() -> APIRouter: if pkg["name"] == "vllm": pkg["installed"] = shutil.which("vllm") is not None else: - importlib_metadata.version(pkg["name"].replace("_", "-")) + importlib_metadata.version(_pip_dist_name(pkg)) pkg["installed"] = True except ImportError: pkg["installed"] = False diff --git a/tests/test_cookbook_package_detection.py b/tests/test_cookbook_package_detection.py new file mode 100644 index 0000000..32aa7c9 --- /dev/null +++ b/tests/test_cookbook_package_detection.py @@ -0,0 +1,50 @@ +"""Local Cookbook dependency detection — distribution-name mapping (issue #1020). + +The Cookbook → Dependencies tab reported `llama-cpp-python[server]` as "not +installed" even when it was installed. The local check looked up distribution +metadata under `pkg["name"].replace("_", "-")` → "llama-cpp", but the import +module `llama_cpp` ships in the **llama-cpp-python** distribution, so +`importlib.metadata.version("llama-cpp")` raised PackageNotFoundError and the +package was marked missing. The fix derives the distribution name from the +package's declared pip spec instead. +""" + +from pathlib import Path + +from routes.shell_routes import _pip_dist_name + + +def test_llama_cpp_maps_to_llama_cpp_python_distribution(): + pkg = {"name": "llama_cpp", "pip": "llama-cpp-python[server]"} + assert _pip_dist_name(pkg) == "llama-cpp-python" + # The old behaviour (munging the import name) produced the wrong dist name. + assert _pip_dist_name(pkg) != "llama-cpp" + + +def test_extras_and_version_markers_are_stripped(): + assert _pip_dist_name({"name": "diffusers", "pip": "diffusers[torch]"}) == "diffusers" + assert _pip_dist_name({"name": "sglang", "pip": "sglang[all]"}) == "sglang" + assert _pip_dist_name({"name": "rembg", "pip": "rembg[gpu]"}) == "rembg" + assert _pip_dist_name({"name": "x", "pip": "foo>=1.2,<2"}) == "foo" + assert _pip_dist_name({"name": "y", "pip": "bar==1.0 ; python_version>='3.9'"}) == "bar" + + +def test_plain_names_pass_through(): + assert _pip_dist_name({"name": "vllm", "pip": "vllm"}) == "vllm" + assert _pip_dist_name({"name": "playwright", "pip": "playwright"}) == "playwright" + assert _pip_dist_name({"name": "hf_transfer", "pip": "hf_transfer"}) == "hf_transfer" + + +def test_falls_back_to_import_name_when_no_pip_spec(): + # System rows (tmux/docker) declare no pip spec; fall back to the munged name. + assert _pip_dist_name({"name": "some_mod", "pip": ""}) == "some-mod" + assert _pip_dist_name({"name": "tmux"}) == "tmux" + + +def test_route_uses_dist_name_helper_not_munged_import_name(): + """Lock the wiring: the local package check must look up metadata by the + derived distribution name, not the old `name.replace('_','-')` (the exact + bug that hid llama-cpp-python).""" + src = (Path(__file__).resolve().parents[1] / "routes" / "shell_routes.py").read_text(encoding="utf-8") + assert "importlib_metadata.version(_pip_dist_name(pkg))" in src + assert 'importlib_metadata.version(pkg["name"].replace("_", "-"))' not in src