Skip to content

Commit 941948d

Browse files
authored
Merge branch 'develop' into feature/refactor-imf
2 parents 4170d13 + 97cae93 commit 941948d

File tree

45 files changed

+100201
-102851
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+100201
-102851
lines changed

openbb_platform/providers/yfinance/openbb_yfinance/models/balance_sheet.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,23 +82,17 @@ def extract_data(
8282
"""Extract the data from the Yahoo Finance endpoints."""
8383
# pylint: disable=import-outside-toplevel
8484
import json # noqa
85-
from curl_adapter import CurlCffiAdapter
8685
from numpy import nan
8786
from openbb_core.provider.utils.errors import EmptyDataError
8887
from openbb_core.provider.utils.helpers import (
89-
get_requests_session,
9088
to_snake_case,
9189
)
9290
from yfinance import Ticker
9391

9492
period = "yearly" if query.period == "annual" else "quarterly" # type: ignore
95-
session = get_requests_session()
96-
session.mount("https://", CurlCffiAdapter())
97-
session.mount("http://", CurlCffiAdapter())
98-
data = Ticker(
99-
query.symbol,
100-
session=session,
101-
).get_balance_sheet(as_dict=False, pretty=False, freq=period)
93+
data = Ticker(query.symbol).get_balance_sheet(
94+
as_dict=False, pretty=False, freq=period
95+
)
10296

10397
if data is None:
10498
raise EmptyDataError()

openbb_platform/providers/yfinance/openbb_yfinance/models/cash_flow.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,24 +79,17 @@ def extract_data(
7979
"""Extract the data from the Yahoo Finance endpoints."""
8080
# pylint: disable=import-outside-toplevel
8181
import json # noqa
82-
from curl_adapter import CurlCffiAdapter
8382
from numpy import nan
8483
from openbb_core.provider.utils.errors import EmptyDataError
8584
from openbb_core.provider.utils.helpers import (
86-
get_requests_session,
8785
to_snake_case,
8886
)
8987
from yfinance import Ticker
9088

9189
period = "yearly" if query.period == "annual" else "quarterly" # type: ignore
92-
session = get_requests_session()
93-
session.mount("https://", CurlCffiAdapter())
94-
session.mount("http://", CurlCffiAdapter())
95-
96-
data = Ticker(
97-
query.symbol,
98-
session=session,
99-
).get_cash_flow(as_dict=False, pretty=False, freq=period)
90+
data = Ticker(query.symbol).get_cash_flow(
91+
as_dict=False, pretty=False, freq=period
92+
)
10093

10194
if data is None:
10295
raise EmptyDataError()

openbb_platform/providers/yfinance/openbb_yfinance/models/company_news.py

Lines changed: 86 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -50,57 +50,97 @@ def transform_query(params: dict[str, Any]) -> YFinanceCompanyNewsQueryParams:
5050

5151
@staticmethod
5252
async def aextract_data(
53-
query: YFinanceCompanyNewsQueryParams,
54-
credentials: dict[str, str] | None,
55-
**kwargs: Any,
53+
query,
54+
credentials=None,
55+
**kwargs,
5656
) -> list[dict]:
57-
"""Extract data."""
57+
"""Extract the raw data from YFinance and normalize to CompanyNewsData schema."""
5858
# pylint: disable=import-outside-toplevel
59-
import asyncio # noqa
60-
from curl_adapter import CurlCffiAdapter
59+
import asyncio
60+
from warnings import warn
61+
6162
from openbb_core.provider.utils.errors import EmptyDataError
62-
from openbb_core.provider.utils.helpers import get_requests_session
6363
from yfinance import Ticker
6464

65-
results: list = []
66-
symbols = query.symbol.split(",") # type: ignore
67-
session = get_requests_session()
68-
session.mount("https://", CurlCffiAdapter())
69-
session.mount("http://", CurlCffiAdapter())
70-
71-
async def get_one(symbol):
72-
data = Ticker(symbol, session=session).get_news(
73-
count=query.limit,
74-
tab="all",
75-
)
76-
for d in data:
77-
new_content: dict = {}
78-
content = d.get("content")
79-
if not content:
80-
continue
81-
if thumbnail := content.get("thumbnail"):
82-
images = thumbnail.get("resolutions")
83-
if images:
84-
new_content["images"] = [
85-
{k: str(v) for k, v in img.items()} for img in images
86-
]
87-
new_content["url"] = content.get("canonicalUrl", {}).get("url")
88-
new_content["source"] = content.get("provider", {}).get("displayName")
89-
new_content["title"] = content.get("title")
90-
new_content["date"] = content.get("pubDate")
91-
description = content.get("description")
92-
summary = content.get("summary")
93-
94-
if description:
95-
new_content["text"] = description
96-
elif summary:
97-
new_content["text"] = summary
98-
99-
results.append(new_content)
100-
101-
tasks = [get_one(symbol) for symbol in symbols]
102-
103-
await asyncio.gather(*tasks)
65+
symbols = [s.strip() for s in query.symbol.split(",") if s.strip()]
66+
results: list[dict] = []
67+
68+
def _normalize_news_item(item: dict, sym: str) -> dict | None:
69+
"""Flatten the response."""
70+
if not isinstance(item, dict):
71+
return None
72+
73+
content = item.get("content")
74+
if not isinstance(content, dict):
75+
return None
76+
77+
title = content.get("title") or content.get("summary")
78+
# Prefer clickThroughUrl; fallback to canonicalUrl; fallback to previewUrl
79+
url = None
80+
ctu = content.get("clickThroughUrl")
81+
if isinstance(ctu, dict):
82+
url = ctu.get("url")
83+
if not url:
84+
can = content.get("canonicalUrl")
85+
if isinstance(can, dict):
86+
url = can.get("url")
87+
if not url:
88+
url = content.get("previewUrl")
89+
90+
date = content.get("pubDate") or content.get("displayTime")
91+
92+
# Optional fields
93+
provider = content.get("provider")
94+
source = provider.get("displayName") if isinstance(provider, dict) else None
95+
summary = content.get("summary") or content.get("description") or ""
96+
97+
# If CompanyNewsData requires these, don't emit invalid items
98+
if not (sym and title and url and date):
99+
return None
100+
101+
# CompanyNewsData typically includes: symbol, title, url, date, summary/text
102+
# We include both "summary" and "text" to be resilient across schema variants.
103+
normalized: dict[str, Any] = {
104+
"symbol": sym,
105+
"title": title,
106+
"url": url,
107+
"date": date,
108+
"source": source,
109+
}
110+
# Only add if non-empty to avoid weird validation rules
111+
if summary:
112+
normalized["summary"] = summary
113+
normalized["text"] = summary
114+
115+
# Keep an id if present (harmless if the model ignores it)
116+
if item.get("id"):
117+
normalized["id"] = item["id"]
118+
elif content.get("id"):
119+
normalized["id"] = content["id"]
120+
121+
return normalized
122+
123+
def _fetch_news(sym: str) -> list[dict]:
124+
"""Fetch the data in a worker thread."""
125+
raw = Ticker(sym).get_news() or []
126+
out: list[dict] = []
127+
for item in raw:
128+
norm = _normalize_news_item(item, sym)
129+
if norm:
130+
out.append(norm)
131+
return out
132+
133+
async def get_one(sym: str) -> None:
134+
"""Get the data for one ticker symbol."""
135+
try:
136+
items = await asyncio.to_thread(_fetch_news, sym)
137+
except Exception as e:
138+
warn(f"Error getting news for {sym}: {e}")
139+
return
140+
if items:
141+
results.extend(items)
142+
143+
await asyncio.gather(*(get_one(sym) for sym in symbols))
104144

105145
if not results:
106146
raise EmptyDataError("No data was returned for the given symbol(s)")

openbb_platform/providers/yfinance/openbb_yfinance/models/equity_profile.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,8 @@ async def aextract_data(
119119
"""Extract the raw data from YFinance."""
120120
# pylint: disable=import-outside-toplevel
121121
import asyncio # noqa
122-
from curl_adapter import CurlCffiAdapter
123122
from openbb_core.app.model.abstract.error import OpenBBError
124123
from openbb_core.provider.utils.errors import EmptyDataError
125-
from openbb_core.provider.utils.helpers import get_requests_session
126124
from warnings import warn
127125
from yfinance import Ticker
128126

@@ -157,19 +155,13 @@ async def aextract_data(
157155
"beta",
158156
]
159157
messages: list = []
160-
session = get_requests_session()
161-
session.mount("https://", CurlCffiAdapter())
162-
session.mount("http://", CurlCffiAdapter())
163158

164159
async def get_one(symbol):
165160
"""Get the data for one ticker symbol."""
166161
result: dict = {}
167162
ticker: dict = {}
168163
try:
169-
ticker = Ticker(
170-
symbol,
171-
session=session,
172-
).get_info()
164+
ticker = await asyncio.to_thread(lambda: Ticker(symbol).get_info())
173165
except Exception as e:
174166
messages.append(
175167
f"Error getting data for {symbol} -> {e.__class__.__name__}: {e}"

openbb_platform/providers/yfinance/openbb_yfinance/models/equity_quote.py

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,11 @@ async def aextract_data(
7878
"""Extract the raw data from YFinance."""
7979
# pylint: disable=import-outside-toplevel
8080
import asyncio # noqa
81-
from curl_adapter import CurlCffiAdapter
82-
from openbb_core.provider.utils.helpers import get_requests_session
8381
from yfinance import Ticker
8482

85-
session = get_requests_session()
86-
session.mount("https://", CurlCffiAdapter())
87-
session.mount("http://", CurlCffiAdapter())
83+
symbols = [s.strip() for s in query.symbol.split(",") if s.strip()]
84+
results: list[dict] = []
8885

89-
symbols = query.symbol.split(",")
90-
results = []
9186
fields = [
9287
"symbol",
9388
"longName",
@@ -112,28 +107,18 @@ async def aextract_data(
112107
"currency",
113108
]
114109

115-
async def get_one(symbol):
116-
"""Get the data for one ticker symbol."""
117-
result: dict = {}
118-
ticker: dict = {}
110+
async def get_one(symbol: str) -> None:
119111
try:
120-
ticker = Ticker(
121-
symbol,
122-
session=session,
123-
).get_info()
112+
ticker = await asyncio.to_thread(lambda: Ticker(symbol).get_info())
124113
except Exception as e:
125114
warn(f"Error getting data for {symbol}: {e}")
126-
if ticker:
127-
for field in fields:
128-
if field in ticker:
129-
result[field] = ticker.get(field, None)
130-
if result:
131-
results.append(result)
115+
return
132116

133-
tasks = [get_one(symbol) for symbol in symbols]
134-
135-
await asyncio.gather(*tasks)
117+
result = {f: ticker.get(f) for f in fields if f in ticker}
118+
if result:
119+
results.append(result)
136120

121+
await asyncio.gather(*(get_one(symbol) for symbol in symbols))
137122
return results
138123

139124
@staticmethod

openbb_platform/providers/yfinance/openbb_yfinance/models/etf_info.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,9 @@ async def aextract_data(
211211
"""Extract the raw data from YFinance."""
212212
# pylint: disable=import-outside-toplevel
213213
import asyncio # noqa
214-
from curl_adapter import CurlCffiAdapter
215214
from openbb_core.app.model.abstract.error import OpenBBError
216215
from openbb_core.provider.utils.errors import EmptyDataError
217216
from openbb_core.provider.utils.helpers import (
218-
get_requests_session,
219217
safe_fromtimestamp,
220218
)
221219
from warnings import warn
@@ -263,19 +261,13 @@ async def aextract_data(
263261
"firstTradeDateEpochUtc",
264262
]
265263
messages: list = []
266-
session = get_requests_session()
267-
session.mount("https://", CurlCffiAdapter())
268-
session.mount("http://", CurlCffiAdapter())
269264

270265
async def get_one(symbol):
271266
"""Get the data for one ticker symbol."""
272267
result: dict = {}
273268
ticker: dict = {}
274269
try:
275-
ticker = Ticker(
276-
symbol,
277-
session=session,
278-
).get_info()
270+
ticker = await asyncio.to_thread(lambda: Ticker(symbol).get_info())
279271
except Exception as e:
280272
messages.append(
281273
f"Error getting data for {symbol} -> {e.__class__.__name__}: {e}"

openbb_platform/providers/yfinance/openbb_yfinance/models/historical_dividends.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,10 @@ def extract_data(
4141
) -> list[dict]:
4242
"""Extract the raw data from YFinance."""
4343
# pylint: disable=import-outside-toplevel
44-
from curl_adapter import CurlCffiAdapter
45-
from openbb_core.provider.utils.helpers import get_requests_session
4644
from yfinance import Ticker
4745

48-
session = get_requests_session()
49-
session.mount("https://", CurlCffiAdapter())
50-
session.mount("http://", CurlCffiAdapter())
51-
5246
try:
53-
ticker = Ticker(
54-
query.symbol,
55-
session=session,
56-
).get_dividends()
47+
ticker = Ticker(query.symbol).get_dividends()
5748
if isinstance(ticker, list) and not ticker or ticker.empty: # type: ignore
5849
raise OpenBBError(f"No dividend data found for {query.symbol}")
5950
except Exception as e:

openbb_platform/providers/yfinance/openbb_yfinance/models/income_statement.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,24 +82,17 @@ def extract_data(
8282
"""Extract the data from the Yahoo Finance endpoints."""
8383
# pylint: disable=import-outside-toplevel
8484
import json # noqa
85-
from curl_adapter import CurlCffiAdapter
8685
from numpy import nan
8786
from openbb_core.provider.utils.errors import EmptyDataError
8887
from openbb_core.provider.utils.helpers import (
89-
get_requests_session,
9088
to_snake_case,
9189
)
9290
from yfinance import Ticker
9391

9492
period = "yearly" if query.period == "annual" else "quarterly"
95-
session = get_requests_session()
96-
session.mount("https://", CurlCffiAdapter())
97-
session.mount("http://", CurlCffiAdapter())
98-
99-
data = Ticker(
100-
query.symbol,
101-
session=session,
102-
).get_income_stmt(as_dict=False, pretty=False, freq=period)
93+
data = Ticker(query.symbol).get_income_stmt(
94+
as_dict=False, pretty=False, freq=period
95+
)
10396

10497
if data is None:
10598
raise EmptyDataError()

openbb_platform/providers/yfinance/openbb_yfinance/models/key_executives.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,11 @@ def extract_data(
5858
) -> list[dict]:
5959
"""Extract the raw data from YFinance."""
6060
# pylint: disable=import-outside-toplevel
61-
from curl_adapter import CurlCffiAdapter # noqa
6261
from openbb_core.app.model.abstract.error import OpenBBError
63-
from openbb_core.provider.utils.helpers import get_requests_session
6462
from yfinance import Ticker
6563

66-
session = get_requests_session()
67-
session.mount("https://", CurlCffiAdapter())
68-
session.mount("http://", CurlCffiAdapter())
69-
7064
try:
71-
ticker = Ticker(
72-
query.symbol,
73-
session=session,
74-
).get_info()
65+
ticker = Ticker(query.symbol).get_info()
7566
except Exception as e:
7667
raise OpenBBError(
7768
f"Error getting data for {query.symbol} -> {e.__class__.__name__}: {e}"

0 commit comments

Comments
 (0)