mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-10 08:38:30 +00:00
Add import utilities for optional dependencies (#3389)
This commit is contained in:
32
src/crewai/utilities/import_utils.py
Normal file
32
src/crewai/utilities/import_utils.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""Import utilities for optional dependencies."""
|
||||
|
||||
import importlib
|
||||
from types import ModuleType
|
||||
|
||||
|
||||
class OptionalDependencyError(ImportError):
|
||||
"""Exception raised when an optional dependency is not installed."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def require(name: str, *, purpose: str) -> ModuleType:
|
||||
"""Import a module, raising a helpful error if it's not installed.
|
||||
|
||||
Args:
|
||||
name: The module name to import.
|
||||
purpose: Description of what requires this dependency.
|
||||
|
||||
Returns:
|
||||
The imported module.
|
||||
|
||||
Raises:
|
||||
OptionalDependencyError: If the module is not installed.
|
||||
"""
|
||||
try:
|
||||
return importlib.import_module(name)
|
||||
except ImportError as exc:
|
||||
raise OptionalDependencyError(
|
||||
f"{purpose} requires the optional dependency '{name}'.\n"
|
||||
f"Install it with: uv add {name}"
|
||||
) from exc
|
||||
42
tests/utilities/test_import_utils.py
Normal file
42
tests/utilities/test_import_utils.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""Tests for import utilities."""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import patch
|
||||
|
||||
from crewai.utilities.import_utils import require, OptionalDependencyError
|
||||
|
||||
|
||||
class TestRequire:
|
||||
"""Test the require function."""
|
||||
|
||||
def test_require_existing_module(self):
|
||||
"""Test requiring a module that exists."""
|
||||
module = require("json", purpose="testing")
|
||||
assert module.__name__ == "json"
|
||||
|
||||
def test_require_missing_module(self):
|
||||
"""Test requiring a module that doesn't exist."""
|
||||
with pytest.raises(OptionalDependencyError) as exc_info:
|
||||
require("nonexistent_module_xyz", purpose="testing missing module")
|
||||
|
||||
error_msg = str(exc_info.value)
|
||||
assert (
|
||||
"testing missing module requires the optional dependency 'nonexistent_module_xyz'"
|
||||
in error_msg
|
||||
)
|
||||
assert "uv add nonexistent_module_xyz" in error_msg
|
||||
|
||||
def test_require_with_import_error(self):
|
||||
"""Test that ImportError is properly chained."""
|
||||
with patch("importlib.import_module") as mock_import:
|
||||
mock_import.side_effect = ImportError("Module import failed")
|
||||
|
||||
with pytest.raises(OptionalDependencyError) as exc_info:
|
||||
require("some_module", purpose="testing error handling")
|
||||
|
||||
assert isinstance(exc_info.value.__cause__, ImportError)
|
||||
assert str(exc_info.value.__cause__) == "Module import failed"
|
||||
|
||||
def test_optional_dependency_error_is_import_error(self):
|
||||
"""Test that OptionalDependencyError is a subclass of ImportError."""
|
||||
assert issubclass(OptionalDependencyError, ImportError)
|
||||
Reference in New Issue
Block a user