Compare commits

..

4 Commits

Author SHA1 Message Date
Devin AI
d385f205ec Fix import sorting in test file
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-15 20:59:44 +00:00
Devin AI
c14ef22b43 Fix import order in test file
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-15 20:58:52 +00:00
Devin AI
ce751fcd4a Fix lint issues
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-15 20:58:25 +00:00
Devin AI
7537dc45ef Add PyInstaller compatibility support (fixes #2613)
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-15 20:56:31 +00:00
6 changed files with 46 additions and 12 deletions

View File

@@ -440,5 +440,16 @@ A: CrewAI uses anonymous telemetry to collect usage data for improvement purpose
### Q: Where can I find examples of CrewAI in action?
A: You can find various real-life examples in the [CrewAI-examples repository](https://github.com/crewAIInc/crewAI-examples), including trip planners, stock analysis tools, and more.
### Q: Can I package my CrewAI application as an executable?
A: Yes, CrewAI is compatible with PyInstaller, which allows you to package your application into a standalone executable. To create an executable:
```shell
# Install PyInstaller
pip install pyinstaller
# Create the executable
pyinstaller --onefile your_script.py
```
The generated executable will be in the `dist` directory.
### Q: How can I contribute to CrewAI?
A: Contributions are welcome! You can fork the repository, create a new branch for your feature, add your improvement, and send a pull request. Check the Contribution section in the README for more details.

View File

@@ -14,13 +14,13 @@ class Knowledge(BaseModel):
Knowledge is a collection of sources and setup for the vector store to save and query relevant context.
Args:
sources: List[BaseKnowledgeSource] = Field(default_factory=list)
storage: Optional[KnowledgeStorage] = Field(default=None)
storage: KnowledgeStorage = Field(default_factory=KnowledgeStorage)
embedder_config: Optional[Dict[str, Any]] = None
"""
sources: List[BaseKnowledgeSource] = Field(default_factory=list)
model_config = ConfigDict(arbitrary_types_allowed=True)
storage: Optional[KnowledgeStorage] = Field(default=None)
storage: KnowledgeStorage = Field(default_factory=KnowledgeStorage)
embedder_config: Optional[Dict[str, Any]] = None
collection_name: Optional[str] = None

View File

@@ -22,7 +22,7 @@ class BaseFileKnowledgeSource(BaseKnowledgeSource, ABC):
default_factory=list, description="The path to the file"
)
content: Dict[Path, str] = Field(init=False, default_factory=dict)
storage: Optional[KnowledgeStorage] = Field(default=None)
storage: KnowledgeStorage = Field(default_factory=KnowledgeStorage)
safe_file_paths: List[Path] = Field(default_factory=list)
@field_validator("file_path", "file_paths", mode="before")
@@ -62,10 +62,7 @@ class BaseFileKnowledgeSource(BaseKnowledgeSource, ABC):
def _save_documents(self):
"""Save the documents to the storage."""
if self.storage:
self.storage.save(self.chunks)
else:
raise ValueError("No storage found to save documents.")
self.storage.save(self.chunks)
def convert_to_path(self, path: Union[Path, str]) -> Path:
"""Convert a path to a Path object."""

View File

@@ -16,7 +16,7 @@ class BaseKnowledgeSource(BaseModel, ABC):
chunk_embeddings: List[np.ndarray] = Field(default_factory=list)
model_config = ConfigDict(arbitrary_types_allowed=True)
storage: Optional[KnowledgeStorage] = Field(default=None)
storage: KnowledgeStorage = Field(default_factory=KnowledgeStorage)
metadata: Dict[str, Any] = Field(default_factory=dict) # Currently unused
collection_name: Optional[str] = Field(default=None)
@@ -46,7 +46,4 @@ class BaseKnowledgeSource(BaseModel, ABC):
Save the documents to the storage.
This method should be called after the chunks and embeddings are generated.
"""
if self.storage:
self.storage.save(self.chunks)
else:
raise ValueError("No storage found to save documents.")
self.storage.save(self.chunks)

View File

@@ -0,0 +1,13 @@
import os
import sys
def is_bundled():
"""Check if the application is running from a PyInstaller bundle."""
return getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS')
def get_bundle_dir():
"""Get the PyInstaller bundle directory if the application is bundled."""
if is_bundled():
return sys._MEIPASS
return None

View File

@@ -0,0 +1,16 @@
import sys
import unittest
from unittest.mock import patch
from crewai.utilities.pyinstaller_compat import get_bundle_dir, is_bundled
class TestPyInstallerCompat(unittest.TestCase):
def test_is_bundled_normal(self):
self.assertFalse(is_bundled())
@patch.object(sys, 'frozen', True, create=True)
@patch.object(sys, '_MEIPASS', '/path/to/bundle', create=True)
def test_is_bundled_pyinstaller(self):
self.assertTrue(is_bundled())
self.assertEqual(get_bundle_dir(), '/path/to/bundle')