mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-07-01 13:18:10 +00:00
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>
This commit is contained in:
55
lib/cli/tests/test_entrypoint_consistency.py
Normal file
55
lib/cli/tests/test_entrypoint_consistency.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""Tests ensuring the crewai and crewai-cli packages expose consistent entry points.
|
||||
|
||||
Regression test for https://github.com/crewAIInc/crewAI/issues/6010:
|
||||
`uv tool install crewai` failed because only crewai-cli declared [project.scripts].
|
||||
Both packages must declare the same entry point so that installing either one
|
||||
via `uv tool install` exposes the `crewai` executable.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import tomllib
|
||||
|
||||
|
||||
LIB_DIR = Path(__file__).resolve().parents[2]
|
||||
CREWAI_PYPROJECT = LIB_DIR / "crewai" / "pyproject.toml"
|
||||
CLI_PYPROJECT = LIB_DIR / "cli" / "pyproject.toml"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def crewai_scripts() -> dict[str, str]:
|
||||
data = tomllib.loads(CREWAI_PYPROJECT.read_text())
|
||||
return data.get("project", {}).get("scripts", {})
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cli_scripts() -> dict[str, str]:
|
||||
data = tomllib.loads(CLI_PYPROJECT.read_text())
|
||||
return data.get("project", {}).get("scripts", {})
|
||||
|
||||
|
||||
def test_crewai_package_has_crewai_script(crewai_scripts: dict[str, str]) -> None:
|
||||
"""The crewai package must declare a 'crewai' script entry point."""
|
||||
assert "crewai" in crewai_scripts, (
|
||||
"lib/crewai/pyproject.toml must have [project.scripts] crewai = ... "
|
||||
"so that `uv tool install crewai` exposes the crewai executable."
|
||||
)
|
||||
|
||||
|
||||
def test_cli_package_has_crewai_script(cli_scripts: dict[str, str]) -> None:
|
||||
"""The crewai-cli package must declare a 'crewai' script entry point."""
|
||||
assert "crewai" in cli_scripts
|
||||
|
||||
|
||||
def test_entrypoint_targets_same_function(
|
||||
crewai_scripts: dict[str, str],
|
||||
cli_scripts: dict[str, str],
|
||||
) -> None:
|
||||
"""Both packages must point at the same CLI entry function."""
|
||||
assert crewai_scripts["crewai"] == cli_scripts["crewai"], (
|
||||
"The crewai and crewai-cli packages should declare the same "
|
||||
"entry point target for the 'crewai' script."
|
||||
)
|
||||
@@ -138,6 +138,9 @@ torchvision = [
|
||||
crewai-files = { workspace = true }
|
||||
|
||||
|
||||
[project.scripts]
|
||||
crewai = "crewai_cli.cli:crewai"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
60
lib/crewai/tests/cli/test_entrypoint.py
Normal file
60
lib/crewai/tests/cli/test_entrypoint.py
Normal file
@@ -0,0 +1,60 @@
|
||||
"""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__}"
|
||||
)
|
||||
Reference in New Issue
Block a user