Skip to content

Commit 9581b8b

Browse files
authored
Merge pull request #1705 from ranaroussi/fix/tz-cache-init
Fix TZ cache exception blocking import
2 parents 95ef486 + 62b2c25 commit 9581b8b

File tree

3 files changed

+89
-62
lines changed

3 files changed

+89
-62
lines changed

tests/ticker.py

Lines changed: 54 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -152,22 +152,10 @@ def test_goodTicker_withProxy(self):
152152
tkr = "IBM"
153153
dat = yf.Ticker(tkr, session=self.session)
154154

155-
dat._fetch_ticker_tz(proxy=self.proxy, timeout=5, debug_mode=False, raise_errors=False)
156-
dat._get_ticker_tz(proxy=self.proxy, timeout=5, debug_mode=False, raise_errors=False)
155+
dat._fetch_ticker_tz(proxy=self.proxy, timeout=5)
156+
dat._get_ticker_tz(proxy=self.proxy, timeout=5)
157157
dat.history(period="1wk", proxy=self.proxy)
158158

159-
v = dat.stats(proxy=self.proxy)
160-
self.assertIsNotNone(v)
161-
self.assertTrue(len(v) > 0)
162-
163-
v = dat.get_recommendations(proxy=self.proxy)
164-
self.assertIsNotNone(v)
165-
self.assertFalse(v.empty)
166-
167-
v = dat.get_calendar(proxy=self.proxy)
168-
self.assertIsNotNone(v)
169-
self.assertFalse(v.empty)
170-
171159
v = dat.get_major_holders(proxy=self.proxy)
172160
self.assertIsNotNone(v)
173161
self.assertFalse(v.empty)
@@ -184,38 +172,6 @@ def test_goodTicker_withProxy(self):
184172
self.assertIsNotNone(v)
185173
self.assertTrue(len(v) > 0)
186174

187-
v = dat.get_sustainability(proxy=self.proxy)
188-
self.assertIsNotNone(v)
189-
self.assertFalse(v.empty)
190-
191-
v = dat.get_recommendations_summary(proxy=self.proxy)
192-
self.assertIsNotNone(v)
193-
self.assertFalse(v.empty)
194-
195-
v = dat.get_analyst_price_target(proxy=self.proxy)
196-
self.assertIsNotNone(v)
197-
self.assertFalse(v.empty)
198-
199-
v = dat.get_rev_forecast(proxy=self.proxy)
200-
self.assertIsNotNone(v)
201-
self.assertFalse(v.empty)
202-
203-
v = dat.get_earnings_forecast(proxy=self.proxy)
204-
self.assertIsNotNone(v)
205-
self.assertFalse(v.empty)
206-
207-
v = dat.get_trend_details(proxy=self.proxy)
208-
self.assertIsNotNone(v)
209-
self.assertFalse(v.empty)
210-
211-
v = dat.get_earnings_trend(proxy=self.proxy)
212-
self.assertIsNotNone(v)
213-
self.assertFalse(v.empty)
214-
215-
v = dat.get_earnings(proxy=self.proxy)
216-
self.assertIsNotNone(v)
217-
self.assertFalse(v.empty)
218-
219175
v = dat.get_income_stmt(proxy=self.proxy)
220176
self.assertIsNotNone(v)
221177
self.assertFalse(v.empty)
@@ -244,10 +200,6 @@ def test_goodTicker_withProxy(self):
244200
self.assertIsNotNone(v)
245201
self.assertFalse(v.empty)
246202

247-
v = dat.get_shares(proxy=self.proxy)
248-
self.assertIsNotNone(v)
249-
self.assertFalse(v.empty)
250-
251203
v = dat.get_shares_full(proxy=self.proxy)
252204
self.assertIsNotNone(v)
253205
self.assertFalse(v.empty)
@@ -264,11 +216,60 @@ def test_goodTicker_withProxy(self):
264216
self.assertIsNotNone(v)
265217
self.assertFalse(v.empty)
266218

267-
# TODO: enable after merge
268-
# dat.get_history_metadata(proxy=self.proxy)
219+
dat.get_history_metadata(proxy=self.proxy)
220+
self.assertIsNotNone(v)
221+
self.assertTrue(len(v) > 0)
222+
223+
# Below will fail because not ported to Yahoo API
224+
225+
# v = dat.stats(proxy=self.proxy)
269226
# self.assertIsNotNone(v)
270227
# self.assertTrue(len(v) > 0)
271228

229+
# v = dat.get_recommendations(proxy=self.proxy)
230+
# self.assertIsNotNone(v)
231+
# self.assertFalse(v.empty)
232+
233+
# v = dat.get_calendar(proxy=self.proxy)
234+
# self.assertIsNotNone(v)
235+
# self.assertFalse(v.empty)
236+
237+
# v = dat.get_sustainability(proxy=self.proxy)
238+
# self.assertIsNotNone(v)
239+
# self.assertFalse(v.empty)
240+
241+
# v = dat.get_recommendations_summary(proxy=self.proxy)
242+
# self.assertIsNotNone(v)
243+
# self.assertFalse(v.empty)
244+
245+
# v = dat.get_analyst_price_target(proxy=self.proxy)
246+
# self.assertIsNotNone(v)
247+
# self.assertFalse(v.empty)
248+
249+
# v = dat.get_rev_forecast(proxy=self.proxy)
250+
# self.assertIsNotNone(v)
251+
# self.assertFalse(v.empty)
252+
253+
# v = dat.get_earnings_forecast(proxy=self.proxy)
254+
# self.assertIsNotNone(v)
255+
# self.assertFalse(v.empty)
256+
257+
# v = dat.get_trend_details(proxy=self.proxy)
258+
# self.assertIsNotNone(v)
259+
# self.assertFalse(v.empty)
260+
261+
# v = dat.get_earnings_trend(proxy=self.proxy)
262+
# self.assertIsNotNone(v)
263+
# self.assertFalse(v.empty)
264+
265+
# v = dat.get_earnings(proxy=self.proxy)
266+
# self.assertIsNotNone(v)
267+
# self.assertFalse(v.empty)
268+
269+
# v = dat.get_shares(proxy=self.proxy)
270+
# self.assertIsNotNone(v)
271+
# self.assertFalse(v.empty)
272+
272273

273274
class TestTickerHistory(unittest.TestCase):
274275
session = None
@@ -318,7 +319,7 @@ def test_no_expensive_calls_introduced(self):
318319
actual_urls_called = tuple([r.url for r in session.cache.filter()])
319320
session.close()
320321
expected_urls = (
321-
'https://query2.finance.yahoo.com/v8/finance/chart/GOOGL?events=div,splits,capitalGains&includePrePost=False&interval=1d&range=1y',
322+
'https://query2.finance.yahoo.com/v8/finance/chart/GOOGL?events=div%2Csplits%2CcapitalGains&includePrePost=False&interval=1d&range=1y',
322323
)
323324
self.assertEqual(expected_urls, actual_urls_called, "Different than expected url used to fetch history.")
324325

tests/utils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import unittest
1818
# import requests_cache
1919
import tempfile
20+
import os
2021

2122

2223
class TestUtils(unittest.TestCase):
@@ -40,6 +41,15 @@ def test_storeTzNoRaise(self):
4041
cache.store(tkr, tz1)
4142
cache.store(tkr, tz2)
4243

44+
def test_setTzCacheLocation(self):
45+
self.assertEqual(yf.utils._DBManager.get_location(), self.tempCacheDir.name)
46+
47+
tkr = 'AMZN'
48+
tz1 = "America/New_York"
49+
cache = yf.utils.get_tz_cache()
50+
cache.store(tkr, tz1)
51+
52+
self.assertTrue(os.path.exists(os.path.join(self.tempCacheDir.name, "tkr-tz.db")))
4353

4454
def suite():
4555
suite = unittest.TestSuite()

yfinance/utils.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -936,7 +936,8 @@ class _TzCacheManager:
936936
@classmethod
937937
def get_tz(cls):
938938
if cls._tz_cache is None:
939-
cls._initialise()
939+
with _cache_init_lock:
940+
cls._initialise()
940941
return cls._tz_cache
941942

942943
@classmethod
@@ -976,7 +977,13 @@ def _initialise(cls, cache_dir=None):
976977
cls._cache_dir = cache_dir
977978

978979
if not _os.path.isdir(cls._cache_dir):
979-
_os.mkdir(cls._cache_dir)
980+
try:
981+
_os.makedirs(cls._cache_dir)
982+
except OSError as err:
983+
raise _TzCacheException(f"Error creating TzCache folder: '{cls._cache_dir}' reason: {err}")
984+
elif not (_os.access(cls._cache_dir, _os.R_OK) and _os.access(cls._cache_dir, _os.W_OK)):
985+
raise _TzCacheException(f"Cannot read and write in TzCache folder: '{cls._cache_dir}'")
986+
980987
cls._db = _peewee.SqliteDatabase(
981988
_os.path.join(cls._cache_dir, 'tkr-tz.db'),
982989
pragmas={'journal_mode': 'wal', 'cache_size': -64}
@@ -987,10 +994,16 @@ def _initialise(cls, cache_dir=None):
987994
_os.remove(old_cache_file_path)
988995

989996
@classmethod
990-
def change_location(cls, new_cache_dir):
991-
cls._db.close()
992-
cls._db = None
997+
def set_location(cls, new_cache_dir):
998+
if cls._db is not None:
999+
cls._db.close()
1000+
cls._db = None
9931001
cls._cache_dir = new_cache_dir
1002+
1003+
@classmethod
1004+
def get_location(cls):
1005+
return cls._cache_dir
1006+
9941007
# close DB when Python exists
9951008
_atexit.register(_DBManager.close_db)
9961009

@@ -1000,7 +1013,11 @@ class _KV(_peewee.Model):
10001013
value = _peewee.CharField(null=True)
10011014

10021015
class Meta:
1003-
database = _DBManager.get_database()
1016+
try:
1017+
database = _DBManager.get_database()
1018+
except Exception:
1019+
# This code runs at import, so Logger won't be ready yet, so must discard exception.
1020+
database = None
10041021
without_rowid = True
10051022

10061023

@@ -1043,8 +1060,7 @@ def get_tz_cache():
10431060
dummy cache with same interface as real cash.
10441061
"""
10451062
# as this can be called from multiple threads, protect it.
1046-
with _cache_init_lock:
1047-
return _TzCacheManager.get_tz()
1063+
return _TzCacheManager.get_tz()
10481064

10491065

10501066
def set_tz_cache_location(cache_dir: str):
@@ -1055,4 +1071,4 @@ def set_tz_cache_location(cache_dir: str):
10551071
:param cache_dir: Path to use for caches
10561072
:return: None
10571073
"""
1058-
_DBManager.change_location(cache_dir)
1074+
_DBManager.set_location(cache_dir)

0 commit comments

Comments
 (0)