Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
from langchain_community.tools.financial_datasets.cash_flow_statements import (
CashFlowStatements,
)
from langchain_community.tools.financial_datasets.financial_metrics import (
FinancialMetrics,
)
from langchain_community.tools.financial_datasets.financial_snapshots import (
FinancialSnapshots,
)
from langchain_community.tools.financial_datasets.income_statements import (
IncomeStatements,
)
Expand Down Expand Up @@ -41,4 +47,6 @@ def get_tools(self) -> List[BaseTool]:
BalanceSheets(api_wrapper=self.api_wrapper),
CashFlowStatements(api_wrapper=self.api_wrapper),
IncomeStatements(api_wrapper=self.api_wrapper),
FinancialMetrics(api_wrapper=self.api_wrapper),
FinancialSnapshots(api_wrapper=self.api_wrapper),
]
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
from langchain_community.tools.financial_datasets.cash_flow_statements import (
CashFlowStatements,
)
from langchain_community.tools.financial_datasets.financial_metrics import (
FinancialMetrics,
)
from langchain_community.tools.financial_datasets.financial_snapshots import (
FinancialSnapshots,
)
from langchain_community.tools.financial_datasets.income_statements import (
IncomeStatements,
)
Expand All @@ -14,4 +20,6 @@
"BalanceSheets",
"CashFlowStatements",
"IncomeStatements",
"FinancialMetrics",
"FinancialSnapshots",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from typing import Optional, Type

from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field

from langchain_community.utilities.financial_datasets import FinancialDatasetsAPIWrapper


class FinancialMetricsSchema(BaseModel):
"""Input for FinancialMetrics."""

ticker: str = Field(
description="The ticker symbol to fetch financial metrics for.",
)
period: str = Field(
description="The period of the financial metrics. "
"Possible values are: "
"annual, quarterly, ttm. "
"Default is 'annual'.",
)
Comment on lines +16 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The period field in the schema is required (no default value) but the implementation treats it as optional with a default of 'annual'. This mismatch will force users to always provide a period value even though the description says "Default is 'annual'" and the API wrapper uses kwargs.get("period", "annual") on line 203. This will cause the tool to fail validation when users expect to rely on the default.

Fix by making the field optional with a default:

period: str = Field(
    default="annual",
    description="The period of the financial metrics. "
    "Possible values are: "
    "annual, quarterly, ttm.",
)
Suggested change
period: str = Field(
description="The period of the financial metrics. "
"Possible values are: "
"annual, quarterly, ttm. "
"Default is 'annual'.",
)
period: str = Field(
default="annual",
description="The period of the financial metrics. "
"Possible values are: "
"annual, quarterly, ttm.",
)

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

limit: int = Field(
description="The number of financial metrics to return. Default is 10.",
)
Comment on lines +22 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The limit field in the schema is required (no default value) but the implementation treats it as optional with a default of 10. The _run method signature shows limit: Optional[int] on line 53, and the API wrapper uses kwargs.get("limit", 10) on line 204. This mismatch will force users to always provide a limit value even though the description says "Default is 10." This will cause validation errors when users expect to rely on the default.

Fix by making the field optional with a default:

limit: int = Field(
    default=10,
    description="The number of financial metrics to return.",
)
Suggested change
limit: int = Field(
description="The number of financial metrics to return. Default is 10.",
)
limit: int = Field(
default=10,
description="The number of financial metrics to return.",
)

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.



class FinancialMetrics(BaseTool):
"""
Tool that gets financial metrics for a given ticker over a given period.
"""

mode: str = "get_financial_metrics"
name: str = "financial_metrics"
description: str = (
"A wrapper around financial datasets's financial metrics API. "
"This tool is useful for fetching financial metrics for a given ticker."
"The tool fetches financial metrics for a given ticker over a given period."
"The period can be annual, quarterly, or trailing twelve months (ttm)."
"The number of financial metrics to return can also be "
"specified using the limit parameter."
)
args_schema: Type[FinancialMetricsSchema] = FinancialMetricsSchema

api_wrapper: FinancialDatasetsAPIWrapper = Field(..., exclude=True)

def __init__(self, api_wrapper: FinancialDatasetsAPIWrapper):
super().__init__(api_wrapper=api_wrapper)
Comment on lines +46 to +47
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The init method violates the 'Use Google-Style Docstrings (with Args section)' rule. This public method lacks a Google-style docstring with an Args section. It should include documentation explaining the api_wrapper parameter. Add a docstring like: '''Initialize the FinancialMetrics tool.

Args:
api_wrapper: The FinancialDatasetsAPIWrapper instance for API calls.'''

Suggested change
def __init__(self, api_wrapper: FinancialDatasetsAPIWrapper):
super().__init__(api_wrapper=api_wrapper)
def __init__(self, api_wrapper: FinancialDatasetsAPIWrapper):
"""Initialize the FinancialMetrics tool.
Args:
api_wrapper: The FinancialDatasetsAPIWrapper instance for API calls.
"""
super().__init__(api_wrapper=api_wrapper)

Spotted by Graphite Agent (based on custom rule: Code quality)

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.


def _run(
self,
ticker: str,
period: str,
limit: Optional[int],
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the financial metrics API tool."""
return self.api_wrapper.run(
mode=self.mode,
ticker=ticker,
period=period,
limit=limit,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from typing import Optional, Type

from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field

from langchain_community.utilities.financial_datasets import FinancialDatasetsAPIWrapper


class FinancialSnapshotsSchema(BaseModel):
"""Input for FinancialSnapshots."""

ticker: str = Field(
description="The ticker symbol to fetch financial snapshots for.",
)


class FinancialSnapshots(BaseTool):
"""
Tool that gets financial snapshots for a given ticker over a given period.
"""

mode: str = "get_financial_snapshots"
name: str = "financial_snapshots"
description: str = (
"A wrapper around financial datasets's financial snapshots API. "
"This tool is useful for fetching financial snapshots for a given ticker."
"The tool fetches financial snapshots for a given ticker."
)
args_schema: Type[FinancialSnapshotsSchema] = FinancialSnapshotsSchema

api_wrapper: FinancialDatasetsAPIWrapper = Field(..., exclude=True)

def __init__(self, api_wrapper: FinancialDatasetsAPIWrapper):
super().__init__(api_wrapper=api_wrapper)
Comment on lines +34 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The init method violates the 'Use Google-Style Docstrings (with Args section)' rule. This public method lacks a Google-style docstring with an Args section. It should include documentation explaining the api_wrapper parameter. Add a docstring like: '''Initialize the FinancialSnapshots tool.

Args:
api_wrapper: The FinancialDatasetsAPIWrapper instance for API calls.'''

Suggested change
def __init__(self, api_wrapper: FinancialDatasetsAPIWrapper):
super().__init__(api_wrapper=api_wrapper)
def __init__(self, api_wrapper: FinancialDatasetsAPIWrapper):
"""Initialize the FinancialSnapshots tool.
Args:
api_wrapper: The FinancialDatasetsAPIWrapper instance for API calls.
"""
super().__init__(api_wrapper=api_wrapper)

Spotted by Graphite Agent (based on custom rule: Code quality)

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.


def _run(
self,
ticker: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the financial snapshots API tool."""
return self.api_wrapper.run(mode=self.mode, ticker=ticker)
62 changes: 62 additions & 0 deletions libs/community/langchain_community/utilities/financial_datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,62 @@ def get_cash_flow_statements(

return data.get("cash_flow_statements", None)

def get_financial_metrics(
self,
ticker: str,
period: str,
limit: Optional[int],
) -> List[dict]:
"""
Get the financial metrics for a stock `ticker` over a `period` of time.

:param ticker: the stock ticker
:param period: the period of time to get the balance sheets for.
Possible values are: annual, quarterly, ttm.
:param limit: the number of results to return, default is 10
:return: a list of financial metrics
"""

url = (
f"{FINANCIAL_DATASETS_BASE_URL}/financial-metrics"
f"?ticker={ticker}"
f"&period={period}"
f"&limit={limit if limit else 10}"
)

# Add the api key to the headers
headers = {"X-API-KEY": self._api_key}

# Execute the request
response = requests.get(url, headers=headers)
data = response.json()

return data.get("financial_metrics", None)

def get_financial_snapshots(
self,
ticker: str,
) -> dict:
"""
Get the financial snapshots for a stock `ticker`.

:param ticker: the stock ticker
"""

url = (
f"{FINANCIAL_DATASETS_BASE_URL}/financial-metrics/snapshot"
f"?ticker={ticker}"
)

# Add the api key to the headers
headers = {"X-API-KEY": self._api_key}

# Execute the request
response = requests.get(url, headers=headers)
data = response.json()

return data.get("snapshot", None)

def run(self, mode: str, ticker: str, **kwargs: Any) -> str:
if mode == "get_income_statements":
period = kwargs.get("period", "annual")
Expand All @@ -143,5 +199,11 @@ def run(self, mode: str, ticker: str, **kwargs: Any) -> str:
period = kwargs.get("period", "annual")
limit = kwargs.get("limit", 10)
return json.dumps(self.get_cash_flow_statements(ticker, period, limit))
elif mode == "get_financial_metrics":
period = kwargs.get("period", "annual")
limit = kwargs.get("limit", 10)
return json.dumps(self.get_financial_metrics(ticker, period, limit))
elif mode == "get_financial_snapshots":
return json.dumps(self.get_financial_snapshots(ticker))
else:
raise ValueError(f"Invalid mode {mode} for financial datasets API.")
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import os

from langchain_community.agent_toolkits.financial_datasets.toolkit import (
FinancialDatasetsToolkit,
)
from langchain_community.utilities.financial_datasets import FinancialDatasetsAPIWrapper

api_wrapper = FinancialDatasetsAPIWrapper(
financial_datasets_api_key=os.environ["FINANCIAL_DATASETS_API_KEY"]
)
toolkit = FinancialDatasetsToolkit(api_wrapper=api_wrapper)