From db670aefd73ead89cfd7f317da1fc6137b904b53 Mon Sep 17 00:00:00 2001 From: Value Raider Date: Wed, 20 Dec 2023 23:58:50 +0000 Subject: [PATCH] Fix invalid date entering cache DB 'peewee.DateTimeField' is not ISO-compliant. If user enforces strict ISO-compliance, then translation between DateTimeField and sqlite breaks. Fix is to manually implement translation. --- yfinance/cache.py | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/yfinance/cache.py b/yfinance/cache.py index d1acf2810..d625a2ab2 100644 --- a/yfinance/cache.py +++ b/yfinance/cache.py @@ -197,17 +197,6 @@ def get_tz_cache(): return _TzCacheManager.get_tz_cache() -def set_tz_cache_location(cache_dir: str): - """ - Sets the path to create the "py-yfinance" cache folder in. - Useful if the default folder returned by "appdir.user_cache_dir()" is not writable. - Must be called before cache is used (that is, before fetching tickers). - :param cache_dir: Path to use for caches - :return: None - """ - _TzDBManager.set_location(cache_dir) - - # -------------- # Cookie cache @@ -300,9 +289,21 @@ def get_location(cls): Cookie_db_proxy = _peewee.Proxy() +class ISODateTimeField(_peewee.DateTimeField): + # Ensure Python datetime is read & written correctly for sqlite, + # because user discovered peewee allowed an invalid datetime + # to get written. + def db_value(self, value): + if value and isinstance(value, _datetime.datetime): + return value.isoformat() + return super().db_value(value) + def python_value(self, value): + if value and isinstance(value, str) and 'T' in value: + return _datetime.datetime.fromisoformat(value) + return super().python_value(value) class _CookieSchema(_peewee.Model): strategy = _peewee.CharField(primary_key=True) - fetch_date = _peewee.DateTimeField(default=_datetime.datetime.now) + fetch_date = ISODateTimeField(default=_datetime.datetime.now) # Which cookie type depends on strategy cookie_bytes = _peewee.BlobField() @@ -398,3 +399,19 @@ def store(self, strategy, cookie): def get_cookie_cache(): return _CookieCacheManager.get_cookie_cache() + + +def set_cache_location(cache_dir: str): + """ + Sets the path to create the "py-yfinance" cache folder in. + Useful if the default folder returned by "appdir.user_cache_dir()" is not writable. + Must be called before cache is used (that is, before fetching tickers). + :param cache_dir: Path to use for caches + :return: None + """ + _TzDBManager.set_location(cache_dir) + _CookieDBManager.set_location(cache_dir) + +def set_tz_cache_location(cache_dir: str): + set_cache_location(cache_dir) +