Repository: crewAIInc/crewAI
Pull request #1455 (2024-10-16 13:07:39)

Adapt Tools CLI to uv
This pull request adapts commands from the Tool CLI from Poetry to uv.

Extra comments inline 👇


Patch:
diff --git a/src/crewai/cli/plus_api.py b/src/crewai/cli/plus_api.py
index 0fa9ff3a..04f6fb8f 100644
--- a/src/crewai/cli/plus_api.py
+++ b/src/crewai/cli/plus_api.py
@@ -25,7 +25,9 @@ class PlusAPI:
 
     def _make_request(self, method: str, endpoint: str, **kwargs) -> requests.Response:
         url = urljoin(self.base_url, endpoint)
-        return requests.request(method, url, headers=self.headers, **kwargs)
+        session = requests.Session()
+        session.trust_env = False
+        return session.request(method, url, headers=self.headers, **kwargs)
 
     def login_to_tool_repository(self):
         return self._make_request("POST", f"{self.TOOLS_RESOURCE}/login")
diff --git a/src/crewai/cli/templates/tool/.gitignore b/src/crewai/cli/templates/tool/.gitignore
new file mode 100644
index 00000000..505a3b1c
--- /dev/null
+++ b/src/crewai/cli/templates/tool/.gitignore
@@ -0,0 +1,10 @@
+# Python-generated files
+__pycache__/
+*.py[oc]
+build/
+dist/
+wheels/
+*.egg-info
+
+# Virtual environments
+.venv
diff --git a/src/crewai/cli/templates/tool/pyproject.toml b/src/crewai/cli/templates/tool/pyproject.toml
index 972e3c10..a5b2ece4 100644
--- a/src/crewai/cli/templates/tool/pyproject.toml
+++ b/src/crewai/cli/templates/tool/pyproject.toml
@@ -1,14 +1,10 @@
-[tool.poetry]
+[project]
 name = "{{folder_name}}"
 version = "0.1.0"
 description = "Power up your crews with {{folder_name}}"
-authors = ["Your Name <you@example.com>"]
 readme = "README.md"
+requires-python = ">=3.10,<=3.13"
+dependencies = [
+    "crewai[tools]>=0.70.1"
+]
 
-[tool.poetry.dependencies]
-python = ">=3.10,<=3.13"
-crewai = { extras = ["tools"], version = ">=0.70.1,<1.0.0" }
-
-[build-system]
-requires = ["poetry-core"]
-build-backend = "poetry.core.masonry.api"
diff --git a/src/crewai/cli/tools/main.py b/src/crewai/cli/tools/main.py
index 08be76d1..b6237c61 100644
--- a/src/crewai/cli/tools/main.py
+++ b/src/crewai/cli/tools/main.py
@@ -4,6 +4,8 @@ import platform
 import subprocess
 import tempfile
 from pathlib import Path
+from netrc import netrc
+import stat
 
 import click
 from rich.console import Console
@@ -147,7 +149,7 @@ class ToolCommand(BaseCommand, PlusAPIMixin):
 
         if login_response.status_code != 200:
             console.print(
-                "Failed to authenticate to the tool repository. Make sure you have the access to tools.",
+                "Authentication failed. Verify access to the tool repository, or try `crewai login`. ",
                 style="bold red",
             )
             raise SystemExit
@@ -159,23 +161,19 @@ class ToolCommand(BaseCommand, PlusAPIMixin):
             "Successfully authenticated to the tool repository.", style="bold green"
         )
 
-    def _set_netrc_credentials(self, credentials):
-        # Create .netrc or _netrc file
-        netrc_filename = "_netrc" if platform.system() == "Windows" else ".netrc"
-        netrc_path = Path.home() / netrc_filename
+    def _set_netrc_credentials(self, credentials, netrc_path=None):
+        if not netrc_path:
+            netrc_filename = "_netrc" if platform.system() == "Windows" else ".netrc"
+            netrc_path = Path.home() / netrc_filename
+            netrc_path.touch(mode=stat.S_IRUSR | stat.S_IWUSR, exist_ok=True)
 
-        netrc_content = f"""machine app.crewai.com
-login {credentials['username']}
-password {credentials['password']}
-"""
+        netrc_instance = netrc(file=netrc_path)
+        netrc_instance.hosts["app.crewai.com"] = (credentials["username"], "", credentials["password"])
 
-        with open(netrc_path, "a") as netrc_file:
-            netrc_file.write(netrc_content)
+        with open(netrc_path, 'w') as file:
+            file.write(str(netrc_instance))
 
-        # Set appropriate permissions for Unix-like systems
-        if platform.system() != "Windows":
-            os.chmod(netrc_path, 0o600)
-        console.print(f"Added credentials to {netrc_filename}", style="bold green")
+        console.print(f"Added credentials to {netrc_path}", style="bold green")
 
     def _add_package(self, tool_details):
         tool_handle = tool_details["handle"]


Test patch:
diff --git a/tests/cli/test_plus_api.py b/tests/cli/test_plus_api.py
index ace9e4e5..e0acf22e 100644
--- a/tests/cli/test_plus_api.py
+++ b/tests/cli/test_plus_api.py
@@ -92,16 +92,20 @@ class TestPlusAPI(unittest.TestCase):
         )
         self.assertEqual(response, mock_response)
 
-    @patch("crewai.cli.plus_api.requests.request")
-    def test_make_request(self, mock_request):
+    @patch("crewai.cli.plus_api.requests.Session")
+    def test_make_request(self, mock_session):
         mock_response = MagicMock()
-        mock_request.return_value = mock_response
+
+        mock_session_instance = mock_session.return_value
+        mock_session_instance.request.return_value = mock_response
 
         response = self.api._make_request("GET", "test_endpoint")
 
-        mock_request.assert_called_once_with(
+        mock_session.assert_called_once()
+        mock_session_instance.request.assert_called_once_with(
             "GET", f"{self.api.base_url}/test_endpoint", headers=self.api.headers
         )
+        mock_session_instance.trust_env = False
         self.assertEqual(response, mock_response)
 
     @patch("crewai.cli.plus_api.PlusAPI._make_request")