diff --git a/CHANGES b/CHANGES index e94806f..5d6a214 100644 --- a/CHANGES +++ b/CHANGES @@ -20,3 +20,4 @@ 1.1 08/23/2018 -- Fixed net income python 3 error 1.2 08/29/2018 -- Fixed timezone error in python testing. Issue #11. 1.2 08/29/2018 -- Fixed unicode formatted_date string for consistency. +1.3 10/25/2018 -- Added patch for reported bug described in Issue #14. diff --git a/README.rst b/README.rst index 5fec5b7..e3e25e8 100644 --- a/README.rst +++ b/README.rst @@ -7,9 +7,9 @@ A python module that returns stock, cryptocurrency, forex, mutual fund, commodit .. image:: https://travis-ci.org/JECSand/yahoofinancials.svg?branch=master :target: https://travis-ci.org/JECSand/yahoofinancials -Current Version: v1.2 +Current Version: v1.3 -Version Released: 08/29/2018 +Version Released: 10/25/2018 Report any bugs by opening an issue here: https://github.com/JECSand/yahoofinancials/issues @@ -21,8 +21,8 @@ A powerful financial data module used for pulling both fundamental and technical Installation ------------ -- yahoofinancials runs fine on most versions of python 2 and 3. -- It was built and tested using versions 2.7 and 3.5 +- yahoofinancials runs on Python 2.7, 3.3, 3.4, 3.5, and 3.6. +- Python 3.7 support is coming soon. - The package depends on beautifulsoup4 and pytz to work. 1. Installation using pip: @@ -67,7 +67,7 @@ Module Methods -------------- - The financial data from all methods is returned as JSON. - You can run multiple symbols at once using an inputted array or run an individual symbol using an inputted string. -- YahooFinancials works on most versions of python 2 and 3 and runs on all operating systems. (Windows, Mac, Linux). +- YahooFinancials works with Python 2.7, 3.3, 3.4, 3.5, and 3.6 and runs on all operating systems. (Windows, Mac, Linux). Featured Methods ^^^^^^^^^^^^^^^^ diff --git a/setup.py b/setup.py index 731bcb2..5f43629 100644 --- a/setup.py +++ b/setup.py @@ -10,15 +10,15 @@ setup( name='yahoofinancials', - version='1.2', + version='1.3', description='A powerful financial data module used for pulling both fundamental and technical data from Yahoo Finance', long_description=long_description, url='https://github.com/JECSand/yahoofinancials', - download_url='https://github.com/JECSand/yahoofinancials/archive/1.2.tar.gz', + download_url='https://github.com/JECSand/yahoofinancials/archive/1.3.tar.gz', author='Connor Sanders', author_email='connor@exceleri.com', license='MIT', - keywords = ['finance data', 'stocks', 'commodities', 'cryptocurrencies', 'currencies', 'forex', 'yahoo finance'], + keywords=['finance data', 'stocks', 'commodities', 'cryptocurrencies', 'currencies', 'forex', 'yahoo finance'], packages=['yahoofinancials'], install_requires=[ "beautifulsoup4", diff --git a/test/test_yahoofinancials.py b/test/test_yahoofinancials.py index b52a878..ec16fea 100644 --- a/test/test_yahoofinancials.py +++ b/test/test_yahoofinancials.py @@ -1,7 +1,7 @@ -# YahooFinancials Unit Tests v1.2 -# Version Released: 08/29/2018 +# YahooFinancials Unit Tests v1.3 +# Version Released: 10/25/2018 # Author: Connor Sanders -# Tested on Python 2.7 and 3.5 +# Tested on Python 2.7, 3.3, 3.4, 3.5, and 3.6 # Copyright (c) 2018 Connor Sanders # MIT License @@ -71,6 +71,7 @@ def test_yf_fundamentals(self): self.assertEqual(result, True) result = check_fundamental(single_all_statement_data_qt, 'all') self.assertEqual(result, True) + # Multi stock check result = check_fundamental(multi_balance_sheet_data_qt, 'bal') self.assertEqual(result, True) diff --git a/yahoofinancials/__init__.py b/yahoofinancials/__init__.py index f7250a4..0861987 100644 --- a/yahoofinancials/__init__.py +++ b/yahoofinancials/__init__.py @@ -1,13 +1,13 @@ """ ============================== The Yahoo Financials Module -Version: 1.2 +Version: 1.3 ============================== Author: Connor Sanders Email: sandersconnor1@gmail.com -Version Released: 8/29/2018 -Tested on Python 2.7 and 3.5 +Version Released: 10/25/2018 +Tested on Python 2.7, 3.3, 3.4, 3.5, and 3.6 Copyright (c) 2018 Connor Sanders MIT License @@ -249,7 +249,7 @@ def _build_historical_url(self, ticker, hist_oj): return url # Private Method to clean the dates of the newly returns historical stock data into readable format - def _clean_historical_data(self, hist_data): + def _clean_historical_data(self, hist_data, last_attempt=False): data = {} for k, v in hist_data.items(): if k == 'eventsData': @@ -267,8 +267,14 @@ def _clean_historical_data(self, hist_data): event_obj.update({type_key: formatted_type_obj}) dict_ent = {k: event_obj} elif 'date' in k.lower(): - cleaned_date = self.format_date(v) - dict_ent = {k: {'formatted_date': cleaned_date, 'date': v}} + if v is not None: + cleaned_date = self.format_date(v) + dict_ent = {k: {'formatted_date': cleaned_date, 'date': v}} + else: + if last_attempt is False: + return None + else: + dict_ent = {k: {'formatted_date': None, 'date': v}} elif isinstance(v, list): sub_dict_list = [] for sub_dict in v: @@ -339,6 +345,20 @@ def _clean_api_data(self, api_url): ret_obj.update({'prices': prices_list}) return ret_obj + # Private Method to Handle Recursive API Request + def _recursive_api_request(self, hist_obj, up_ticker, i=0): + api_url = self._build_api_url(hist_obj, up_ticker) + re_data = self._clean_api_data(api_url) + cleaned_re_data = self._clean_historical_data(re_data) + if cleaned_re_data is not None: + return cleaned_re_data + else: + if i < 3: + i += 1 + return self._recursive_api_request(hist_obj, up_ticker, i) + else: + return self._clean_historical_data(re_data, True) + # Private Method to take scrapped data and build a data dictionary with def _create_dict_ent(self, up_ticker, statement_type, tech_type, report_name, hist_obj): YAHOO_URL = self._BASE_YAHOO_URL + up_ticker + '/' + self.YAHOO_FINANCIAL_TYPES[statement_type][0] + '?p=' +\ @@ -359,9 +379,12 @@ def _create_dict_ent(self, up_ticker, statement_type, tech_type, report_name, hi else: YAHOO_URL = self._build_historical_url(up_ticker, hist_obj) try: + cleaned_re_data = self._recursive_api_request(hist_obj, up_ticker) + ''' api_url = self._build_api_url(hist_obj, up_ticker) re_data = self._clean_api_data(api_url) cleaned_re_data = self._clean_historical_data(re_data) + ''' except KeyError: try: re_data = self._scrape_data(YAHOO_URL, tech_type, statement_type)