Files
crewAI/lib/crewai/tests/cli/test_entrypoint.py
Devin AI 7419fa8a7d fix: add [project.scripts] to crewai package for uv tool install (#6010)
The crewai package did not declare any [project.scripts] entry point,
causing `uv tool install crewai` to fail with:

    No executables are provided by package `crewai`; removing tool
    error: Failed to install entrypoints for `crewai`

The CLI entry point was only defined in the crewai-cli sub-package.
Add `crewai = "crewai_cli.cli:crewai"` to lib/crewai/pyproject.toml
so that installing the main package also exposes the executable.

Add regression tests verifying the entry point is declared, importable,
and consistent between both packages.

Co-Authored-By: João <joao@crewai.com>
2026-06-02 14:00:48 +00:00

61 lines
2.1 KiB
Python

"""Tests ensuring the crewai package exposes the CLI entry point.
Regression test for https://github.com/crewAIInc/crewAI/issues/6010:
`uv tool install crewai` failed because the crewai package did not declare
any [project.scripts], so uv could not find an executable to expose.
"""
from __future__ import annotations
import importlib
from pathlib import Path
import click
import pytest
import tomllib
CREWAI_PYPROJECT = (
Path(__file__).resolve().parents[2] / "pyproject.toml"
)
@pytest.fixture
def crewai_metadata() -> dict:
"""Load the crewai package pyproject.toml as a dict."""
return tomllib.loads(CREWAI_PYPROJECT.read_text())
def test_crewai_package_declares_scripts_entrypoint(crewai_metadata: dict) -> None:
"""The crewai package must declare a 'crewai' console script."""
scripts = crewai_metadata.get("project", {}).get("scripts", {})
assert "crewai" in scripts, (
"The crewai package pyproject.toml must define [project.scripts] "
"with a 'crewai' entry so that `uv tool install crewai` works."
)
def test_crewai_entrypoint_target_is_importable(crewai_metadata: dict) -> None:
"""The target of the crewai script entry point must be importable."""
scripts = crewai_metadata.get("project", {}).get("scripts", {})
ref = scripts.get("crewai", "")
assert ":" in ref, f"Entry point reference should be 'module:attr', got: {ref!r}"
module_path, attr_name = ref.rsplit(":", 1)
mod = importlib.import_module(module_path)
entry = getattr(mod, attr_name, None)
assert entry is not None, (
f"Could not find attribute {attr_name!r} in module {module_path!r}"
)
def test_crewai_entrypoint_is_click_command(crewai_metadata: dict) -> None:
"""The crewai CLI entry point must be a click command/group."""
scripts = crewai_metadata.get("project", {}).get("scripts", {})
ref = scripts["crewai"]
module_path, attr_name = ref.rsplit(":", 1)
mod = importlib.import_module(module_path)
entry = getattr(mod, attr_name)
assert isinstance(entry, click.BaseCommand), (
f"Expected a click command/group, got {type(entry).__name__}"
)