Wednesday, June 1, 2011

Determining Error Types in Python

Many times when writing python code, you want to get some error feedback.  Python, like many other languages, has a try/catch or in this case a try/except/finally pattern where you can capture various errors:

Example: Simple Try/Except Pattern

try:
   a = 1/0
except:
   print 'error'
finally:
   print 'i'm done!'

The code will throw an error and go the to the except section of the code skipping everything else, but not much is being told to the developer.
Let's try to add a trace function that will capture the line where the error occurs and some other information:

import arcpy

def trace(self):
   import sys, traceback, inspect
   tb = sys.exc_info()[2]
   tbinfo = traceback.format_tb(tb)[0]
   # script name + line number
   line = tbinfo.split(", ")[1]
   filename = inspect.getfile( inspect.currentframe() )
   # Get Python syntax error
   #
   synerror = traceback.format_exc().splitlines()[-1]
   return line, filename, synerror


try:
   a=1/0
except:
   line, filename, err = trace()
   print "Python error on " + line + " of " + filename + " : with error - " + err
   arcpy.AddError("Python error on " + line + " of " + filename + " : with error - " + err)


Now we know more about the error than just 'error.' You can further expand your error handling by capturing arcpy errors verse everything else:

import arcpy

def trace(self):
   import sys, traceback, inspect
   tb = sys.exc_info()[2]
   tbinfo = traceback.format_tb(tb)[0]
   # script name + line number
   line = tbinfo.split(", ")[1]
   filename = inspect.getfile( inspect.currentframe() )
   # Get Python syntax error
   #
   synerror = traceback.format_exc().splitlines()[-1]
   return line, filename, synerror


try:
   a=1/0
except arcpy.ExecuteError:
   line, filename, err = trace()
   print "Geoprocessing error on " + line + " of " + filename + " :"
   arcpy.AddError("Geoprocessing error on " + line + " of " + filename + " :")
   arcpy.AddError(arcpy.GetMessages(2))
except:
   line, filename, err = trace()
   print "Python error on " + line + " of " + filename + " : with error - " + err
   arcpy.AddError("Python error on " + line + " of " + filename + " : with error - " + err)

Now you know if it's a python error or an arcpy error. Very cool and helpful

You can further break down error handling by creating custom error classes and use the raise method to call that class, but that's another time.