Simplified Exception Identification in Python

Using functions and exception pattern dictionaries to simplify error recovery.
A Dictionary of Known Exception Patterns

The name of the exception class is not enough to generalize properly the handling of exceptions. As an example, the socket module generates many different exceptions for various conditions, and they all are named "error". What makes each condition distinct lies in the exceptions details. The tuple ('error', (111, 'Connection refused') ) is different from ('error', (32, 'Broken pipe') ).

So what we will do instead is create a dictionary whose keys define exact exceptions. Each of those keys will have a simple integer value that reduces multiple cases to a smaller number. The following dictionary is not complete, but it gives a good idea of how to proceed and build a larger one.

     ExcDiagDict = {
        # another famous OS:
        repr( ('error', (10061, 'Connection refused') ) ) :
        # Linux 2.4:
        repr( ('error', (111, 'Connection refused') ) )   :
        repr( ('error', (32, 'Broken pipe') ) )           : EXC_DISCONNECT,
        repr( ('error', (107, 'Transport endpoint is not connected') ) ) :

In this exception "diagnosis" dictionary, a repr() surrounds each of the tuples that makes up a key. In this example, strings are the only practical way to retrieve the expected results from the dictionary. Using a tuple directly does not work--no match would ever be found, unless the exact same instances of objects and tuples were used in the look-up. String keys are used because they are less restrictive and work according to their lexical values.

In the dictionary as it is initialized above, we have two keys associated with the constant EXC_SERVER_NOT_AVAILABLE. Each of these two keys represents an ('error', (number, 'Connection refused')) exception, but the value of the number varies according to the operating system being used. The last two keys are two completely different exceptions that can happen under Linux, but they basically indicate the same event--a disconnect on a socket. The dictionary can be expanded to include similar exception patterns on more platforms, as well as more exception patterns related to one or more basic events.

If you take the previous import statements, the previous definition of the function formatExceptionInfo() and the dictionary above, you can append the following code:

     def getDiagnosisFromExcInfo(excInfoTuple):
           excPattern = (excInfoTuple[0], excInfoTuple[1])
           return ExcDiagDict[ repr(excPattern) ]
         except KeyError:
           return None
           return None    # maybe was not tuple?
     from socket import *
         s = socket(AF_INET, SOCK_STREAM)
         s.connect( ("", 7788) )
         exInfo = formatExceptionInfo()
         diag = getDiagnosisFromExcInfo(exInfo)
         print "diag:", diag, "exc:", exInfo

When you run that code, the following should be returned:

     diag: 2 exc: ('error', (111, 'Connection refused'), ['File "<stdin>",
     line 3, in ?\n', ...]

The "2" is the value of the constant EXC_SERVER_NOT_AVAILABLE, which is indeed the constant associated with the Connection refused exception pattern in the sample dictionary. From experience, it is safe to say that error recovery code that uses formatExceptionInfo() and getDiagnosisFromExcInfo() is much simpler and, therefore, more reliable.


With the function formatExceptionInfo(), we have found a way to learn important information about any exception from the Python sys.exc_info() function. Also, the exception patterns dictionary makes it possible to simplify the identification of various exceptions, even if they differ from one OS to another or if they actually refer to the same event.

Jean-Francois Touchette has been developing software for 20 years. He has written several gateways and servers with various protocols since 1985. He has been using C and UNIX since that time. When Python is suitable, he prefers it.



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Re: Simplified Exception Identification in Python

Anonymous's picture

Dude, ever hear of errno?

errno is not thread safe

JFT's picture

Only luck would prevent another thread from modifying the value of errno between the time when the first thread does something which sets the value of errno and the time when this first thread checks its value.
Of course, in production environments, Murphy's laws apply fully and that nasty scenario would hit you at the worst possible moment. ;)

Re: Simplified Exception Identification in Python

Anonymous's picture

The same as the first comment, thanks, exactly what I needed to know, I was having trouble getting the trace back from errors in a threaded program

Re: Simplified Exception Identification in Python

Anonymous's picture

[to author:] Dude, ever hear of errno?

Re: Simplified Exception Identification in Python

Anonymous's picture

Thanks man, this was exactly the code I was looking for.