-
Notifications
You must be signed in to change notification settings - Fork 7.6k
fix: make lancedb an optional dependency under [memory] extras #5328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7bec692
baac666
da4b610
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| """Tests that lancedb is an optional dependency. | ||
|
|
||
| These tests verify that: | ||
| 1. The lancedb_storage module handles a missing lancedb gracefully. | ||
| 2. Memory falls back with a clear error when lancedb is not installed. | ||
| 3. Importing crewai itself does not require lancedb. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import sys | ||
| from unittest.mock import MagicMock, patch | ||
|
|
||
| import pytest | ||
|
|
||
|
|
||
| def test_lancedb_storage_raises_import_error_when_lancedb_missing(tmp_path): | ||
| """LanceDBStorage.__init__ raises ImportError with install instructions when lancedb is absent.""" | ||
| with patch.dict(sys.modules, {"lancedb": None}): | ||
| # Force reload so the module picks up the patched sys.modules | ||
| import importlib | ||
|
|
||
| import crewai.memory.storage.lancedb_storage as mod | ||
|
|
||
| importlib.reload(mod) | ||
|
|
||
| with pytest.raises(ImportError, match="pip install 'crewai\\[memory\\]'"): | ||
| mod.LanceDBStorage(path=str(tmp_path / "mem")) | ||
|
|
||
| # Restore the module to its original state | ||
| importlib.reload(mod) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test module restoration happens inside patched contextLow Severity The Additional Locations (2)Reviewed by Cursor Bugbot for commit 7bec692. Configure here. |
||
|
|
||
|
|
||
| def test_memory_default_storage_raises_when_lancedb_missing(tmp_path): | ||
| """Memory(storage='lancedb') raises ImportError when lancedb is not installed.""" | ||
| with patch.dict(sys.modules, {"lancedb": None}): | ||
| import importlib | ||
|
|
||
| import crewai.memory.storage.lancedb_storage as mod | ||
|
|
||
| importlib.reload(mod) | ||
|
|
||
| try: | ||
| from crewai.memory.unified_memory import Memory | ||
|
|
||
| with pytest.raises(ImportError, match="pip install 'crewai\\[memory\\]'"): | ||
| Memory( | ||
| storage="lancedb", | ||
| llm=MagicMock(), | ||
| embedder=MagicMock(), | ||
| ) | ||
| finally: | ||
| importlib.reload(mod) | ||
|
|
||
|
|
||
| def test_memory_with_path_string_raises_when_lancedb_missing(tmp_path): | ||
| """Memory(storage='/some/path') also uses LanceDBStorage and raises when lancedb is missing.""" | ||
| with patch.dict(sys.modules, {"lancedb": None}): | ||
| import importlib | ||
|
|
||
| import crewai.memory.storage.lancedb_storage as mod | ||
|
|
||
| importlib.reload(mod) | ||
|
|
||
| try: | ||
| from crewai.memory.unified_memory import Memory | ||
|
|
||
| with pytest.raises(ImportError, match="pip install 'crewai\\[memory\\]'"): | ||
| Memory( | ||
| storage=str(tmp_path / "custom_path"), | ||
| llm=MagicMock(), | ||
| embedder=MagicMock(), | ||
| ) | ||
| finally: | ||
| importlib.reload(mod) | ||
|
|
||
|
|
||
| def test_crewai_import_does_not_require_lancedb(): | ||
| """Importing crewai should work even if lancedb is not installed. | ||
|
|
||
| The Memory class is lazily imported in crewai/__init__.py, so lancedb | ||
| should never be pulled in at import time. | ||
| """ | ||
| # This test verifies the lazy import mechanism by checking that the | ||
| # crewai module is importable and that Memory is listed in __all__ | ||
| # but not yet resolved in the module globals until accessed. | ||
| import crewai | ||
|
|
||
| assert "Memory" in crewai.__all__ | ||
| # Memory should be accessible (lazy import triggers on access) | ||
| assert hasattr(crewai, "Memory") | ||
|
|
||
|
|
||
| def test_memory_with_custom_storage_backend_does_not_need_lancedb(tmp_path): | ||
| """When a custom StorageBackend is passed, lancedb is never needed.""" | ||
| with patch.dict(sys.modules, {"lancedb": None}): | ||
| import importlib | ||
|
|
||
| import crewai.memory.storage.lancedb_storage as mod | ||
|
|
||
| importlib.reload(mod) | ||
|
|
||
| try: | ||
| from crewai.memory.unified_memory import Memory | ||
|
|
||
| mock_storage = MagicMock() | ||
| # Should not raise, since we're providing a custom storage backend | ||
| mem = Memory( | ||
| storage=mock_storage, | ||
| llm=MagicMock(), | ||
| embedder=MagicMock(), | ||
| ) | ||
| assert mem._storage is mock_storage | ||
| finally: | ||
| importlib.reload(mod) | ||
|
|
||
|
|
||
| def test_lancedb_in_optional_dependencies(): | ||
| """Verify lancedb is listed under optional [memory] dependencies, not core.""" | ||
| import tomli | ||
| from pathlib import Path | ||
|
|
||
| pyproject_path = Path(__file__).resolve().parents[2] / "pyproject.toml" | ||
| with open(pyproject_path, "rb") as f: | ||
| data = tomli.load(f) | ||
|
|
||
| core_deps = data["project"]["dependencies"] | ||
| optional_deps = data["project"]["optional-dependencies"] | ||
|
|
||
| # lancedb should NOT be in core dependencies | ||
| assert not any("lancedb" in dep for dep in core_deps), ( | ||
| "lancedb should not be a core dependency" | ||
| ) | ||
|
|
||
| # lancedb SHOULD be in optional [memory] dependencies | ||
| assert "memory" in optional_deps, "Missing [memory] optional dependency group" | ||
| memory_deps = optional_deps["memory"] | ||
| assert any("lancedb" in dep for dep in memory_deps), ( | ||
| "lancedb should be in the [memory] optional dependency group" | ||
| ) | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.


Uh oh!
There was an error while loading. Please reload this page.