From 9cff6c7d1aa28459414bc17dd3dec09d437edb6e Mon Sep 17 00:00:00 2001 From: Kye Gomez Date: Tue, 28 Jan 2025 14:26:19 -0500 Subject: [PATCH] [cleanup] --- .../dao_swarm.py | 0 .../deepseek_r1.py | 0 .../litellm_tool_example.py | 0 pyproject.toml | 22 +- swarms/tools/__init__.py | 2 - swarms/tools/func_calling_executor.py | 238 ---------------- swarms/tools/function_util.py | 16 +- swarms/utils/lazy_loader.py | 263 ------------------ swarms/utils/litellm_tokenizer.py | 3 +- swarms/utils/wrapper_clusterop.py | 9 + tests/utils/test_auto_check_download.py | 83 ++++-- 11 files changed, 87 insertions(+), 549 deletions(-) rename dao_swarm.py => new_features_examples/dao_swarm.py (100%) rename deepseek_r1.py => new_features_examples/deepseek_r1.py (100%) rename litellm_tool_example.py => new_features_examples/litellm_tool_example.py (100%) delete mode 100644 swarms/tools/func_calling_executor.py delete mode 100644 swarms/utils/lazy_loader.py diff --git a/dao_swarm.py b/new_features_examples/dao_swarm.py similarity index 100% rename from dao_swarm.py rename to new_features_examples/dao_swarm.py diff --git a/deepseek_r1.py b/new_features_examples/deepseek_r1.py similarity index 100% rename from deepseek_r1.py rename to new_features_examples/deepseek_r1.py diff --git a/litellm_tool_example.py b/new_features_examples/litellm_tool_example.py similarity index 100% rename from litellm_tool_example.py rename to new_features_examples/litellm_tool_example.py diff --git a/pyproject.toml b/pyproject.toml index c2802359b..32b9a5312 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "swarms" -version = "6.9.9" +version = "7.0.0" description = "Swarms - TGSC" license = "MIT" authors = ["Kye Gomez "] @@ -78,25 +78,11 @@ rich = "*" # sentence-transformers = "*" -# [tool.poetry.extras] -# # Extra for NLP-related functionalities -# nlp = [ -# "torch>=2.1.1,<3.0", -# "transformers>=4.39.0,<5.0.0", -# "sentence-transformers", -# "swarm-models", -# ] - -# # Extra for database-related functionalities -# db = ["chromadb"] - # # All optional dependencies for convenience # all = [ -# "torch>=2.1.1,<3.0", -# "transformers>=4.39.0,<5.0.0", -# "sentence-transformers", -# "chromadb", -# "swarm-models" +# "torch", +# "transformers", +# "litellm" # ] diff --git a/swarms/tools/__init__.py b/swarms/tools/__init__.py index 18ac51ac8..3bb4c5ad7 100644 --- a/swarms/tools/__init__.py +++ b/swarms/tools/__init__.py @@ -2,7 +2,6 @@ scrape_tool_func_docs, tool_find_by_name, ) -from swarms.tools.func_calling_executor import openai_tool_executor from swarms.tools.pydantic_to_json import ( _remove_a_key, base_model_to_openai_function, @@ -34,7 +33,6 @@ __all__ = [ "scrape_tool_func_docs", "tool_find_by_name", - "openai_tool_executor", "_remove_a_key", "base_model_to_openai_function", "multi_base_model_to_openai_function", diff --git a/swarms/tools/func_calling_executor.py b/swarms/tools/func_calling_executor.py deleted file mode 100644 index 65d95a738..000000000 --- a/swarms/tools/func_calling_executor.py +++ /dev/null @@ -1,238 +0,0 @@ -import concurrent.futures -from typing import Callable, Any, Dict, List -from swarms.utils.loguru_logger import initialize_logger - -logger = initialize_logger(log_folder="func_calling_executor") - -# def openai_tool_executor( -# tools: List[Dict[str, Any]], -# function_map: Dict[str, Callable], -# verbose: bool = True, -# return_as_string: bool = False, -# *args, -# **kwargs, -# ) -> Callable: -# """ -# Creates a function that dynamically and concurrently executes multiple functions based on parameters specified -# in a list of tool dictionaries, with extensive error handling and validation. - -# Args: -# tools (List[Dict[str, Any]]): A list of dictionaries, each containing configuration for a tool, including parameters. -# function_map (Dict[str, Callable]): A dictionary mapping function names to their corresponding callable functions. -# verbose (bool): If True, enables verbose logging. -# return_as_string (bool): If True, returns the results as a concatenated string. - -# Returns: -# Callable: A function that, when called, executes the specified functions concurrently with the parameters given. - -# Examples: -# >>> def test_function(param1: int, param2: str) -> str: -# ... return f"Test function called with parameters: {param1}, {param2}" - -# >>> tool_executor = openai_tool_executor( -# ... tools=[ -# ... { -# ... "type": "function", -# ... "function": { -# ... "name": "test_function", -# ... "parameters": { -# ... "param1": 1, -# ... "param2": "example" -# ... } -# ... } -# ... } -# ... ], -# ... function_map={ -# ... "test_function": test_function -# ... }, -# ... return_as_string=True -# ... ) -# >>> results = tool_executor() -# >>> print(results) -# """ - -# def tool_executor(): -# # Prepare tasks for concurrent execution -# results = [] -# logger.info(f"Executing {len(tools)} tools concurrently.") -# with concurrent.futures.ThreadPoolExecutor() as executor: -# futures = [] -# for tool in tools: -# if tool.get("type") != "function": -# continue # Skip non-function tool entries - -# function_info = tool.get("function", {}) -# func_name = function_info.get("name") -# logger.info(f"Executing function: {func_name}") - -# # Check if the function name is mapped to an actual function -# if func_name not in function_map: -# error_message = f"Function '{func_name}' not found in function map." -# logger.error(error_message) -# results.append(error_message) -# continue - -# # Validate parameters -# params = function_info.get("parameters", {}) -# if not params: -# error_message = f"No parameters specified for function '{func_name}'." -# logger.error(error_message) -# results.append(error_message) -# continue - -# # Submit the function for execution -# try: -# future = executor.submit( -# function_map[func_name], **params -# ) -# futures.append((func_name, future)) -# except Exception as e: -# error_message = f"Failed to submit the function '{func_name}' for execution: {e}" -# logger.error(error_message) -# results.append(error_message) - -# # Gather results from all futures -# for func_name, future in futures: -# try: -# result = future.result() # Collect result from future -# results.append(f"{func_name}: {result}") -# except Exception as e: -# error_message = f"Error during execution of function '{func_name}': {e}" -# logger.error(error_message) -# results.append(error_message) - -# if return_as_string: -# return "\n".join(results) - -# logger.info(f"Results: {results}") - -# return results - -# return tool_executor - - -def openai_tool_executor( - tools: List[Dict[str, Any]], - function_map: Dict[str, Callable], - verbose: bool = True, - return_as_string: bool = False, - *args, - **kwargs, -) -> Callable: - def tool_executor(): - results = [] - logger.info(f"Executing {len(tools)} tools concurrently.") - with concurrent.futures.ThreadPoolExecutor() as executor: - futures = [] - for tool in tools: - if tool.get("type") != "function": - continue - - function_info = tool.get("function", {}) - func_name = function_info.get("name") - logger.info(f"Executing function: {func_name}") - - if func_name not in function_map: - error_message = f"Function '{func_name}' not found in function map." - logger.error(error_message) - results.append(error_message) - continue - - params = function_info.get("parameters", {}) - if not params: - error_message = f"No parameters specified for function '{func_name}'." - logger.error(error_message) - results.append(error_message) - continue - - if ( - "name" in params - and params["name"] in function_map - ): - try: - result = function_map[params["name"]]( - **params - ) - results.append(f"{params['name']}: {result}") - except Exception as e: - error_message = f"Failed to execute the function '{params['name']}': {e}" - logger.error(error_message) - results.append(error_message) - continue - - try: - future = executor.submit( - function_map[func_name], **params - ) - futures.append((func_name, future)) - except Exception as e: - error_message = f"Failed to submit the function '{func_name}' for execution: {e}" - logger.error(error_message) - results.append(error_message) - - for func_name, future in futures: - try: - result = future.result() - results.append(f"{func_name}: {result}") - except Exception as e: - error_message = f"Error during execution of function '{func_name}': {e}" - logger.error(error_message) - results.append(error_message) - - if return_as_string: - return "\n".join(results) - - logger.info(f"Results: {results}") - - return results - - return tool_executor - - -# function_schema = { -# "name": "execute", -# "description": "Executes code on the user's machine **in the users local environment** and returns the output", -# "parameters": { -# "type": "object", -# "properties": { -# "language": { -# "type": "string", -# "description": "The programming language (required parameter to the `execute` function)", -# "enum": [ -# # This will be filled dynamically with the languages OI has access to. -# ], -# }, -# "code": { -# "type": "string", -# "description": "The code to execute (required)", -# }, -# }, -# "required": ["language", "code"], -# }, -# } - - -# def execute(language: str, code: str): -# """ -# Executes code on the user's machine **in the users local environment** and returns the output - -# Args: -# language (str): The programming language (required parameter to the `execute` function) -# code (str): The code to execute (required) - -# Returns: -# str: The output of the code execution -# """ -# # This function will be implemented by the user -# return "Code execution not implemented yet" - - -# # Example execution -# out = openai_tool_executor( -# tools=[function_schema], -# function_map={ -# "execute": execute, -# }, -# return_as_string=True, -# ) -# print(out) diff --git a/swarms/tools/function_util.py b/swarms/tools/function_util.py index de0ec97a5..731584fb6 100644 --- a/swarms/tools/function_util.py +++ b/swarms/tools/function_util.py @@ -1,16 +1,24 @@ import inspect +from typing import Callable, Type, Union -def process_tool_docs(item): +def process_tool_docs(item: Union[Callable, Type]) -> str: """ - Process the documentation for a given item. + Process the documentation for a given item, which can be a function or a class. Args: - item: The item to process the documentation for. + item: The item to process the documentation for. It can be a function or a class. Returns: - metadata: The processed metadata containing the item's name, documentation, and source code. + str: The processed metadata containing the item's name, documentation, and source code. + + Raises: + TypeError: If the item is not a function or a class. """ + # Check if item is a function or a class + if not inspect.isfunction(item) and not inspect.isclass(item): + raise TypeError("Item must be a function or a class.") + # If item is an instance of a class, get its class if not inspect.isclass(item) and hasattr(item, "__class__"): item = item.__class__ diff --git a/swarms/utils/lazy_loader.py b/swarms/utils/lazy_loader.py deleted file mode 100644 index c9725e51b..000000000 --- a/swarms/utils/lazy_loader.py +++ /dev/null @@ -1,263 +0,0 @@ -""" -Lazy Package Loader - -This module provides utilities for lazy loading Python packages to improve startup time -and reduce memory usage by only importing packages when they are actually used. - -Features: -- Type-safe lazy loading of packages -- Support for nested module imports -- Auto-completion support in IDEs -- Thread-safe implementation -- Comprehensive test coverage -""" - -from types import ModuleType -from typing import ( - Optional, - Dict, - Any, - Callable, - Type, - TypeVar, - Union, - cast, -) -import importlib -import functools -import threading -from importlib.util import find_spec -from swarms.utils.auto_download_check_packages import ( - auto_check_and_download_package, -) - - -T = TypeVar("T") -C = TypeVar("C") - - -class ImportError(Exception): - """Raised when a lazy import fails.""" - - pass - - -class LazyLoader: - """ - A thread-safe lazy loader for Python packages that only imports them when accessed. - - Attributes: - _module_name (str): The name of the module to be lazily loaded - _module (Optional[ModuleType]): The cached module instance once loaded - _lock (threading.Lock): Thread lock for safe concurrent access - - Examples: - >>> np = LazyLoader('numpy') - >>> # numpy is not imported yet - >>> result = np.array([1, 2, 3]) - >>> # numpy is imported only when first used - """ - - def __init__(self, module_name: str) -> None: - """ - Initialize the lazy loader with a module name. - - Args: - module_name: The fully qualified name of the module to lazily load - - Raises: - ImportError: If the module cannot be found in sys.path - """ - self._module_name = module_name - self._module: Optional[ModuleType] = None - self._lock = threading.Lock() - - auto_check_and_download_package( - module_name, package_manager="pip" - ) - - # Verify module exists without importing it - if find_spec(module_name) is None: - raise ImportError( - f"Module '{module_name}' not found in sys.path" - ) - - def _load_module(self) -> ModuleType: - """ - Thread-safe module loading. - - Returns: - ModuleType: The loaded module - - Raises: - ImportError: If module import fails - """ - if self._module is None: - with self._lock: - # Double-check pattern - if self._module is None: - try: - self._module = importlib.import_module( - self._module_name - ) - except Exception as e: - raise ImportError( - f"Failed to import '{self._module_name}': {str(e)}" - ) - return cast(ModuleType, self._module) - - def __getattr__(self, name: str) -> Any: - """ - Intercepts attribute access to load the module if needed. - - Args: - name: The attribute name being accessed - - Returns: - Any: The requested attribute from the loaded module - - Raises: - AttributeError: If the attribute doesn't exist in the module - """ - module = self._load_module() - try: - return getattr(module, name) - except AttributeError: - raise AttributeError( - f"Module '{self._module_name}' has no attribute '{name}'" - ) - - def __dir__(self) -> list[str]: - """ - Returns list of attributes for autocomplete support. - - Returns: - List[str]: Available attributes in the module - """ - return dir(self._load_module()) - - def is_loaded(self) -> bool: - """ - Check if the module has been loaded. - - Returns: - bool: True if module is loaded, False otherwise - """ - return self._module is not None - - -class LazyLoaderMetaclass(type): - """Metaclass to handle lazy loading behavior""" - - def __call__(cls, *args, **kwargs): - if hasattr(cls, "_lazy_loader"): - return super().__call__(*args, **kwargs) - return super().__call__(*args, **kwargs) - - -class LazyClassLoader: - """ - A descriptor that creates the actual class only when accessed, - with proper inheritance support. - """ - - def __init__( - self, class_name: str, bases: tuple, namespace: Dict[str, Any] - ): - self.class_name = class_name - self.bases = bases - self.namespace = namespace - self._real_class: Optional[Type] = None - self._lock = threading.Lock() - - def _create_class(self) -> Type: - """Creates the actual class if it hasn't been created yet.""" - if self._real_class is None: - with self._lock: - if self._real_class is None: - # Update namespace to include metaclass - namespace = dict(self.namespace) - namespace["__metaclass__"] = LazyLoaderMetaclass - - # Create the class with metaclass - new_class = LazyLoaderMetaclass( - self.class_name, self.bases, namespace - ) - - # Store reference to this loader - new_class._lazy_loader = self - self._real_class = new_class - - return cast(Type, self._real_class) - - def __call__(self, *args: Any, **kwargs: Any) -> Any: - """Creates an instance of the lazy loaded class.""" - real_class = self._create_class() - # Use the metaclass __call__ method - return real_class(*args, **kwargs) - - def __instancecheck__(self, instance: Any) -> bool: - """Support for isinstance() checks""" - real_class = self._create_class() - return isinstance(instance, real_class) - - def __subclasscheck__(self, subclass: Type) -> bool: - """Support for issubclass() checks""" - real_class = self._create_class() - return issubclass(subclass, real_class) - - -def lazy_import(*names: str) -> Dict[str, LazyLoader]: - """ - Create multiple lazy loaders at once. - - Args: - *names: Module names to create lazy loaders for - - Returns: - Dict[str, LazyLoader]: Dictionary mapping module names to their lazy loaders - - Examples: - >>> modules = lazy_import('numpy', 'pandas', 'matplotlib.pyplot') - >>> np = modules['numpy'] - >>> pd = modules['pandas'] - >>> plt = modules['matplotlib.pyplot'] - """ - return {name.split(".")[-1]: LazyLoader(name) for name in names} - - -def lazy_import_decorator( - target: Union[Callable[..., T], Type[C]] -) -> Union[Callable[..., T], Type[C], LazyClassLoader]: - """ - Enhanced decorator that supports both lazy imports and lazy class loading. - """ - if isinstance(target, type): - # Store the original class details - namespace = { - name: value - for name, value in target.__dict__.items() - if not name.startswith("__") - or name in ("__init__", "__new__") - } - - # Create lazy loader - loader = LazyClassLoader( - target.__name__, target.__bases__, namespace - ) - - # Preserve class metadata - loader.__module__ = target.__module__ - loader.__doc__ = target.__doc__ - - # Add reference to original class - loader._original_class = target - - return loader - else: - # Handle function decoration - @functools.wraps(target) - def wrapper(*args: Any, **kwargs: Any) -> T: - return target(*args, **kwargs) - - return wrapper diff --git a/swarms/utils/litellm_tokenizer.py b/swarms/utils/litellm_tokenizer.py index 1db46aee7..2d7cae4c7 100644 --- a/swarms/utils/litellm_tokenizer.py +++ b/swarms/utils/litellm_tokenizer.py @@ -1,5 +1,6 @@ import subprocess + def count_tokens(text: str, model: str = "gpt-4o") -> int: """Count the number of tokens in the given text.""" try: @@ -8,10 +9,8 @@ def count_tokens(text: str, model: str = "gpt-4o") -> int: subprocess.run(["pip", "install", "litellm"]) from litellm import encode - return len(encode(model=model, text=text)) - # if __name__ == "__main__": # print(count_tokens("Hello, how are you?")) diff --git a/swarms/utils/wrapper_clusterop.py b/swarms/utils/wrapper_clusterop.py index 646383c64..7dc6d8558 100644 --- a/swarms/utils/wrapper_clusterop.py +++ b/swarms/utils/wrapper_clusterop.py @@ -1,3 +1,4 @@ +import platform from typing import Any @@ -53,6 +54,14 @@ def exec_callable_with_clusterops( logger.info(f"Attempting to run on device: {device}") device = device.lower() + # Check if the platform is Windows and do nothing if true + if platform.system() == "Windows": + if enable_logging: + logger.info( + "Platform is Windows, not executing on device." + ) + return None + if device == "cpu": if enable_logging: logger.info("Device set to CPU") diff --git a/tests/utils/test_auto_check_download.py b/tests/utils/test_auto_check_download.py index 0a4ad157d..ac8fee3d2 100644 --- a/tests/utils/test_auto_check_download.py +++ b/tests/utils/test_auto_check_download.py @@ -1,65 +1,104 @@ -from swarms.utils.auto_download_check_packages import auto_check_and_download_package, check_and_install_package +from swarms.utils.auto_download_check_packages import ( + auto_check_and_download_package, + check_and_install_package, +) + def test_check_and_install_package_pip(): result = check_and_install_package("numpy", package_manager="pip") print(f"Test result for 'numpy' installation using pip: {result}") assert result, "Failed to install or verify 'numpy' using pip" + def test_check_and_install_package_conda(): - result = check_and_install_package("numpy", package_manager="conda") - print(f"Test result for 'numpy' installation using conda: {result}") + result = check_and_install_package( + "numpy", package_manager="conda" + ) + print( + f"Test result for 'numpy' installation using conda: {result}" + ) assert result, "Failed to install or verify 'numpy' using conda" + def test_check_and_install_specific_version(): - result = check_and_install_package("numpy", package_manager="pip", version="1.21.0") - print(f"Test result for specific version of 'numpy' installation using pip: {result}") - assert result, "Failed to install or verify specific version of 'numpy' using pip" + result = check_and_install_package( + "numpy", package_manager="pip", version="1.21.0" + ) + print( + f"Test result for specific version of 'numpy' installation using pip: {result}" + ) + assert ( + result + ), "Failed to install or verify specific version of 'numpy' using pip" + def test_check_and_install_with_upgrade(): - result = check_and_install_package("numpy", package_manager="pip", upgrade=True) + result = check_and_install_package( + "numpy", package_manager="pip", upgrade=True + ) print(f"Test result for 'numpy' upgrade using pip: {result}") assert result, "Failed to upgrade 'numpy' using pip" + def test_auto_check_and_download_single_package(): - result = auto_check_and_download_package("scipy", package_manager="pip") + result = auto_check_and_download_package( + "scipy", package_manager="pip" + ) print(f"Test result for 'scipy' installation using pip: {result}") assert result, "Failed to install or verify 'scipy' using pip" + def test_auto_check_and_download_multiple_packages(): packages = ["scipy", "pandas"] - result = auto_check_and_download_package(packages, package_manager="pip") - print(f"Test result for multiple packages installation using pip: {result}") - assert result, f"Failed to install or verify one or more packages in {packages} using pip" + result = auto_check_and_download_package( + packages, package_manager="pip" + ) + print( + f"Test result for multiple packages installation using pip: {result}" + ) + assert ( + result + ), f"Failed to install or verify one or more packages in {packages} using pip" + def test_auto_check_and_download_multiple_packages_with_versions(): packages = ["numpy:1.21.0", "pandas:1.3.0"] - result = auto_check_and_download_package(packages, package_manager="pip") - print(f"Test result for multiple packages with versions installation using pip: {result}") - assert result, f"Failed to install or verify one or more packages in {packages} with specific versions using pip" + result = auto_check_and_download_package( + packages, package_manager="pip" + ) + print( + f"Test result for multiple packages with versions installation using pip: {result}" + ) + assert ( + result + ), f"Failed to install or verify one or more packages in {packages} with specific versions using pip" + # Example of running tests if __name__ == "__main__": try: test_check_and_install_package_pip() print("test_check_and_install_package_pip passed") - + test_check_and_install_package_conda() print("test_check_and_install_package_conda passed") - + test_check_and_install_specific_version() print("test_check_and_install_specific_version passed") - + test_check_and_install_with_upgrade() print("test_check_and_install_with_upgrade passed") - + test_auto_check_and_download_single_package() print("test_auto_check_and_download_single_package passed") - + test_auto_check_and_download_multiple_packages() print("test_auto_check_and_download_multiple_packages passed") - + test_auto_check_and_download_multiple_packages_with_versions() - print("test_auto_check_and_download_multiple_packages_with_versions passed") - + print( + "test_auto_check_and_download_multiple_packages_with_versions passed" + ) + except AssertionError as e: print(f"Test failed: {str(e)}")