diff --git a/test_imports.py b/test_imports.py new file mode 100644 index 00000000..09d6e087 --- /dev/null +++ b/test_imports.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +"""Test imports to find slow modules.""" + +import time +import sys + +def time_import(module_name, import_statement): + """Time an import statement.""" + start = time.time() + try: + exec(import_statement) + elapsed = time.time() - start + print(f"✓ {module_name}: {elapsed:.2f}s") + return True + except Exception as e: + print(f"✗ {module_name}: {e}") + return False + +print("Testing imports...") +print("-" * 40) + +imports_to_test = [ + ("os", "import os"), + ("datetime", "from datetime import datetime"), + ("typing", "from typing import Annotated"), + ("unittest.mock", "from unittest.mock import Mock"), + ("pandas", "import pandas"), + ("numpy", "import numpy"), + ("yfinance", "import yfinance"), + ("openai", "from openai import OpenAI"), + ("langchain_core.messages", "from langchain_core.messages import HumanMessage"), + ("langchain_core.prompts", "from langchain_core.prompts import ChatPromptTemplate"), + ("langchain_core.tools", "from langchain_core.tools import tool"), +] + +total_start = time.time() +for name, stmt in imports_to_test: + time_import(name, stmt) + +print("-" * 40) +print(f"Total time: {time.time() - total_start:.2f}s") \ No newline at end of file diff --git a/test_minimal.py b/test_minimal.py new file mode 100644 index 00000000..1ffdf61f --- /dev/null +++ b/test_minimal.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +"""Minimal test to verify mock fixes without problematic imports.""" + +import sys +from unittest.mock import Mock, patch +import pytest + +# Mock the problematic imports +sys.modules['pandas'] = Mock() +sys.modules['yfinance'] = Mock() +sys.modules['openai'] = Mock() +sys.modules['tqdm'] = Mock() + + +def test_mock_toolkit_structure(): + """Test that mock toolkit has correct structure.""" + # Create mock toolkit + toolkit = Mock() + toolkit.config = {"online_tools": False} + + # Create proper mock functions + def mock_get_YFin_data(): + return "Mock data" + + toolkit.get_YFin_data = Mock(side_effect=mock_get_YFin_data) + toolkit.get_YFin_data.__name__ = "get_YFin_data" + toolkit.get_YFin_data.name = "get_YFin_data" + + # Test + assert hasattr(toolkit.get_YFin_data, '__name__') + assert toolkit.get_YFin_data.__name__ == "get_YFin_data" + assert callable(toolkit.get_YFin_data) + + # Test tool name extraction (what fails in actual tests) + tools = [toolkit.get_YFin_data] + tool_names = [tool.name for tool in tools] + assert "get_YFin_data" in tool_names + + print("✓ Mock toolkit structure test passed") + + +def test_mock_llm_bind_tools(): + """Test that mock LLM can bind tools properly.""" + # Create mock LLM + mock_llm = Mock() + mock_chain = Mock() + mock_llm.bind_tools = Mock(return_value=mock_chain) + + # Create mock tools + def tool1(): + pass + + def tool2(): + pass + + tools = [tool1, tool2] + + # Bind tools + result = mock_llm.bind_tools(tools) + + # Verify + assert result == mock_chain + mock_llm.bind_tools.assert_called_once_with(tools) + + print("✓ Mock LLM bind_tools test passed") + + +def test_tool_name_extraction(): + """Test various ways of extracting tool names.""" + # Method 1: Function with __name__ + def func1(): + pass + assert hasattr(func1, '__name__') + assert func1.__name__ == 'func1' + + # Method 2: Mock with __name__ set + mock_func = Mock() + mock_func.__name__ = 'mock_func' + mock_func.name = 'mock_func' + assert hasattr(mock_func, '__name__') + assert mock_func.__name__ == 'mock_func' + + # Method 3: Check both attributes + tools = [func1, mock_func] + names = [] + for tool in tools: + if hasattr(tool, 'name'): + names.append(tool.name) + elif hasattr(tool, '__name__'): + names.append(tool.__name__) + + assert 'func1' in names + assert 'mock_func' in names + + print("✓ Tool name extraction test passed") + + +if __name__ == "__main__": + print("Running minimal tests...") + print("-" * 40) + + test_mock_toolkit_structure() + test_mock_llm_bind_tools() + test_tool_name_extraction() + + print("-" * 40) + print("✅ All minimal tests passed!") \ No newline at end of file diff --git a/test_mock_fix.py b/test_mock_fix.py new file mode 100644 index 00000000..d72ac55e --- /dev/null +++ b/test_mock_fix.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +"""Test script to verify mock fixes without full imports.""" + +from unittest.mock import Mock + + +def create_mock_toolkit(): + """Create a properly mocked toolkit.""" + toolkit = Mock() + toolkit.config = {"online_tools": False} + + # Create proper mock functions with __name__ attributes + def mock_get_YFin_data(): + return "Mock YFin data" + + def mock_get_stockstats_indicators_report(): + return "Mock stockstats report" + + # Wrap functions in Mock but preserve __name__ + toolkit.get_YFin_data = Mock(side_effect=mock_get_YFin_data) + toolkit.get_YFin_data.name = "get_YFin_data" + toolkit.get_YFin_data.__name__ = "get_YFin_data" + + toolkit.get_stockstats_indicators_report = Mock( + side_effect=mock_get_stockstats_indicators_report + ) + toolkit.get_stockstats_indicators_report.name = "get_stockstats_indicators_report" + toolkit.get_stockstats_indicators_report.__name__ = "get_stockstats_indicators_report" + + return toolkit + + +def test_mock_has_name_attribute(): + """Test that mocked functions have __name__ attribute.""" + toolkit = create_mock_toolkit() + + # Check get_YFin_data + assert hasattr(toolkit.get_YFin_data, '__name__'), "get_YFin_data missing __name__" + assert toolkit.get_YFin_data.__name__ == "get_YFin_data", "get_YFin_data has wrong __name__" + assert callable(toolkit.get_YFin_data), "get_YFin_data is not callable" + + # Check get_stockstats_indicators_report + assert hasattr(toolkit.get_stockstats_indicators_report, '__name__'), \ + "get_stockstats_indicators_report missing __name__" + assert toolkit.get_stockstats_indicators_report.__name__ == "get_stockstats_indicators_report", \ + "get_stockstats_indicators_report has wrong __name__" + assert callable(toolkit.get_stockstats_indicators_report), \ + "get_stockstats_indicators_report is not callable" + + print("✓ All mock functions have proper __name__ attributes") + return True + + +def test_mock_can_be_used_as_tool(): + """Test that mocked functions can be used as tools.""" + toolkit = create_mock_toolkit() + + # Simulate what happens when tools are collected + tools = [ + toolkit.get_YFin_data, + toolkit.get_stockstats_indicators_report + ] + + # Check that we can get names from tools + tool_names = [] + for tool in tools: + if hasattr(tool, 'name'): + tool_names.append(tool.name) + elif hasattr(tool, '__name__'): + tool_names.append(tool.__name__) + else: + raise ValueError(f"Tool {tool} has neither 'name' nor '__name__' attribute") + + assert "get_YFin_data" in tool_names, "get_YFin_data not in tool names" + assert "get_stockstats_indicators_report" in tool_names, \ + "get_stockstats_indicators_report not in tool names" + + print(f"✓ Tools can be collected: {tool_names}") + return True + + +def test_mock_functions_return_correct_values(): + """Test that mock functions return expected values.""" + toolkit = create_mock_toolkit() + + # Test return values + result1 = toolkit.get_YFin_data() + assert result1 == "Mock YFin data", f"Unexpected return: {result1}" + + result2 = toolkit.get_stockstats_indicators_report() + assert result2 == "Mock stockstats report", f"Unexpected return: {result2}" + + # Test that Mock tracking works + assert toolkit.get_YFin_data.called, "get_YFin_data not marked as called" + assert toolkit.get_stockstats_indicators_report.called, \ + "get_stockstats_indicators_report not marked as called" + + print("✓ Mock functions return correct values and track calls") + return True + + +if __name__ == "__main__": + print("Testing mock toolkit fixes...") + print("-" * 40) + + tests = [ + test_mock_has_name_attribute, + test_mock_can_be_used_as_tool, + test_mock_functions_return_correct_values + ] + + all_passed = True + for test in tests: + try: + if not test(): + all_passed = False + print(f"✗ {test.__name__} failed") + except Exception as e: + all_passed = False + print(f"✗ {test.__name__} raised exception: {e}") + + print("-" * 40) + if all_passed: + print("✅ All tests passed! Mock fixes are working correctly.") + else: + print("❌ Some tests failed. Check the output above.") \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index fcb04492..c62588ec 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -92,23 +92,139 @@ def mock_toolkit(): toolkit = Mock() toolkit.config = {"online_tools": False} - # Mock data retrieval methods - toolkit.get_YFin_data = Mock() - toolkit.get_YFin_data_online = Mock() - toolkit.get_stockstats_indicators_report = Mock() - toolkit.get_stockstats_indicators_report_online = Mock() - toolkit.get_reddit_stock_info = Mock() - toolkit.get_stock_news_openai = Mock() - toolkit.get_finnhub_news = Mock() - toolkit.get_reddit_news = Mock() - toolkit.get_global_news_openai = Mock() - toolkit.get_google_news = Mock() - toolkit.get_fundamentals_openai = Mock() - toolkit.get_finnhub_company_insider_sentiment = Mock() - toolkit.get_finnhub_company_insider_transactions = Mock() - toolkit.get_simfin_balance_sheet = Mock() - toolkit.get_simfin_cashflow = Mock() - toolkit.get_simfin_income_stmt = Mock() + # Create mock functions with proper __name__ attributes + def mock_get_YFin_data(): + return "Mock YFin data" + + def mock_get_YFin_data_online(): + return "Mock YFin data online" + + def mock_get_stockstats_indicators_report(): + return "Mock stockstats report" + + def mock_get_stockstats_indicators_report_online(): + return "Mock stockstats report online" + + def mock_get_reddit_stock_info(): + return "Mock reddit stock info" + + def mock_get_stock_news_openai(): + return "Mock stock news" + + def mock_get_finnhub_news(): + return "Mock finnhub news" + + def mock_get_reddit_news(): + return "Mock reddit news" + + def mock_get_global_news_openai(): + return "Mock global news" + + def mock_get_google_news(): + return "Mock google news" + + def mock_get_fundamentals_openai(): + return "Mock fundamentals" + + def mock_get_finnhub_company_insider_sentiment(): + return "Mock insider sentiment" + + def mock_get_finnhub_company_insider_transactions(): + return "Mock insider transactions" + + def mock_get_simfin_balance_sheet(): + return "Mock balance sheet" + + def mock_get_simfin_cashflow(): + return "Mock cashflow" + + def mock_get_simfin_income_stmt(): + return "Mock income statement" + + # Assign the mock functions to the toolkit + toolkit.get_YFin_data = Mock(side_effect=mock_get_YFin_data) + toolkit.get_YFin_data.name = "get_YFin_data" + toolkit.get_YFin_data.__name__ = "get_YFin_data" + + toolkit.get_YFin_data_online = Mock(side_effect=mock_get_YFin_data_online) + toolkit.get_YFin_data_online.name = "get_YFin_data_online" + toolkit.get_YFin_data_online.__name__ = "get_YFin_data_online" + + toolkit.get_stockstats_indicators_report = Mock( + side_effect=mock_get_stockstats_indicators_report + ) + toolkit.get_stockstats_indicators_report.name = "get_stockstats_indicators_report" + toolkit.get_stockstats_indicators_report.__name__ = "get_stockstats_indicators_report" + + toolkit.get_stockstats_indicators_report_online = Mock( + side_effect=mock_get_stockstats_indicators_report_online + ) + toolkit.get_stockstats_indicators_report_online.name = ( + "get_stockstats_indicators_report_online" + ) + toolkit.get_stockstats_indicators_report_online.__name__ = ( + "get_stockstats_indicators_report_online" + ) + + toolkit.get_reddit_stock_info = Mock(side_effect=mock_get_reddit_stock_info) + toolkit.get_reddit_stock_info.name = "get_reddit_stock_info" + toolkit.get_reddit_stock_info.__name__ = "get_reddit_stock_info" + + toolkit.get_stock_news_openai = Mock(side_effect=mock_get_stock_news_openai) + toolkit.get_stock_news_openai.name = "get_stock_news_openai" + toolkit.get_stock_news_openai.__name__ = "get_stock_news_openai" + + toolkit.get_finnhub_news = Mock(side_effect=mock_get_finnhub_news) + toolkit.get_finnhub_news.name = "get_finnhub_news" + toolkit.get_finnhub_news.__name__ = "get_finnhub_news" + + toolkit.get_reddit_news = Mock(side_effect=mock_get_reddit_news) + toolkit.get_reddit_news.name = "get_reddit_news" + toolkit.get_reddit_news.__name__ = "get_reddit_news" + + toolkit.get_global_news_openai = Mock(side_effect=mock_get_global_news_openai) + toolkit.get_global_news_openai.name = "get_global_news_openai" + toolkit.get_global_news_openai.__name__ = "get_global_news_openai" + + toolkit.get_google_news = Mock(side_effect=mock_get_google_news) + toolkit.get_google_news.name = "get_google_news" + toolkit.get_google_news.__name__ = "get_google_news" + + toolkit.get_fundamentals_openai = Mock(side_effect=mock_get_fundamentals_openai) + toolkit.get_fundamentals_openai.name = "get_fundamentals_openai" + toolkit.get_fundamentals_openai.__name__ = "get_fundamentals_openai" + + toolkit.get_finnhub_company_insider_sentiment = Mock( + side_effect=mock_get_finnhub_company_insider_sentiment + ) + toolkit.get_finnhub_company_insider_sentiment.name = ( + "get_finnhub_company_insider_sentiment" + ) + toolkit.get_finnhub_company_insider_sentiment.__name__ = ( + "get_finnhub_company_insider_sentiment" + ) + + toolkit.get_finnhub_company_insider_transactions = Mock( + side_effect=mock_get_finnhub_company_insider_transactions + ) + toolkit.get_finnhub_company_insider_transactions.name = ( + "get_finnhub_company_insider_transactions" + ) + toolkit.get_finnhub_company_insider_transactions.__name__ = ( + "get_finnhub_company_insider_transactions" + ) + + toolkit.get_simfin_balance_sheet = Mock(side_effect=mock_get_simfin_balance_sheet) + toolkit.get_simfin_balance_sheet.name = "get_simfin_balance_sheet" + toolkit.get_simfin_balance_sheet.__name__ = "get_simfin_balance_sheet" + + toolkit.get_simfin_cashflow = Mock(side_effect=mock_get_simfin_cashflow) + toolkit.get_simfin_cashflow.name = "get_simfin_cashflow" + toolkit.get_simfin_cashflow.__name__ = "get_simfin_cashflow" + + toolkit.get_simfin_income_stmt = Mock(side_effect=mock_get_simfin_income_stmt) + toolkit.get_simfin_income_stmt.name = "get_simfin_income_stmt" + toolkit.get_simfin_income_stmt.__name__ = "get_simfin_income_stmt" return toolkit