Search code examples
python-3.xsocketsexceptionpython-requestsbinance

How to properly handle multiple connection error exceptions on Python3? related to python-binance package


I'm coding a little cryptocurrency tracker using the python-binance package version 1.0.16 (the last version as of today)

My problem appears at some specific part of the process which is the login to the Binance server through the Client using the api and secret keys. Here's the code for that:

from binance.Client import Client

api = input("Paste your API KEY here: ")
secret = input("Now paste your SECRET KEY here: ")

client = Client(api_key=api, api_secret=secret, tld = "com")

Note: As long as the user has an stable internet connection, no exception is raised, allowing the tracker to work as expected

But, if the user were not even connected to the internet (without obviously noticing it), the following exceptions would be thrown after executing the code above:

Traceback (most recent call last):

  File "F:\Python\Python310\lib\site-packages\urllib3\connection.py", line 174, in _new_conn
    conn = connection.create_connection(

  File "F:\Python\Python310\lib\site-packages\urllib3\util\connection.py", line 72, in create_connection
    for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):

  File "F:\Python\Python310\lib\socket.py", line 955, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):

gaierror: [Errno 11001] getaddrinfo failed


During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File "F:\Python\Python310\lib\site-packages\urllib3\connectionpool.py", line 703, in urlopen
    httplib_response = self._make_request(

  File "F:\Python\Python310\lib\site-packages\urllib3\connectionpool.py", line 386, in _make_request
    self._validate_conn(conn)

  File "F:\Python\Python310\lib\site-packages\urllib3\connectionpool.py", line 1042, in _validate_conn
    conn.connect()

  File "F:\Python\Python310\lib\site-packages\urllib3\connection.py", line 358, in connect
    self.sock = conn = self._new_conn()

  File "F:\Python\Python310\lib\site-packages\urllib3\connection.py", line 186, in _new_conn
    raise NewConnectionError(

NewConnectionError: <urllib3.connection.HTTPSConnection object at 0x0000020B4CEB4A00>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed


During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File "F:\Python\Python310\lib\site-packages\requests\adapters.py", line 489, in send
    resp = conn.urlopen(

  File "F:\Python\Python310\lib\site-packages\urllib3\connectionpool.py", line 787, in urlopen
    retries = retries.increment(

  File "F:\Python\Python310\lib\site-packages\urllib3\util\retry.py", line 592, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))

MaxRetryError: HTTPSConnectionPool(host='api.binance.com', port=443): Max retries exceeded with url: /api/v3/ping (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x0000020B4CEB4A00>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed'))


During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File "F:\Python\Python310\lib\site-packages\spyder_kernels\py3compat.py", line 356, in compat_exec
    exec(code, globals, locals)

  File "c:\users\user\.spyder-py3\btcusdt_only-signals.system.py", line 207, in <module>
    client = Client(api_key= api_key, api_secret= secret_key, tld= "com")

  File "F:\Python\Python310\lib\site-packages\binance\client.py", line 300, in __init__
    self.ping()

  File "F:\Python\Python310\lib\site-packages\binance\client.py", line 526, in ping
    return self._get('ping', version=self.PRIVATE_API_VERSION)

  File "F:\Python\Python310\lib\site-packages\binance\client.py", line 371, in _get
    return self._request_api('get', path, signed, version, **kwargs)

  File "F:\Python\Python310\lib\site-packages\binance\client.py", line 334, in _request_api
    return self._request(method, uri, signed, **kwargs)

  File "F:\Python\Python310\lib\site-packages\binance\client.py", line 314, in _request
    self.response = getattr(self.session, method)(uri, **kwargs)

  File "F:\Python\Python310\lib\site-packages\requests\sessions.py", line 600, in get
    return self.request("GET", url, **kwargs)

  File "F:\Python\Python310\lib\site-packages\requests\sessions.py", line 587, in request
    resp = self.send(prep, **send_kwargs)

  File "F:\Python\Python310\lib\site-packages\requests\sessions.py", line 701, in send
    r = adapter.send(request, **kwargs)

  File "F:\Python\Python310\lib\site-packages\requests\adapters.py", line 565, in send
    raise ConnectionError(e, request=request)

ConnectionError: HTTPSConnectionPool(host='api.binance.com', port=443): Max retries exceeded with url: /api/v3/ping (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x0000020B4CEB4A00>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed'))

So, in essence, there are 4 exceptions that need to be handled:

  • gaierror
  • NewConnectionError
  • MaxRetryError
  • ConnectionError

At first I tried the following code based on this approach because I thought that as gaierror was always the very first exception raised, I supposed that by correctly handling it, the rest of the exceptions would not be raised:

from binance.Client import Client
import socket

api = input("Paste your API KEY here: ")
secret = input("Now paste your SECRET KEY here: ")

while True:
    try: 
        client = Client(api_key= api_key, api_secret= secret_key, tld= "com")
        break
    except socket.gaierror:
        print("You are not connected to the internet, first make sure to be connected before executing this program")
        input("Once done, press Enter key:")

Unfortunately, my approach didn't handle anything and ended up throwing exactly the same output described above, with the same exceptions raised in the same order.

However, this other one DID WORK!:

from binance.Client import Client

api = input("Paste your API KEY here: ")
secret = input("Now paste your SECRET KEY here: ")

while True:
    try: 
        client = Client(api_key= api_key, api_secret= secret_key, tld= "com")
        break
    except Exception:
        print("You are not connected to the internet, first make sure to be connected before executing this program")
        input("Once done, press Enter key:")

So guys, I came here to know if there's a better way than just setting except Exception to handle the 4 exceptions raised? You know, it doesn't look very Good Practices to me, and also doesn't let me know exactly what's happening behind and how to explain the user why such thing is happening, so may you help me out here?


Solution

  • You can extend your except blocks like so:

    from binance.Client import Client
    import socket
    from urllib3.exceptions import NewConnectionError, MaxRetryError, ConnectionError
    
    api = input("Paste your API KEY here: ")
    secret = input("Now paste your SECRET KEY here: ")
    
    while True:
        try: 
            client = Client(api_key= api_key, api_secret= secret_key, tld= "com")
            break
        except (socket.gaierror, NewConnectionError, MaxRetryError, ConnectionError) as e:
            print("You are not connected to the internet, first make sure to be connected before executing this program")
            input("Once done, press Enter key:")
    

    or

        except gaierror as ge:
            print("something ge specific")
        except NewConnectionError as nce:
            print("something nce specific")
        # ...
    

    With the latter approach, you can handle each error independently. If you want to just filter out connection errors and deal with them in one batch, the first is a good option.

    Thank you.