Catching and rendering exceptions

Error handling in Zope 4

TL;DR: You have to write an exception view in file system code which is rendered when an exception occurs.

History

If an exception occurred in Zope 2 the standard_error_message (an object in the ZODB) was rendered. This way the error page could be customised through the web.

When using a WSGI server on Zope 2 the standard_error_message is no longer used. The exceptions have to be handled in a WSGI middleware. (This is a sub-optimal solution as the middleware is not run in the same execution context where the exception occurred.)

Thats why error handling changed again in Zope 4:  Like Zope 3 (aka BlueBream) Zope 4 tries to lookup an exception view if an exception occurs. If the lookup succeeds (aka there is an exception view registered for the current exception) this view is rendered as response. This approach allows different views for different exceptions. The standard_error_message is even gone when installing Zope 4 from scratch.

Base solution

The exception view has to be created in the file system and registered via ZCML. If you do not have a file system package yet – where this code can be placed – you can create a new package e. g. by using paster:

$ bin/pip install PasteScript
$ bin/paster create -t basic_package errorviews
$ bin/pip install -e errorviews

Where errorviews is the name of my example package.

In the existing errorviews/__init__.pyenter the following code:

class SiteErrorView(object):
    """View rendered on SiteError."""

    def __call__(self):
        return "SiteError!"

This view returns the string SiteError! instead of the standard error message. It has to be registered via ZCML. Write a file named configure.zcml right besides __init__.py:

<configure
  xmlns="http://namespaces.zope.org/zope"
  xmlns:browser="http://namespaces.zope.org/browser">

  <browser:page
    for="Exception"
    name="index.html"
    class=".SiteErrorView"
    permission="zope.Public"
    />

</configure>

The view gets registered for Exception and all classes inheriting from it. (This might be a bit too general for use in actual code, I know.) Zope 4 expects that the name is index.html. class  is a relative dotted path to the view class.

If you put these files into a Zope Product they could be picked automatically. If you created an errorviews package like me you have to register it in etc/site.zcml . Put the following line near the end before </configure>:

 <include package="errorviews" />

After re-starting Zope each exception renders as SiteError!

Using a PageTemplate

Writing HTML in a Python class is not very convenient. It is easier to use a PageTemplate to store the templating code. Create a file error.pt right beside __init__.py:

<html>
 <body>
   <h1>SiteError occurred</h1>
 </body>
</html>

In configure.zcml replace class=".SiteErrorView" by template="error.pt". (The view class is not used in this example.) After re-starting Zope each exception renders the HTML page.

Back to standard_error_message

If you have an existing Data.fs and want to re-use standard_error_message you might try the following hack: Change configure.zcml (back) to the XML code shown in the section “Base solution”.  Change __init__.py to the following content:

class SiteErrorView(object):
    """View rendered on SiteError."""

    def __call__(self):
        root = self.request['PARENTS'][-1]
        return root.standard_error_message(
            error_type=self.context.__class__.__name__,
            error_value=str(self.context))

The code in the example expects that standard_error_message  is a DTMLMethod (as provided by Zope 2.13). The arguments error_type  and error_value  allow using &dtml-error_type; and &dtml-error_value; in the DTMLMethod as before.

Conclusion

Zope 4 has a nice and flexible concept to render error pages. But it requires at least some Python code in the file system. Even this can be tricked back to standard_error_message if needed. But I think this should only be used for old applications or as an interim solution.

Author: Michael Howitz

I am a software developer at gocept in Halle (Saale). To develop software, I mainly use Python, Zope, ZTK and Django.

One thought on “Catching and rendering exceptions”

Leave a Reply

%d bloggers like this: