Simplified exception identification in Python

Source: Internet
Author: User

Using Functions and exception pattern dictionaries to simplify error recovery.

 

 

One of the features that makes Python a great programming language is exceptions for error handling. specified tions are convenient in specified ways for handling errors and special conditions in a program. but, if several kinds of exceptions occur in short seort of code and in several parts of a program, it quickly becomes tedious and error-causing to recode the "response t: "chunks of the Code. error recovery, especially, is a place where you want to have well-tested, clear and simple chunks of code. this article suggests an approach that helps users achieve this goal.

A second factor that makes Python so flexible is it does not reinvent the wheel when its API interfaces with the operating system. any C or C ++ programmer familiar with standard * nix system calland libraries can leverage his/her previous knowledge when moving into Python application development. on the other hand, the python socket module generates exceptions that differ from one platform to another. as an example, the connection refused error exception is assigned the Number 111 under Linux, but it is 10061 in another popular operating system. again, it quickly becomes boring to code multiple handle T: clses for use on your different platforms.

Always searching for a better and easier way to do things, let's look now at how we can identify and categorize conditions in Python in order to simplify error recovery. in addition, let's try to do this in a way that can be applied to multiple operating systems.

Anatomy of an exception

There is more than one generic way to discover the identity of an exception. First, you need to code a catch-all privileges T: Clause, like this:

     try:         ...some statements here...     except:         ...exception handling...

In the exception handling code, we want to have as few lines of code as possible. also, it is highly desirable to funnel both normal exceptions (disconnect, connection refused) alongside the weirder ones (attribute Error !), Running both through a single execution path. you will, of course, need more statements to do the precise action required by the condition. but, if you can do the first four or five steps in a generic way, it will making testing things later as easier task.

In our example, Python offers two ways to access the exception information. For both, the Python script first must haveImport sysBeforeTry: .. try t:Portion of the Code. with the first method, the function sys. exc_type gives the name of the exception, and SYS. exc_value gives more details about the exception. for example, in a nameerror exception the sys. exc_value command might return"There is no variable named 'x '", When X was referenced without first having been assigned a value. this method, however, is not thread-safe. as a result, it is not that useful, because most network applications are multithreaded.

The second way to access exception information is with sys. exc_info (). this function is thread-safe and also is more flexible, although it might look intimidating at first. if you run the following code:

     import sys     try:         x = x + 1     except:         print sys.exc_info()

You will see this message:

     (<class exceptions.NameError at 007C5B2C>, <exceptions.NameError     instance at 007F5E3C>, <traceback object at 007F5E10>)

How's that for cryptic! But, with a few lines of code we can unravel this into rather useful chunks of information. Suppose that you run the following code instead:

     import sys     import traceback     def formatExceptionInfo(maxTBlevel=5):         cla, exc, trbk = sys.exc_info()         excName = cla.__name__         try:             excArgs = exc.__dict__["args"]         except KeyError:             excArgs = "<no args>"         excTb = traceback.format_tb(trbk, maxTBlevel)         return (excName, excArgs, excTb)     try:         x = x + 1     except:         print formatExceptionInfo()

This will display:

     ('NameError', ("There is no variable named 'x'",), ['  File "<stdin>",     line 14, in ?/n'])

The function formatexceptioninfo () takes the Three-element tuple returned by sys. exc_info () and transforms each element into a more convenient form, a string.. _ name _ gives the name of the exception class, while exc. _ dict _ ["ARGs"] gives other details about the exception. in the case of socket exceptions, these details will be in a two-element tuple, like("Error", (32, 'Broken pipe '). Lastly, traceback. format_tb () formats the traceback information into a string. the optional argument (maxtblevel> in the sample code) allows users to control the depth of the traceback that will be formatted. the traceback information is not essential to identify or categorize exceptions, but if you want to log all the spurous unknown tions your program encounters, it is useful to write that traceback string in the log.

With the first two elements -- the name of the exception class and the exception details -- we can now try to identify the exception and reduce it to a well-known one from a set of previusly recognized exception patterns.

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 invalid different exceptions for varous 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 calls CES 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.

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

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 wocould 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 refered') 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):         try:           excPattern = (excInfoTuple[0], excInfoTuple[1])           return ExcDiagDict[ repr(excPattern) ]         except KeyError:           return None         except:           return None    # maybe was not tuple?     from socket import *     try:         s = socket(AF_INET, SOCK_STREAM)         s.connect( ("127.0.0.1", 7788) )         s.close()     except:         exInfo = formatExceptionInfo()         diag = getDiagnosisFromExcInfo(exInfo)         print "diag:", diag, "exc:", exInfo

When you run that code, the following shoshould 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.

Conclusion

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 touchetteHas been developing software for 20 years. he has written several gateways and servers with varous protocols since 1985. he has been using C and Unix since that time. when python is suitable, he prefers it.

Email:Jftouchette@yahoo.com

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.