MicroPyramid / forex-python

Foreign exchange rates, Bitcoin price index and currency conversion using ratesapi.io
http://forex-python.readthedocs.io/en/latest/usage.html
MIT License
661 stars 195 forks source link

Error handling failing when Theforexapi.com is down #154

Open PedroGFonseca opened 2 months ago

PedroGFonseca commented 2 months ago

When the website is down the error handling fails and results in a hard to interpret JSON decoding error

Minimum code to reproduce:

from forex_python.converter import CurrencyRates
self =  CurrencyRates()
date_obj = None

base_cur = 'EUR'
dest_cur = 'USD'

self.get_rate(base_cur, dest_cur)

The problem seems to happen within the decoder. There is error handling on line 75 and 79, but the code never reaches the error handling as it breaks on line 74. Line 79 seems to be set up expecting a Try/Except, but that is not how it is implemented.

Follows more detailed digging into the problem and a full stack trace:

from forex_python.converter import CurrencyRates
self =  CurrencyRates()
date_obj = None

base_cur = 'EUR'
dest_cur = 'USD'

date_str = self._get_date_string(date_obj)
payload = {'base': base_cur, 'symbols': dest_cur, 'rtype': 'fpy'}
source_url = self._source_url() + date_str
print(f'Source URL: {source_url}')
response = requests.get(source_url, params=payload)

assert response.status_code == 200  # is true 

print(f'self._force_decimal is set to {self._force_decimal}')

print(f'self.use_decimal is set to {use_decimal}')

# This line produces JSONDecodeError 
# rate = self._get_decoded_rate(response, dest_cur, date_str=date_str)

# this is what is inside the _get_decoded_rate
use_decimal=False  # setting the default parameter 

# digging into self._decode_rates
# the problem is when this is called: 
decoded_data = response.json()

Results in:

Source URL: https://theforexapi.com/api/latest
self._force_decimal is set to False
self.use_decimal is set to False
---------------------------------------------------------------------------
JSONDecodeError                           Traceback (most recent call last)
File ~/.virtualenv/stocks/lib/python3.10/site-packages/requests/models.py:971, in Response.json(self, **kwargs)
    970 try:
--> 971     return complexjson.loads(self.text, **kwargs)
    972 except JSONDecodeError as e:
    973     # Catch JSON-related errors and raise as requests.JSONDecodeError
    974     # This aliases json.JSONDecodeError and simplejson.JSONDecodeError

File ~/.virtualenv/stocks/lib/python3.10/site-packages/simplejson/__init__.py:514, in loads(s, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, use_decimal, allow_nan, **kw)
    510 if (cls is None and encoding is None and object_hook is None and
    511         parse_int is None and parse_float is None and
    512         parse_constant is None and object_pairs_hook is None
    513         and not use_decimal and not allow_nan and not kw):
--> 514     return _default_decoder.decode(s)
    515 if cls is None:

File ~/.virtualenv/stocks/lib/python3.10/site-packages/simplejson/decoder.py:386, in JSONDecoder.decode(self, s, _w, _PY3)
    385     s = str(s, self.encoding)
--> 386 obj, end = self.raw_decode(s)
    387 end = _w(s, end).end()

File ~/.virtualenv/stocks/lib/python3.10/site-packages/simplejson/decoder.py:416, in JSONDecoder.raw_decode(self, s, idx, _w, _PY3)
    415         idx += 3
--> 416 return self.scan_once(s, idx=_w(s, idx).end())

JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

JSONDecodeError                           Traceback (most recent call last)
Cell In [45], line 28
     24 use_decimal=False  # setting the default parameter 
     26 # digging into self._decode_rates
     27 # the problem is when this is called: 
---> 28 decoded_data = response.json()

File ~/.virtualenv/stocks/lib/python3.10/site-packages/requests/models.py:975, in Response.json(self, **kwargs)
    971     return complexjson.loads(self.text, **kwargs)
    972 except JSONDecodeError as e:
    973     # Catch JSON-related errors and raise as requests.JSONDecodeError
    974     # This aliases json.JSONDecodeError and simplejson.JSONDecodeError
--> 975     raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)

JSONDecodeError: Expecting value: line 1 column 1 (char 0)