Handling Exceptions

Exceptions are errors that prevent your code (or the code of modules that your code is calling) from executing properly and cause execution to terminate. In our previous example in the Listing 2-27, the code fails because we included a statement that instructs Python to execute division by zero, which is not possible. This raised a ZeroDivisionError exception and execution of the code is terminated there. Unless we used the try: ... except: ... statement, our program would terminate at this point. Python allows us to act on the exceptions, so we can decide how ]to handle them appropriately. For example, if we try to establish communication with a remote web service, but the service is not responding, we will get a "connection timed out" exception. If we have more than one service to query, we might just report this as an error and proceed with other services. Catching exceptions is easy:

try:

call_to_some_function() except:

do_something_about_it()

As you saw in the previous section, you can log a full exception stack trace just by indicating that you want to log exception details to the logger function call. In my code example I use the following construction to detect an exception, log it and pass it on. If you are writing a module, and you cannot really decide what to do with exceptions that occur, this is one of the ways to deal with them:

try:

module.function() except:

logger.error('An exception has occurred while executing module.function()', exc_info=True)

raise

It is also possible to catch specific exceptions and perform different actions for each:

try:

result = divide_two_numbers(arg1, arg2) except ZeroDivisionError:

# if this happens, we will return 0

logger.error('We attempted to divide by zero, setting result to 0') result = 0 except:

# something else has happened, so we reraise it logger.critical('An exception has occurred while executing module.function()', exc_info=True)

raise

If you're writing your own module, you might decide to introduce exceptions specific to this module, so they can be caught and dealt with accordingly. I use this technique in the NSLib.py module. Custom exceptions must be derived from the generic Exception class. If you do not require any specific functionality, you could define new exception as the following class:

class NSLibError(Exception):

self.error_message = error_message def __str__(self):

return repr(self.error_message)

Once the exception class is defined, you would raise it by calling the raise operator and passing an object instance of this exception class:

class NSSoapApi(object):

def __init__(self, module=None, hostname=None, username=None, password=None):

if not (hostname and username and password):

self.logger.critical('One or more from the following: hostname, username and password, are undefined')

raise NSLibError('hostname, username and password must be defined')

Although it is not required, it is a good practice to follow the exception class convention, which states that all exception class names should end with Error. Unless the module is huge and implements distinctively different functionality, you might just define one exception per module or group of omodules.

Was this article helpful?

0 0

Post a comment