Infrastructure Perspective: Handling and Raising WebErrors

What are WebError's?

W
ebError is an exception object which is used to raise and catch errors / exceptions. For example, if the client asks for information about a non-existent course, the page which usually displays the information, raises a WebError exception. This exception is then caught and an error page is displayed to the user. As soon as the exception is raised the code execution is aborted and control is transferred to the exception handler. For example, suppose you have locked some tables in the database and then encounter a bad condition, you need to make sure you unlock the tables before raising the exception. In python this can be done using a finally block as follows:


try:
  lock tables
  calculate
  if bad condition:
      raise WebError ("bad_condition","Error Message")
  continue with regular stuff
finally:
  unlock tables

This ensures that the tables are unlocked irrespective of whether an exception occurred or not.

Raising WebError's

T
he python code to raise a WebError exception is raise WebError (error,message), where error and message are plain strings. The handler eventually calls self.generate_error_page(error,message) which generates the error page. If you need a more sophisticated exception handling check out the dictionary lookup and function call based exception handling.

Dictionary Lookup

I
f you want to raise the same error messages at many places in your code, or if you want to collect all the error messages together to make your code look cleaner, then you want to use the dictionary based error handling. All you need to do is to define a dictionary called error_messages as a static member of your display class. This dictionary should map short strings to pairs of strings.


error_messages = {
   'no_perms' : ("No Permissions","You have no permissions for this page"),
   'no_crse'  : ("No course", "There is no course with specified course number")
}

Then when raising the exception you do a

raise WebError ("no_perms{}")

The "{}" at the end of the error string, instructs the handler to do a dictionary lookup and call generate_error_page with the two strings defined in the dictionary. The second argument is ignored in this case. If the specified dictionary entry does not exist, it generates a default error message to the user as well as an error message to the debug.log file.

Function Call based exception handling

A
ll the methods so far have one inherent limitation, the error message generated can be determined at compile time. Some times you may want to give more information like

 
You gave me -100 for a course number

Another possible situation: An error has occurred. But some special cases does not require user intervention, the script should be able to take care of it.

In either of these situations you need a function call based exception handling. In this case the exception is raised using

raise WebError ("bad_crse_num()",self.args)

When the exception handler sees a "()" at the end of the first argument, it assumes that you want to handle the exception in your own function. The name of the function is handle_bad_crse_num(self,page,message), i.e. function name is got by prepending the first argument with "handle_". The function should take three arguments: self (since it is a method of the Display class), page and message. The page argument contains the page object which contains the error page. The message argument is whatever was passed in the second argument in your raise statement. In this case it is self.args. Since arguments in python can be any type, you can send as much information as you want to your exception handler, by properly packing it and unpacking it.

Caveat:

After your function has finished it is assumed that the page object has the contents of the error page to be displayed. So it is your responsibility to populate the page object. The simplest way, is to call generate_error_page with appropriate arguments. If you are trying to rectify some mistake, it might easier to bounce the user to the same URL with the correct arguments, than to call make_page from within your exception handling function. Of course, make sure that there are no infinite bounce loops.