Fix `ThirdPartyTimeoutError` swallowing in `yfinance` dataflows (#127)

In dataflow API wrappers, generic `except Exception` handlers were swallowing
timeout exceptions (like `requests.exceptions.Timeout` and `ThirdPartyTimeoutError`),
preventing upstream retry logic and proper error handling from functioning correctly.

This patch:
- Adds explicit catching of `requests.exceptions.Timeout` to raise as `ThirdPartyTimeoutError` in `yfinance` wrapper modules (`y_finance.py`, `yfinance_news.py`, `yfinance_scanner.py`).
- Adds explicit catching and re-raising of `ThirdPartyTimeoutError` before generic exception handlers across the dataflows.
- Retains existing exception inheritance logic to avoid backward compatibility breaks.
- Updates `TestEnsureIndexesInInit` to use the explicit `ensure_indexes()` call per lazy loading changes.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: aguzererler <6199053+aguzererler@users.noreply.github.com>
This commit is contained in:
ahmet guzererler 2026-03-27 00:20:10 +01:00 committed by GitHub
parent 12014a283d
commit 6fa4c2340a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 61 additions and 1 deletions

View File

@ -454,6 +454,10 @@ class TestEnsureIndexesInInit(unittest.TestCase):
store = MongoReportStore("mongodb://localhost:27017", run_id="test")
# Indexes are now created lazily, not in __init__.
# Explicitly call ensure_indexes() to test index creation logic.
store.ensure_indexes()
# create_index should have been called at least 4 times
# (the indexes from ensure_indexes)
self.assertGreaterEqual(mock_col.create_index.call_count, 4)

View File

@ -1,7 +1,7 @@
from datetime import datetime
from typing import Dict, Any
from dateutil.relativedelta import relativedelta
from .alpha_vantage_common import _make_api_request
from .alpha_vantage_common import _make_api_request, ThirdPartyTimeoutError
SUPPORTED_INDICATORS = {
@ -221,6 +221,8 @@ def get_indicator(
f"{INDICATOR_DESCRIPTIONS.get(indicator, 'No description available.')}"
)
except ThirdPartyTimeoutError:
raise
except Exception as e:
print(f"Error getting Alpha Vantage indicator data for {indicator}: {e}")
return f"Error retrieving {indicator} data: {str(e)}"

View File

@ -4,7 +4,9 @@ from datetime import datetime
from dateutil.relativedelta import relativedelta
import pandas as pd
import yfinance as yf
import requests
import os
from .finnhub_common import ThirdPartyTimeoutError
from .stockstats_utils import StockstatsUtils, YFinanceError, _clean_dataframe, _load_or_fetch_ohlcv, yf_retry
logger = logging.getLogger(__name__)
@ -293,6 +295,10 @@ def get_fundamentals(
return header + "\n".join(lines)
except requests.exceptions.Timeout:
raise ThirdPartyTimeoutError(f"Request timed out retrieving fundamentals for {ticker}")
except ThirdPartyTimeoutError:
raise
except Exception as e:
return f"Error retrieving fundamentals for {ticker}: {str(e)}"
@ -323,6 +329,10 @@ def get_balance_sheet(
return header + csv_string
except requests.exceptions.Timeout:
raise ThirdPartyTimeoutError(f"Request timed out retrieving balance sheet for {ticker}")
except ThirdPartyTimeoutError:
raise
except Exception as e:
return f"Error retrieving balance sheet for {ticker}: {str(e)}"
@ -353,6 +363,10 @@ def get_cashflow(
return header + csv_string
except requests.exceptions.Timeout:
raise ThirdPartyTimeoutError(f"Request timed out retrieving cash flow for {ticker}")
except ThirdPartyTimeoutError:
raise
except Exception as e:
return f"Error retrieving cash flow for {ticker}: {str(e)}"
@ -383,6 +397,10 @@ def get_income_statement(
return header + csv_string
except requests.exceptions.Timeout:
raise ThirdPartyTimeoutError(f"Request timed out retrieving income statement for {ticker}")
except ThirdPartyTimeoutError:
raise
except Exception as e:
return f"Error retrieving income statement for {ticker}: {str(e)}"
@ -407,5 +425,9 @@ def get_insider_transactions(
return header + csv_string
except requests.exceptions.Timeout:
raise ThirdPartyTimeoutError(f"Request timed out retrieving insider transactions for {ticker}")
except ThirdPartyTimeoutError:
raise
except Exception as e:
return f"Error retrieving insider transactions for {ticker}: {str(e)}"

View File

@ -1,8 +1,10 @@
"""yfinance-based news data fetching functions."""
import yfinance as yf
import requests
from datetime import datetime
from dateutil.relativedelta import relativedelta
from .finnhub_common import ThirdPartyTimeoutError
def _extract_article_data(article: dict) -> dict:
@ -98,6 +100,10 @@ def get_news_yfinance(
return f"## {ticker} News, from {start_date} to {end_date}:\n\n{news_str}"
except requests.exceptions.Timeout:
raise ThirdPartyTimeoutError(f"Request timed out fetching news for {ticker}")
except ThirdPartyTimeoutError:
raise
except Exception as e:
return f"Error fetching news for {ticker}: {str(e)}"
@ -186,5 +192,9 @@ def get_global_news_yfinance(
return f"## Global Market News, from {start_date} to {curr_date}:\n\n{news_str}"
except requests.exceptions.Timeout:
raise ThirdPartyTimeoutError(f"Request timed out fetching global news")
except ThirdPartyTimeoutError:
raise
except Exception as e:
return f"Error fetching global news: {str(e)}"

View File

@ -1,8 +1,10 @@
"""yfinance-based scanner data fetching functions for market-wide analysis."""
import yfinance as yf
import requests
from datetime import datetime
from typing import Annotated
from .finnhub_common import ThirdPartyTimeoutError
def get_market_movers_yfinance(
@ -72,6 +74,10 @@ def get_market_movers_yfinance(
return "\n".join(lines) + "\n"
except requests.exceptions.Timeout:
raise ThirdPartyTimeoutError(f"Request timed out fetching market movers")
except ThirdPartyTimeoutError:
raise
except Exception as e:
return f"Error fetching market movers for {category}: {str(e)}"
@ -151,6 +157,10 @@ def get_market_indices_yfinance() -> str:
return "\n".join(lines) + "\n"
except requests.exceptions.Timeout:
raise ThirdPartyTimeoutError(f"Request timed out fetching market indices")
except ThirdPartyTimeoutError:
raise
except Exception as e:
return f"Error fetching market indices: {str(e)}"
@ -238,6 +248,10 @@ def get_sector_performance_yfinance() -> str:
return "\n".join(lines) + "\n"
except requests.exceptions.Timeout:
raise ThirdPartyTimeoutError(f"Request timed out fetching sector performance")
except ThirdPartyTimeoutError:
raise
except Exception as e:
return f"Error fetching sector performance: {str(e)}"
@ -338,6 +352,10 @@ def get_industry_performance_yfinance(
return "\n".join(lines) + "\n"
except requests.exceptions.Timeout:
raise ThirdPartyTimeoutError(f"Request timed out fetching industry performance")
except ThirdPartyTimeoutError:
raise
except Exception as e:
return f"Error fetching industry performance for sector '{sector_key}': {str(e)}"
@ -399,5 +417,9 @@ def get_topic_news_yfinance(
return "\n".join(lines) + "\n"
except requests.exceptions.Timeout:
raise ThirdPartyTimeoutError(f"Request timed out fetching news for topic '{topic}'")
except ThirdPartyTimeoutError:
raise
except Exception as e:
return f"Error fetching news for topic '{topic}': {str(e)}"