Repository: ranaroussi/yfinance

Issue:
dev: Cannot run tests from command-line
> python -m tests.ticker

This used to work with old test code containing just a simple `unittest.main()`, but fails with new suite. Am I being dumb?

> Traceback (most recent call last):
>   File "/usr/lib64/python3.10/unittest/case.py", line 366, in __init__
>     testMethod = getattr(self, methodName)
> AttributeError: 'TestTicker' object has no attribute 'Test ticker'
> 
> During handling of the above exception, another exception occurred:
> 
> Traceback (most recent call last):
>   File "/usr/lib64/python3.10/runpy.py", line 196, in _run_module_as_main
>     return _run_code(code, main_globals, None,
>   File "/usr/lib64/python3.10/runpy.py", line 86, in _run_code
>     exec(code, run_globals)
>   File "yfinance-tz-cache/tests/ticker.py", line 288, in <module>
>     runner.run(suite())
>   File "yfinance-tz-cache/tests/ticker.py", line 279, in suite
>     suite.addTest(TestTicker('Test ticker'))
>   File "/usr/lib64/python3.10/unittest/case.py", line 371, in __init__
>     raise ValueError("no such test method in %s: %s" %
> ValueError: no such test method in <class '__main__.TestTicker'>: Test ticker

@fredrik-corneliusson 


Discussion:

Resolving patch:
diff --git a/yfinance/base.py b/yfinance/base.py
--- a/yfinance/base.py
+++ b/yfinance/base.py
@@ -869,7 +869,7 @@ def cleanup(data):
 
         # generic patterns
         for name in ["income", "balance-sheet", "cash-flow"]:
-            annual, qtr = self._create_financials_table(name, financials_data, proxy)
+            annual, qtr = self._create_financials_table(name, proxy)
             if annual is not None:
                 self._financials[name]["yearly"] = annual
             if qtr is not None:
@@ -977,7 +977,7 @@ def cleanup(data):
 
         self._fundamentals = True
 
-    def _create_financials_table(self, name, financials_data, proxy):
+    def _create_financials_table(self, name, proxy):
         acceptable_names = ["income", "balance-sheet", "cash-flow"]
         if not name in acceptable_names:
             raise Exception("name '{}' must be one of: {}".format(name, acceptable_names))
@@ -986,6 +986,8 @@ def _create_financials_table(self, name, financials_data, proxy):
             # Yahoo stores the 'income' table internally under 'financials' key
             name = "financials"
 
+        ticker_url = "{}/{}".format(self._scrape_url, self.ticker)
+        data_stores = self._data.get_json_data_stores(ticker_url + '/' + name, proxy)
         _stmt_annual = None
         _stmt_qtr = None
         try:
@@ -993,8 +995,8 @@ def _create_financials_table(self, name, financials_data, proxy):
             # visible on Yahoo website. But more work needed to make it user-friendly! Ideally
             # return a tree data structure instead of Pandas MultiIndex
             # So until this is implemented, just return simple tables
-            _stmt_annual = self._data.get_financials_time_series(name, "annual", financials_data, proxy)
-            _stmt_qtr = self._data.get_financials_time_series(name, "quarterly", financials_data, proxy)
+            _stmt_annual = self._data.get_financials_time_series("annual", data_stores, proxy)
+            _stmt_qtr = self._data.get_financials_time_series("quarterly", data_stores, proxy)
 
             # template_ttm_order, template_annual_order, template_order, level_detail = utils.build_template(data_store["FinancialTemplateStore"])
             # TTM_dicts, Annual_dicts = utils.retreive_financial_details(data_store['QuoteTimeSeriesStore'])
diff --git a/yfinance/data.py b/yfinance/data.py
--- a/yfinance/data.py
+++ b/yfinance/data.py
@@ -86,11 +86,8 @@ def get_json_data_stores(self, url, proxy=None):
         return json.loads(new_data)
 
     # Note cant use lru_cache as financials_data is a nested dict (freezeargs only handle flat dicts)
-    def get_financials_time_series(self, name, timescale, financials_data, proxy=None):
+    def get_financials_time_series(self, timescale, financials_data, proxy=None):
 
-        acceptable_names = ["financials", "balance-sheet", "cash-flow"]
-        if name not in acceptable_names:
-            raise Exception("name '{}' must be one of: {}".format(name, acceptable_names))
         acceptable_timestamps = ["annual", "quarterly"]
         if timescale not in acceptable_timestamps:
             raise Exception("timescale '{}' must be one of: {}".format(timescale, acceptable_timestamps))


Test patch:
diff --git a/tests/ticker.py b/tests/ticker.py
--- a/tests/ticker.py
+++ b/tests/ticker.py
@@ -1,28 +1,40 @@
+"""
+Tests for Ticker
+
+To run all tests in suite from commandline:
+   python -m unittest tests.ticker
+
+Specific test class:
+   python -m unittest tests.ticker.TestTicker
+
+"""
 import pandas as pd
 
 from .context import yfinance as yf
 
 import unittest
+import requests_cache
 
-log_requests = False
+# Set this to see the exact requests that are made during tests
+DEBUG_LOG_REQUESTS = True
 
-if log_requests:
+if DEBUG_LOG_REQUESTS:
     import logging
 
     logging.basicConfig(level=logging.DEBUG)
 
-# Create temp session
-import requests_cache, tempfile
-td = tempfile.TemporaryDirectory()
 
 class TestTicker(unittest.TestCase):
-    def setUp(self):
-        global td
-        self.td = td
-        self.session = requests_cache.CachedSession(self.td.name + '/' + "yfinance.cache")
+    session = None
 
-    def tearDown(self):
-        self.session.close()
+    @classmethod
+    def setUpClass(cls):
+        cls.session = requests_cache.CachedSession()
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.session is not None:
+            cls.session.close()
 
     def test_getTz(self):
         tkrs = ["IMP.JO", "BHG.JO", "SSW.JO", "BP.L", "INTC"]
@@ -74,6 +86,7 @@ def test_badTicker(self):
         dat.earnings_dates
         dat.earnings_forecasts
 
+
 class TestTickerEarnings(unittest.TestCase):
 
     def setUp(self):
@@ -173,33 +186,41 @@ def tearDown(self):
         self.ticker = None
 
     def test_balance_sheet(self):
+        expected_row = "TotalAssets"
         data = self.ticker.balance_sheet
         self.assertIsInstance(data, pd.DataFrame, "data has wrong type")
         self.assertFalse(data.empty, "data is empty")
+        self.assertIn(expected_row, data.index, "Did not find expected row in index")
 
         data_cached = self.ticker.balance_sheet
         self.assertIs(data, data_cached, "data not cached")
 
     def test_quarterly_balance_sheet(self):
+        expected_row = "TotalAssets"
         data = self.ticker.quarterly_balance_sheet
         self.assertIsInstance(data, pd.DataFrame, "data has wrong type")
         self.assertFalse(data.empty, "data is empty")
+        self.assertIn(expected_row, data.index, "Did not find expected row in index")
 
         data_cached = self.ticker.quarterly_balance_sheet
         self.assertIs(data, data_cached, "data not cached")
 
     def test_cashflow(self):
+        expected_row = "OperatingCashFlow"
         data = self.ticker.cashflow
         self.assertIsInstance(data, pd.DataFrame, "data has wrong type")
         self.assertFalse(data.empty, "data is empty")
+        self.assertIn(expected_row, data.index, "Did not find expected row in index")
 
         data_cached = self.ticker.cashflow
         self.assertIs(data, data_cached, "data not cached")
 
     def test_quarterly_cashflow(self):
+        expected_row = "OperatingCashFlow"
         data = self.ticker.quarterly_cashflow
         self.assertIsInstance(data, pd.DataFrame, "data has wrong type")
         self.assertFalse(data.empty, "data is empty")
+        self.assertIn(expected_row, data.index, "Did not find expected row in index")
 
         data_cached = self.ticker.quarterly_cashflow
         self.assertIs(data, data_cached, "data not cached")
@@ -271,10 +292,9 @@ def suite():
     suite.addTest(TestTicker('Test ticker'))
     suite.addTest(TestTickerEarnings('Test earnings'))
     suite.addTest(TestTickerHolders('Test holders'))
-    suite.addTest(TestTickerMiscFinancials('Test balance sheet'))
+    suite.addTest(TestTickerMiscFinancials('Test misc financials'))
     return suite
 
 
 if __name__ == '__main__':
-    runner = unittest.TextTestRunner()
-    runner.run(suite())
+    unittest.main()