refactor(yahoo-finance): Refactor Yahoo Finance API component to support tool mode (#5434)

* refactor(yahoo-finance): Refactor Yahoo Finance API component

* fix(yahoo-finance): Revert method input changes and fix enum error

* fix: update yfinance tool test and remove duplicate method

* fix: rename component class to avoid conflict with legacy version

* [autofix.ci] apply automated fixes

* test: add ToolException import to yfinance tool tests

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
This commit is contained in:
Raphael Valdetaro 2025-01-20 12:07:37 -03:00 • committed by GitHub
commit 06139ef2df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 226 additions and 12 deletions

View file

@ -1,14 +1,83 @@
from langflow.components.tools import YfinanceToolComponent
from langflow.custom import Component
from unittest.mock import MagicMock, patch
import pytest
from langchain_core.tools import ToolException
from langflow.components.tools import YfinanceComponent
from langflow.components.tools.yahoo import YahooFinanceMethod
from langflow.custom.utils import build_custom_component_template
from langflow.schema import Data
def test_yfinance_tool_template():
yf_tool = YfinanceToolComponent()
component = Component(_code=yf_tool._code)
frontend_node, _ = build_custom_component_template(component)
assert "outputs" in frontend_node
output_names = [output["name"] for output in frontend_node["outputs"]]
assert "api_run_model" in output_names
assert "api_build_tool" in output_names
assert all(output["types"] != [] for output in frontend_node["outputs"])
class TestYfinanceComponent:
@pytest.fixture
def component_class(self):
return YfinanceComponent
@pytest.fixture
def default_kwargs(self):
return {"symbol": "AAPL", "method": YahooFinanceMethod.GET_INFO, "num_news": 5, "_session_id": "test-session"}
@pytest.fixture
def file_names_mapping(self):
return []
def test_initialization(self, component_class):
component = component_class()
assert component.display_name == "Yahoo Finance"
assert component.icon == "trending-up"
assert "yfinance" in component.description
def test_template_structure(self, component_class):
component = component_class()
frontend_node, _ = build_custom_component_template(component)
assert "template" in frontend_node
input_names = [input_["name"] for input_ in frontend_node["template"].values() if isinstance(input_, dict)]
expected_inputs = ["symbol", "method", "num_news"]
for input_name in expected_inputs:
assert input_name in input_names
@patch("langflow.components.tools.yahoo.yf.Ticker")
def test_fetch_info(self, mock_ticker, component_class, default_kwargs):
component = component_class(**default_kwargs)
# Setup mock
mock_instance = MagicMock()
mock_ticker.return_value = mock_instance
mock_instance.info = {"companyName": "Apple Inc."}
result = component.fetch_content()
assert isinstance(result, list)
assert len(result) == 1
assert "Apple Inc." in result[0].text
@patch("langflow.components.tools.yahoo.yf.Ticker")
def test_fetch_news(self, mock_ticker, component_class):
component = component_class(symbol="AAPL", method=YahooFinanceMethod.GET_NEWS, num_news=2)
# Setup mock
mock_instance = MagicMock()
mock_ticker.return_value = mock_instance
mock_instance.news = [
{"title": "News 1", "link": "http://example.com/1"},
{"title": "News 2", "link": "http://example.com/2"},
]
result = component.fetch_content()
assert isinstance(result, list)
assert len(result) == 2
assert all(isinstance(item, Data) for item in result)
assert "News 1" in result[0].text
assert "http://example.com/1" in result[0].text
def test_error_handling(self, component_class, default_kwargs):
component = component_class(**default_kwargs)
with patch.object(component, "_fetch_yfinance_data") as mock_fetch:
mock_fetch.side_effect = Exception("API Error")
with pytest.raises(ToolException):
component.fetch_content()