mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-09 16:18:30 +00:00
refactor: renaming available_tools_classes by available_exports
This commit is contained in:
@@ -48,7 +48,7 @@ class PlusAPI:
|
|||||||
version: str,
|
version: str,
|
||||||
description: Optional[str],
|
description: Optional[str],
|
||||||
encoded_file: str,
|
encoded_file: str,
|
||||||
available_tool_classes: Optional[List[str]] = None,
|
available_exports: Optional[List[str]] = None,
|
||||||
):
|
):
|
||||||
params = {
|
params = {
|
||||||
"handle": handle,
|
"handle": handle,
|
||||||
@@ -56,7 +56,7 @@ class PlusAPI:
|
|||||||
"version": version,
|
"version": version,
|
||||||
"file": encoded_file,
|
"file": encoded_file,
|
||||||
"description": description,
|
"description": description,
|
||||||
"available_tool_classes": available_tool_classes,
|
"available_exports": available_exports,
|
||||||
}
|
}
|
||||||
return self._make_request("POST", f"{self.TOOLS_RESOURCE}", json=params)
|
return self._make_request("POST", f"{self.TOOLS_RESOURCE}", json=params)
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from crewai.cli import git
|
|||||||
from crewai.cli.command import BaseCommand, PlusAPIMixin
|
from crewai.cli.command import BaseCommand, PlusAPIMixin
|
||||||
from crewai.cli.config import Settings
|
from crewai.cli.config import Settings
|
||||||
from crewai.cli.utils import (
|
from crewai.cli.utils import (
|
||||||
extract_available_tools,
|
extract_available_exports,
|
||||||
get_project_description,
|
get_project_description,
|
||||||
get_project_name,
|
get_project_name,
|
||||||
get_project_version,
|
get_project_version,
|
||||||
@@ -84,11 +84,11 @@ class ToolCommand(BaseCommand, PlusAPIMixin):
|
|||||||
encoded_tarball = None
|
encoded_tarball = None
|
||||||
|
|
||||||
console.print("[bold blue]Discovering tools from your project...[/bold blue]")
|
console.print("[bold blue]Discovering tools from your project...[/bold blue]")
|
||||||
available_tools = extract_available_tools()
|
available_exports = extract_available_exports()
|
||||||
|
|
||||||
if available_tools:
|
if available_exports:
|
||||||
console.print(
|
console.print(
|
||||||
f"[green]Found these tools to publish: {', '.join(available_tools)}[/green]"
|
f"[green]Found these tools to publish: {', '.join(available_exports)}[/green]"
|
||||||
)
|
)
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as temp_build_dir:
|
with tempfile.TemporaryDirectory() as temp_build_dir:
|
||||||
@@ -121,7 +121,7 @@ class ToolCommand(BaseCommand, PlusAPIMixin):
|
|||||||
version=project_version,
|
version=project_version,
|
||||||
description=project_description,
|
description=project_description,
|
||||||
encoded_file=f"data:application/x-gzip;base64,{encoded_tarball}",
|
encoded_file=f"data:application/x-gzip;base64,{encoded_tarball}",
|
||||||
available_tools=available_tools,
|
available_exports=available_exports,
|
||||||
)
|
)
|
||||||
|
|
||||||
self._validate_response(publish_response)
|
self._validate_response(publish_response)
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ def is_valid_tool(obj):
|
|||||||
return isinstance(obj, Tool)
|
return isinstance(obj, Tool)
|
||||||
|
|
||||||
|
|
||||||
def extract_available_tools(dir_path: str = "src"):
|
def extract_available_exports(dir_path: str = "src"):
|
||||||
"""
|
"""
|
||||||
Extract available tool classes from the project's __init__.py files.
|
Extract available tool classes from the project's __init__.py files.
|
||||||
Only includes classes that inherit from BaseTool or functions decorated with @tool.
|
Only includes classes that inherit from BaseTool or functions decorated with @tool.
|
||||||
@@ -365,17 +365,17 @@ def extract_available_tools(dir_path: str = "src"):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
init_files = Path(dir_path).glob("**/__init__.py")
|
init_files = Path(dir_path).glob("**/__init__.py")
|
||||||
available_tools = []
|
available_exports = []
|
||||||
|
|
||||||
for init_file in init_files:
|
for init_file in init_files:
|
||||||
tools = _load_tools_from_init(init_file)
|
tools = _load_tools_from_init(init_file)
|
||||||
available_tools.extend(tools)
|
available_exports.extend(tools)
|
||||||
|
|
||||||
if not available_tools:
|
if not available_exports:
|
||||||
_print_no_tools_warning()
|
_print_no_tools_warning()
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
|
|
||||||
return available_tools
|
return available_exports
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
console.print(f"[red]Error: Could not extract tool classes: {str(e)}[/red]")
|
console.print(f"[red]Error: Could not extract tool classes: {str(e)}[/red]")
|
||||||
@@ -406,6 +406,7 @@ def _load_tools_from_init(init_file: Path) -> list:
|
|||||||
)
|
)
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
|
|
||||||
|
# TODO: Security check: prevent any inject malicious code, or stuff like that
|
||||||
return [
|
return [
|
||||||
name
|
name
|
||||||
for name in module.__all__
|
for name in module.__all__
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class TestPlusAPI(unittest.TestCase):
|
|||||||
"version": version,
|
"version": version,
|
||||||
"file": encoded_file,
|
"file": encoded_file,
|
||||||
"description": description,
|
"description": description,
|
||||||
"available_tool_classes": None,
|
"available_exports": None,
|
||||||
}
|
}
|
||||||
mock_make_request.assert_called_once_with(
|
mock_make_request.assert_called_once_with(
|
||||||
"POST", "/crewai_plus/api/v1/tools", json=params
|
"POST", "/crewai_plus/api/v1/tools", json=params
|
||||||
@@ -88,7 +88,7 @@ class TestPlusAPI(unittest.TestCase):
|
|||||||
"version": version,
|
"version": version,
|
||||||
"file": encoded_file,
|
"file": encoded_file,
|
||||||
"description": description,
|
"description": description,
|
||||||
"available_tool_classes": None,
|
"available_exports": None,
|
||||||
}
|
}
|
||||||
mock_make_request.assert_called_once_with(
|
mock_make_request.assert_called_once_with(
|
||||||
"POST", "/crewai_plus/api/v1/tools", json=params
|
"POST", "/crewai_plus/api/v1/tools", json=params
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from crewai.cli import utils
|
from crewai.cli import utils
|
||||||
@@ -113,45 +114,45 @@ def create_init_file(directory, content):
|
|||||||
return create_file(directory / "__init__.py", content)
|
return create_file(directory / "__init__.py", content)
|
||||||
|
|
||||||
|
|
||||||
def test_extract_available_tools_empty_project(temp_project_dir, capsys):
|
def test_extract_available_exports_empty_project(temp_project_dir, capsys):
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
utils.extract_available_tools(dir_path=temp_project_dir)
|
utils.extract_available_exports(dir_path=temp_project_dir)
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
|
|
||||||
assert "No valid tools were exposed in your __init__.py file" in captured.out
|
assert "No valid tools were exposed in your __init__.py file" in captured.out
|
||||||
|
|
||||||
|
|
||||||
def test_extract_available_tools_no_init_file(temp_project_dir, capsys):
|
def test_extract_available_exports_no_init_file(temp_project_dir, capsys):
|
||||||
(temp_project_dir / "some_file.py").write_text("print('hello')")
|
(temp_project_dir / "some_file.py").write_text("print('hello')")
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
utils.extract_available_tools(dir_path=temp_project_dir)
|
utils.extract_available_exports(dir_path=temp_project_dir)
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
|
|
||||||
assert "No valid tools were exposed in your __init__.py file" in captured.out
|
assert "No valid tools were exposed in your __init__.py file" in captured.out
|
||||||
|
|
||||||
|
|
||||||
def test_extract_available_tools_empty_init_file(temp_project_dir, capsys):
|
def test_extract_available_exports_empty_init_file(temp_project_dir, capsys):
|
||||||
create_init_file(temp_project_dir, "")
|
create_init_file(temp_project_dir, "")
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
utils.extract_available_tools(dir_path=temp_project_dir)
|
utils.extract_available_exports(dir_path=temp_project_dir)
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
|
|
||||||
assert "Warning: No __all__ defined in" in captured.out
|
assert "Warning: No __all__ defined in" in captured.out
|
||||||
|
|
||||||
|
|
||||||
def test_extract_available_tools_no_all_variable(temp_project_dir, capsys):
|
def test_extract_available_exports_no_all_variable(temp_project_dir, capsys):
|
||||||
create_init_file(
|
create_init_file(
|
||||||
temp_project_dir,
|
temp_project_dir,
|
||||||
"from crewai.tools import BaseTool\n\nclass MyTool(BaseTool):\n pass",
|
"from crewai.tools import BaseTool\n\nclass MyTool(BaseTool):\n pass",
|
||||||
)
|
)
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
utils.extract_available_tools(dir_path=temp_project_dir)
|
utils.extract_available_exports(dir_path=temp_project_dir)
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
|
|
||||||
assert "Warning: No __all__ defined in" in captured.out
|
assert "Warning: No __all__ defined in" in captured.out
|
||||||
|
|
||||||
|
|
||||||
def test_extract_available_tools_valid_base_tool_class(temp_project_dir):
|
def test_extract_available_exports_valid_base_tool_class(temp_project_dir):
|
||||||
create_init_file(
|
create_init_file(
|
||||||
temp_project_dir,
|
temp_project_dir,
|
||||||
"""from crewai.tools import BaseTool
|
"""from crewai.tools import BaseTool
|
||||||
@@ -163,11 +164,11 @@ class MyTool(BaseTool):
|
|||||||
__all__ = ['MyTool']
|
__all__ = ['MyTool']
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
tools = utils.extract_available_tools(dir_path=temp_project_dir)
|
tools = utils.extract_available_exports(dir_path=temp_project_dir)
|
||||||
assert ["MyTool"] == tools
|
assert ["MyTool"] == tools
|
||||||
|
|
||||||
|
|
||||||
def test_extract_available_tools_valid_tool_decorator(temp_project_dir):
|
def test_extract_available_exports_valid_tool_decorator(temp_project_dir):
|
||||||
create_init_file(
|
create_init_file(
|
||||||
temp_project_dir,
|
temp_project_dir,
|
||||||
"""from crewai.tools import tool
|
"""from crewai.tools import tool
|
||||||
@@ -180,11 +181,11 @@ def my_tool_function(text: str) -> str:
|
|||||||
__all__ = ['my_tool_function']
|
__all__ = ['my_tool_function']
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
tools = utils.extract_available_tools(dir_path=temp_project_dir)
|
tools = utils.extract_available_exports(dir_path=temp_project_dir)
|
||||||
assert ["my_tool_function"] == tools
|
assert ["my_tool_function"] == tools
|
||||||
|
|
||||||
|
|
||||||
def test_extract_available_tools_multiple_valid_tools(temp_project_dir):
|
def test_extract_available_exports_multiple_valid_tools(temp_project_dir):
|
||||||
create_init_file(
|
create_init_file(
|
||||||
temp_project_dir,
|
temp_project_dir,
|
||||||
"""from crewai.tools import BaseTool, tool
|
"""from crewai.tools import BaseTool, tool
|
||||||
@@ -201,11 +202,11 @@ def my_tool_function(text: str) -> str:
|
|||||||
__all__ = ['MyTool', 'my_tool_function']
|
__all__ = ['MyTool', 'my_tool_function']
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
tools = utils.extract_available_tools(dir_path=temp_project_dir)
|
tools = utils.extract_available_exports(dir_path=temp_project_dir)
|
||||||
assert ["MyTool", "my_tool_function"] == tools
|
assert ["MyTool", "my_tool_function"] == tools
|
||||||
|
|
||||||
|
|
||||||
def test_extract_available_tools_with_invalid_tool_decorator(temp_project_dir):
|
def test_extract_available_exports_with_invalid_tool_decorator(temp_project_dir):
|
||||||
create_init_file(
|
create_init_file(
|
||||||
temp_project_dir,
|
temp_project_dir,
|
||||||
"""from crewai.tools import BaseTool
|
"""from crewai.tools import BaseTool
|
||||||
@@ -220,11 +221,11 @@ def not_a_tool():
|
|||||||
__all__ = ['MyTool', 'not_a_tool']
|
__all__ = ['MyTool', 'not_a_tool']
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
tools = utils.extract_available_tools(dir_path=temp_project_dir)
|
tools = utils.extract_available_exports(dir_path=temp_project_dir)
|
||||||
assert ["MyTool"] == tools
|
assert ["MyTool"] == tools
|
||||||
|
|
||||||
|
|
||||||
def test_extract_available_tools_import_error(temp_project_dir, capsys):
|
def test_extract_available_exports_import_error(temp_project_dir, capsys):
|
||||||
create_init_file(
|
create_init_file(
|
||||||
temp_project_dir,
|
temp_project_dir,
|
||||||
"""from nonexistent_module import something
|
"""from nonexistent_module import something
|
||||||
@@ -236,13 +237,13 @@ __all__ = ['MyTool']
|
|||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
utils.extract_available_tools(dir_path=temp_project_dir)
|
utils.extract_available_exports(dir_path=temp_project_dir)
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
|
|
||||||
assert "nonexistent_module" in captured.out
|
assert "nonexistent_module" in captured.out
|
||||||
|
|
||||||
|
|
||||||
def test_extract_available_tools_syntax_error(temp_project_dir, capsys):
|
def test_extract_available_exports_syntax_error(temp_project_dir, capsys):
|
||||||
create_init_file(
|
create_init_file(
|
||||||
temp_project_dir,
|
temp_project_dir,
|
||||||
"""from crewai.tools import BaseTool
|
"""from crewai.tools import BaseTool
|
||||||
@@ -256,7 +257,7 @@ __all__ = ['MyTool']
|
|||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
utils.extract_available_tools(dir_path=temp_project_dir)
|
utils.extract_available_exports(dir_path=temp_project_dir)
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
|
|
||||||
assert "was never closed" in captured.out
|
assert "was never closed" in captured.out
|
||||||
|
|||||||
@@ -135,9 +135,9 @@ def test_publish_when_not_in_sync(mock_is_synced, capsys, tool_command):
|
|||||||
)
|
)
|
||||||
@patch("crewai.cli.plus_api.PlusAPI.publish_tool")
|
@patch("crewai.cli.plus_api.PlusAPI.publish_tool")
|
||||||
@patch("crewai.cli.tools.main.git.Repository.is_synced", return_value=False)
|
@patch("crewai.cli.tools.main.git.Repository.is_synced", return_value=False)
|
||||||
@patch("crewai.cli.tools.main.extract_available_tools", return_value=["SampleTool"])
|
@patch("crewai.cli.tools.main.available_exports", return_value=["SampleTool"])
|
||||||
def test_publish_when_not_in_sync_and_force(
|
def test_publish_when_not_in_sync_and_force(
|
||||||
mock_extract_available_tools,
|
mock_available_exports,
|
||||||
mock_is_synced,
|
mock_is_synced,
|
||||||
mock_publish,
|
mock_publish,
|
||||||
mock_open,
|
mock_open,
|
||||||
@@ -170,7 +170,7 @@ def test_publish_when_not_in_sync_and_force(
|
|||||||
version="1.0.0",
|
version="1.0.0",
|
||||||
description="A sample tool",
|
description="A sample tool",
|
||||||
encoded_file=unittest.mock.ANY,
|
encoded_file=unittest.mock.ANY,
|
||||||
available_tools=["SampleTool"],
|
available_exports=["SampleTool"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -186,9 +186,9 @@ def test_publish_when_not_in_sync_and_force(
|
|||||||
)
|
)
|
||||||
@patch("crewai.cli.plus_api.PlusAPI.publish_tool")
|
@patch("crewai.cli.plus_api.PlusAPI.publish_tool")
|
||||||
@patch("crewai.cli.tools.main.git.Repository.is_synced", return_value=True)
|
@patch("crewai.cli.tools.main.git.Repository.is_synced", return_value=True)
|
||||||
@patch("crewai.cli.tools.main.extract_available_tools", return_value=["SampleTool"])
|
@patch("crewai.cli.tools.main.available_exports", return_value=["SampleTool"])
|
||||||
def test_publish_success(
|
def test_publish_success(
|
||||||
mock_extract_available_tools,
|
mock_available_exports,
|
||||||
mock_is_synced,
|
mock_is_synced,
|
||||||
mock_publish,
|
mock_publish,
|
||||||
mock_open,
|
mock_open,
|
||||||
@@ -221,7 +221,7 @@ def test_publish_success(
|
|||||||
version="1.0.0",
|
version="1.0.0",
|
||||||
description="A sample tool",
|
description="A sample tool",
|
||||||
encoded_file=unittest.mock.ANY,
|
encoded_file=unittest.mock.ANY,
|
||||||
available_tools=["SampleTool"],
|
available_exports=["SampleTool"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -236,9 +236,9 @@ def test_publish_success(
|
|||||||
read_data=b"sample tarball content",
|
read_data=b"sample tarball content",
|
||||||
)
|
)
|
||||||
@patch("crewai.cli.plus_api.PlusAPI.publish_tool")
|
@patch("crewai.cli.plus_api.PlusAPI.publish_tool")
|
||||||
@patch("crewai.cli.tools.main.extract_available_tools", return_value=["SampleTool"])
|
@patch("crewai.cli.tools.main.available_exports", return_value=["SampleTool"])
|
||||||
def test_publish_failure(
|
def test_publish_failure(
|
||||||
mock_extract_available_tools,
|
mock_available_exports,
|
||||||
mock_publish,
|
mock_publish,
|
||||||
mock_open,
|
mock_open,
|
||||||
mock_listdir,
|
mock_listdir,
|
||||||
@@ -274,9 +274,9 @@ def test_publish_failure(
|
|||||||
read_data=b"sample tarball content",
|
read_data=b"sample tarball content",
|
||||||
)
|
)
|
||||||
@patch("crewai.cli.plus_api.PlusAPI.publish_tool")
|
@patch("crewai.cli.plus_api.PlusAPI.publish_tool")
|
||||||
@patch("crewai.cli.tools.main.extract_available_tools", return_value=["SampleTool"])
|
@patch("crewai.cli.tools.main.available_exports", return_value=["SampleTool"])
|
||||||
def test_publish_api_error(
|
def test_publish_api_error(
|
||||||
mock_extract_available_tools,
|
mock_available_exports,
|
||||||
mock_publish,
|
mock_publish,
|
||||||
mock_open,
|
mock_open,
|
||||||
mock_listdir,
|
mock_listdir,
|
||||||
|
|||||||
Reference in New Issue
Block a user