pythonpython-3.xexceptiontraceback

Python extract only exceptions from traceback


I have nested python exceptions. I wan't to extract all of them into a list from a traceback while discarding everything else, i.e. files, code lines, etc.

The code below extracts everything from a traceback as a list of strings

import traceback
import requests


try:
    r = requests.get('https://thisdoesntexist.test')
except Exception as e:
    exc = traceback.format_exception(e)

print(exc)

Output:

[
    'Traceback (most recent call last):\n',
    '  File "c:\\Python312\\Lib\\site-packages\\urllib3\\connection.py", line 203, in _new_conn\n    sock = connection.create_connection(\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n',
    '  File "c:\\Python312\\Lib\\site-packages\\urllib3\\util\\connection.py", line 60, in create_connection\n    for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):\n               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n',
    '  File "c:\\Python312\\Lib\\socket.py", line 963, in getaddrinfo\n    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):\n               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n',
    'socket.gaierror: [Errno 11001] getaddrinfo failed\n',
    '\nThe above exception was the direct cause of the following exception:\n\n',
    'Traceback (most recent call last):\n',
  
    # Output truncated

    'requests.exceptions.ConnectionError: HTTPSConnectionPool(host=\'thisdoesntexist.test\', port=443): Max retries exceeded with url: / (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection object at 0x0000025E6C236600>: Failed to resolve \'thisdoesntexist.test\' ([Errno 11001] getaddrinfo failed)"))\n'
]

But i only need this:

[
    'socket.gaierror: [Errno 11001] getaddrinfo failed',
    'urllib3.exceptions.NameResolutionError: <urllib3.connection.HTTPSConnection object at 0x0000025E6C236600>: Failed to resolve 'thisdoesntexist.test' ([Errno 11001] getaddrinfo failed)',
    'urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host=\'thisdoesntexist.test\', port=443): Max retries exceeded with url: / (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection object at 0x0000025E6C236600>: Failed to resolve \'thisdoesntexist.test\' ([Errno 11001] getaddrinfo failed)"))',
    'requests.exceptions.ConnectionError: HTTPSConnectionPool(host=\'thisdoesntexist.test\', port=443): Max retries exceeded with url: / (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection object at 0x0000025E6C236600>: Failed to resolve \'thisdoesntexist.test\' ([Errno 11001] getaddrinfo failed)"))\n'
]

Is there a better way of achieving this without iterating over strings and pattern matching?

NB: It would be perfect if I could get a type of the exception in addition to the exception message string, e.g:

[
    {"type": "socket.gaierror", "message": 'socket.gaierror: [Errno 11001] getaddrinfo failed'},
    {"type": "urllib3.exceptions.NameResolutionError", "message": 'urllib3.exceptions.NameResolutionError: <urllib3.connection.HTTPSConnection object at 0x0000025E6C236600>: Failed to resolve \'thisdoesntexist.test\' ([Errno 11001] getaddrinfo failed)'},

    # etc

]

Solution

  • You can try:

    import traceback
    
    import requests
    
    
    def get_info(exc):
        r = []
    
        if exc.__context__:
            r += get_info(exc.__context__)
    
        tbe = traceback.TracebackException.from_exception(exc)
    
        t = tbe.exc_type.__module__ + "." + tbe.exc_type.__qualname__
    
        r.append({"type": t, "message": str(exc)})
        return r
    
    
    try:
        r = requests.get("https://thisdoesntexist.test")
    except Exception as e:
        print(get_info(e))
    

    Prints:

    [
        {"type": "socket.gaierror", "message": "[Errno -2] Name or service not known"},
        {
            "type": "urllib3.exceptions.NameResolutionError",
            "message": "<urllib3.connection.HTTPSConnection object at 0x7f6cc693d9d0>: Failed to resolve 'thisdoesntexist.test' ([Errno -2] Name or service not known)",
        },
        {
            "type": "urllib3.exceptions.MaxRetryError",
            "message": "HTTPSConnectionPool(host='thisdoesntexist.test', port=443): Max retries exceeded with url: / (Caused by NameResolutionError(\"<urllib3.connection.HTTPSConnection object at 0x7f6cc693d9d0>: Failed to resolve 'thisdoesntexist.test' ([Errno -2] Name or service not known)\"))",
        },
        {
            "type": "requests.exceptions.ConnectionError",
            "message": "HTTPSConnectionPool(host='thisdoesntexist.test', port=443): Max retries exceeded with url: / (Caused by NameResolutionError(\"<urllib3.connection.HTTPSConnection object at 0x7f6cc693d9d0>: Failed to resolve 'thisdoesntexist.test' ([Errno -2] Name or service not known)\"))",
        },
    ]