Previous Chapter | Next Chapter | Up | Next Section | Contents

Exception Handling with the dtml-try Tag


Exceptions are unexpected errors Zope encounters during the rendering of a DTML statement. Once an exception is detected, the normal execution of the DTML stops. Consider the following example:

Cost per unit: $<dtml-var expr="_.float(total_cost/total_units)">

This statement functions normally if total_units is not zero. However, in the event that total_units is zero, a ZeroDivisionError exception is raised indicating an illegal operation. Thus, rather than rendering the DTML, an error message will be returned.

DTML provides the dtml-try tag to catch and handle these problematic exceptions within a block of DTML code. This allows you to anticipate and handle errors yourself, rather than getting a Zope error message whenever an exception occurs.

As an exception handler, the dtml-try tag has two functions. First, if an exception is raised, the dtml-try tag gains control of execution and handles the exception appropriately, and thus avoids returning a Zope error message. Second, the dtml-try tag allows the rendering of any subsequent DMTL to continue.

 

Within the dtml-try tag are one or more dtml-except tags that identify and handle different exceptions. When an exception is raised, each dtml-except tag is checked in turn to see if it matches the exception's type. The first dtml-except tag to match handles the exception. If no exceptions are given in a dtml-except tag, then the dtml-except tag will match all exceptions.

Implementing the dtml-try tag in the example above would resemble:


<dtml-try>

Cost per unit: $<dtml-var expr="_.float(total_cost/total_units")>

<dtml-except ZeroDivisionError>

Cost per unit: N/A

</dtml-try>

If a ZeroDivisionError is raised, control goes to the dtml-except tag, and "Cost per unit: N/A" is rendered. Once the statements of the dtml-except tag finish, execution of DTML continues past the dtml-try block.

DTML's except tags work with Python's class-based exceptions. In addition to matching exceptions by name, the dtml-except tag will match any subclass of the named exception. For example, if ArithmaticError is named in a dtml-except tag, the tag can handle all ArithmaticError subclasses including, ZeroDivisionError.

Inside the body of a dtml-except tag you can access information about the handled exception through several special variables. These variables are:

  1. error_type, which represents the type of the handled exception,
  2. error_value , which represents the value of the handled exception, and
  3. error_tb , which represents the traceback of the handled exception.

 

The dtml-try tag optional dtml-else block

The dtml-try tag has an optional dtml-else block that is rendered if an exception didn't occur. The exceptions in the else block are not handled by the preceding dtml-except blocks. Implementing the dtml-else tag with the dtml-try tag would be like:

<dtml-try>

<dtml-except SomeError AnotherError>

<dtml-except YetAnotherError>

<dtml-except>

<dtml-else>

</dtml-try>

The first dtml-except block to match the type of error raised is rendered. If a dtml-except block has no name, then it matches all raised errors. The optional dtml-else block is rendered when no exception occurs in the dtml-try block. Exception in the dtml-else block are not handled by the preceding dtml-except blocks.

The dtml-try tag optional dtml-finally block

In addition to the dtml-else block, the dtml-try tag has the ability to use a dtml-finally block that is always rendered whether an exception occurs or not. The dtml-finally form specifies a cleanup block to be rendered even when a exception occurs. Note, any rendered results are discarded if an exception occurs in either the try or finally blocks. The dtml-finally block is only of any used if you need to clean up something that will not be cleaned up by the transaction abort code. The dtml-finally block will always be called, whether there is an exception or nor and whether a return tage is used or not. If you use a dtml-return tag in the try block, any output of the dtml-finally block is discarded.

<dtml-try>
    <dtml-finally>
</dtml-try>

Important to note, if a exception occurs in the dtml-try block and an exception occurs in the dtml-finally block any information about the first exception is lost. It follows that if a return tag is used in the dtml-try block and an exception occurs in the dtml-finally block, the result returned in the dtml-try block will be lost. Also, if a return tag is used in the dtml-finally block, the result returned in the dtml-try block will be lost as well.

Previous Chapter | Next Chapter | Up | Next Section | Contents