Enhance run_crew.py with improved logging, error handling, and tests

Co-Authored-By: Joe Moura <joao@crewai.com>
This commit is contained in:
Devin AI
2025-03-12 13:39:49 +00:00
parent a7d7edb983
commit d4480bc694
3 changed files with 142 additions and 3 deletions

View File

@@ -1,3 +1,4 @@
import logging
import subprocess import subprocess
import sys import sys
from enum import Enum from enum import Enum
@@ -10,6 +11,8 @@ from packaging import version
from crewai.cli.utils import read_toml from crewai.cli.utils import read_toml
from crewai.cli.version import get_crewai_version from crewai.cli.version import get_crewai_version
logger = logging.getLogger(__name__)
class CrewType(Enum): class CrewType(Enum):
STANDARD = "standard" STANDARD = "standard"
@@ -50,17 +53,30 @@ def run_crew() -> None:
def execute_command(crew_type: CrewType) -> None: def execute_command(crew_type: CrewType) -> None:
""" """Execute the appropriate command based on crew type.
Execute the appropriate command based on crew type.
Args: Args:
crew_type: The type of crew to run crew_type: The type of crew to run
Note:
Automatically adds the 'src' directory to sys.path if it exists
to ensure proper module resolution.
""" """
# Add the 'src' directory to sys.path to ensure module imports work correctly # Add the 'src' directory to sys.path to ensure module imports work correctly
cwd = Path.cwd() cwd = Path.cwd()
src_path = cwd / "src" src_path = cwd / "src"
logger.debug(f"Current working directory: {cwd}")
if src_path.exists() and str(src_path) not in sys.path: if src_path.exists() and str(src_path) not in sys.path:
logger.info(f"Adding {src_path} to sys.path")
sys.path.insert(0, str(src_path)) sys.path.insert(0, str(src_path))
elif not src_path.exists():
logger.warning(f"src directory not found: {src_path}")
click.secho(
f"Warning: 'src' directory not found at {src_path}. Module imports may fail.",
fg="yellow",
)
command = ["uv", "run", "kickoff" if crew_type == CrewType.FLOW else "run_crew"] command = ["uv", "run", "kickoff" if crew_type == CrewType.FLOW else "run_crew"]
@@ -71,6 +87,7 @@ def execute_command(crew_type: CrewType) -> None:
handle_error(e, crew_type) handle_error(e, crew_type)
except Exception as e: except Exception as e:
logger.error(f"Unexpected error: {e}")
click.echo(f"An unexpected error occurred: {e}", err=True) click.echo(f"An unexpected error occurred: {e}", err=True)

View File

@@ -10,7 +10,14 @@ from crewai.cli.run_crew import CrewType, execute_command
def test_execute_command_adds_src_to_path(): def test_execute_command_adds_src_to_path():
"""Test that execute_command adds the src directory to sys.path.""" """
Test that execute_command correctly modifies sys.path.
Ensures:
1. src directory is added to sys.path when it exists.
2. Original sys.path is preserved for other entries.
3. Command execution proceeds correctly.
"""
# Create a temporary directory with a src subdirectory # Create a temporary directory with a src subdirectory
with tempfile.TemporaryDirectory() as temp_dir: with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir) temp_path = Path(temp_dir)

View File

@@ -0,0 +1,115 @@
import os
import subprocess
import sys
import tempfile
from pathlib import Path
from unittest.mock import patch
import pytest
from crewai.cli.run_crew import CrewType, execute_command
@pytest.mark.parametrize("crew_type", [CrewType.STANDARD, CrewType.FLOW])
def test_execute_command_with_different_crew_types(crew_type):
"""
Test that execute_command works with different crew types.
Verifies that the correct command is executed based on the crew type.
"""
# Create a temporary directory with a src subdirectory
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
src_path = temp_path / "src"
src_path.mkdir()
# Change to the temporary directory
original_dir = os.getcwd()
os.chdir(temp_dir)
try:
# Save the original sys.path
original_sys_path = sys.path.copy()
# Mock subprocess.run to avoid actually running the command
with patch("subprocess.run") as mock_run:
# Call execute_command
execute_command(crew_type)
# Check that the correct command was called based on crew_type
expected_command = ["uv", "run", "kickoff" if crew_type == CrewType.FLOW else "run_crew"]
mock_run.assert_called_once_with(expected_command, capture_output=False, text=True, check=True)
finally:
# Restore the original directory and sys.path
os.chdir(original_dir)
sys.path = original_sys_path
def test_execute_command_handles_missing_src_directory():
"""
Test that execute_command handles missing src directory gracefully.
Verifies that the command executes even when the src directory doesn't exist.
"""
# Create a temporary directory without a src subdirectory
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
# Change to the temporary directory
original_dir = os.getcwd()
os.chdir(temp_dir)
try:
# Save the original sys.path
original_sys_path = sys.path.copy()
# Mock subprocess.run to avoid actually running the command
with patch("subprocess.run") as mock_run:
# Call execute_command
execute_command(CrewType.STANDARD)
# Check that sys.path wasn't modified (since src doesn't exist)
assert sys.path == original_sys_path
# Check that the command was still called
mock_run.assert_called_once_with(["uv", "run", "run_crew"], capture_output=False, text=True, check=True)
finally:
# Restore the original directory and sys.path
os.chdir(original_dir)
sys.path = original_sys_path
def test_execute_command_handles_subprocess_error():
"""
Test that execute_command properly handles subprocess errors.
Verifies that exceptions from subprocess.run are propagated correctly.
"""
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
src_path = temp_path / "src"
src_path.mkdir()
# Create a dummy pyproject.toml file
with open(temp_path / "pyproject.toml", "w") as f:
f.write("[project]\nname = \"test\"\n")
# Change to the temporary directory
original_dir = os.getcwd()
os.chdir(temp_dir)
try:
# Save the original sys.path
original_sys_path = sys.path.copy()
# Mock subprocess.run to raise an exception
with patch("subprocess.run", side_effect=subprocess.CalledProcessError(1, [])):
# Call execute_command and verify it handles the error
execute_command(CrewType.STANDARD)
# Verify that sys.path was modified correctly
assert str(src_path) in sys.path
finally:
# Restore the original directory and sys.path
os.chdir(original_dir)
sys.path = original_sys_path