Skip to content

Commit e8f005e

Browse files
authored
Merge pull request #2910 from dokson/fix/curl-cffi-cache-attr-detection
Fix: don't treat curl_cffi>=0.16 sessions as caching (presence of .cache != active cache)
2 parents 38c73ce + e5f9079 commit e8f005e

2 files changed

Lines changed: 36 additions & 35 deletions

File tree

‎tests/test_data.py‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
import unittest
33
from functools import lru_cache
44

5+
from yfinance._http import new_session
56
from yfinance.data import SingletonMeta, YfData, _normalize_proxy, lru_cache_freezeargs
7+
from yfinance.exceptions import YFDataException
68
from yfinance.utils import frozendict
79

810

@@ -141,5 +143,31 @@ def test_optimistic_login_survives_strategy_toggle(self):
141143
self.assertEqual(self.data._session.cookies.get("Y"), "Y-opt")
142144

143145

146+
class TestSetSessionCacheDetection(unittest.TestCase):
147+
"""A session is caching only when a cache is active, not when `.cache` merely exists.
148+
149+
curl_cffi >= 0.16 Sessions always expose `.cache` (None when disabled).
150+
"""
151+
152+
def setUp(self):
153+
SingletonMeta._instances.pop(YfData, None)
154+
self.data = YfData()
155+
156+
def tearDown(self):
157+
SingletonMeta._instances.pop(YfData, None)
158+
159+
def test_session_with_disabled_cache_is_accepted(self):
160+
session = new_session()
161+
session.cache = None
162+
self.data._set_session(session)
163+
self.assertIs(self.data._session, session)
164+
165+
def test_session_with_active_cache_is_rejected(self):
166+
session = new_session()
167+
session.cache = object()
168+
with self.assertRaises(YFDataException):
169+
self.data._set_session(session)
170+
171+
144172
if __name__ == "__main__":
145173
unittest.main()

‎yfinance/data.py‎

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,9 @@ def _set_session(self, session):
137137
if session is None:
138138
return
139139

140-
try:
141-
session.cache
142-
except AttributeError:
143-
# Not caching
144-
self._session_is_caching = False
145-
else:
146-
# Is caching. This is annoying.
147-
# Can't simply use a non-caching session to fetch cookie & crumb,
148-
# because then the caching-session won't have cookie.
149-
self._session_is_caching = True
150-
# requests_cache wraps the stdlib Session; it doesn't work with
151-
# curl_cffi and tends to miss anyway because the Yahoo crumb rotates.
140+
# Test for an active cache, not the attribute's presence: curl_cffi >= 0.16
141+
# Sessions always expose `.cache` (None when disabled).
142+
if getattr(session, "cache", None) is not None:
152143
raise YFDataException("Caching sessions (e.g. requests_cache) are not supported. Solution: stop setting session, let yfinance handle.")
153144

154145
if not is_supported_session(session):
@@ -269,11 +260,7 @@ def _get_crumb_basic(self, timeout=30):
269260
'timeout': timeout,
270261
'allow_redirects': True
271262
}
272-
if self._session_is_caching:
273-
get_args['expire_after'] = self._expire_after
274-
crumb_response = self._session.get(**get_args)
275-
else:
276-
crumb_response = self._session.get(**get_args)
263+
crumb_response = self._session.get(**get_args)
277264
self._crumb = crumb_response.text
278265
if crumb_response.status_code == 429 or "Too Many Requests" in self._crumb:
279266
utils.get_yf_logger().debug(f"Didn't receive crumb {self._crumb}")
@@ -308,11 +295,7 @@ def _get_cookie_csrf(self, timeout):
308295

309296
get_args = {**base_args, 'url': 'https://guce.yahoo.com/consent'}
310297
try:
311-
if self._session_is_caching:
312-
get_args['expire_after'] = self._expire_after
313-
response = self._session.get(**get_args)
314-
else:
315-
response = self._session.get(**get_args)
298+
response = self._session.get(**get_args)
316299
except requests.exceptions.ChunkedEncodingError:
317300
# No idea why happens, but handle nicely so can switch to other cookie method.
318301
utils.get_yf_logger().debug('_get_cookie_csrf() encountering requests.exceptions.ChunkedEncodingError, aborting')
@@ -346,14 +329,8 @@ def _get_cookie_csrf(self, timeout):
346329
'url': f'https://guce.yahoo.com/copyConsent?sessionId={sessionId}',
347330
'data': data}
348331
try:
349-
if self._session_is_caching:
350-
post_args['expire_after'] = self._expire_after
351-
get_args['expire_after'] = self._expire_after
352-
self._session.post(**post_args)
353-
self._session.get(**get_args)
354-
else:
355-
self._session.post(**post_args)
356-
self._session.get(**get_args)
332+
self._session.post(**post_args)
333+
self._session.get(**get_args)
357334
except requests.exceptions.ChunkedEncodingError:
358335
# No idea why happens, but handle nicely so can switch to other cookie method.
359336
utils.get_yf_logger().debug('_get_cookie_csrf() encountering requests.exceptions.ChunkedEncodingError, aborting')
@@ -376,11 +353,7 @@ def _get_crumb_csrf(self, timeout=30):
376353
get_args = {
377354
'url': 'https://query2.finance.yahoo.com/v1/test/getcrumb',
378355
'timeout': timeout}
379-
if self._session_is_caching:
380-
get_args['expire_after'] = self._expire_after
381-
r = self._session.get(**get_args)
382-
else:
383-
r = self._session.get(**get_args)
356+
r = self._session.get(**get_args)
384357
self._crumb = r.text
385358

386359
if r.status_code == 429 or "Too Many Requests" in self._crumb:

0 commit comments

Comments
 (0)