17.3. CherryPy Filters
CherryPy also has hooks for running special functions called filters at several different points in the request cycle, before and after the published object is executed.
Filters allow for a lot of flexibility in the way requests are handled. CherryPy comes with several built-in filters to do caching, session management, compression, XML Remote Procedure Call (RPC) request processing, and to otherwise slice and dice the request object in interesting ways. But wait, that's not all. CherryPy also provides an easy-to-use mechanism for you to create your own custom filters, which are applied to whichever sections of your object hierarchy you choose.
But it's likely that future versions of TurboGears will use a somewhat different implementation of filters, so if you're using something more recent than 1.0 you may want to check the online documents.
17.3.1. Input Filters
The most logical place to start seeing what filters can do for you in CherryPy is to take a look at some of the built-in input filters. In Table 17-3 you will find a list of the built-in CherryPy input filters.
These filters are contained in the cherrypy.filter.input_order list in the above order. You should be able to open that list and add your own filters; filters will be applied in the order they appear in the input_order list. Each item in this list should be a fully qualified package location. (This is already true for the built-in filters, but you want to follow the same convention for any filters you add!)
17.3.2. Output Filters
Just like the input filters, each of these output filters is contained in the cherrypy.filters.output_filters list, which defines the order of the filters that are run. You can configure any of these built-in filters by turning them on in the configuration app.cfg (which can be found in your project's config folder).
Here's a sample of how we turn on the static file filter for the /static directory:
[/static] static_filter.on = True static_filter.dir = "%(top_level_dir)s/static"
You can use the Output Filters described in Table 17-4 to compress the response before sending it back to the user, or even create XML-RPC output.
We talk more about CherryPy configuration in the next section. For now, all you need to know is that turning on the static_filter for the /static directory means that any files that you put in your TurboGears application's static folder will be returned without any further processing.
17.3.3. Creating Your Own Filters
If you want to create your own filters, all you have to do is to subclass BaseFilter from the cherrypy.filters.basefilter module:
class PrintMessageFilter(BaseFilter): def before_main(self): print "This happens before the main page handler is called"
If you define a new method with the name of one of CherryPy's predefined filter hook locations, that method will be called at that time in the request cycle.
But, it's probably not enough to define a new filteryou probably want to actually have it run on some set of your controller objects, too. Fortunately that's easy: You can just define a _cp_filters list containing all the custom filter classes that you want to run on objects in that controller class. So, if you want to run our PrintMessageFilter on every object in your whole hierarchy, you could write something like this:
class Root(controllers.RootController): _cp_filters = [PrintMessageFilter(),]
As mentioned earlier, there are several predefined hooks in CherrPy where filters can be run. Whenever the request/response cycle hooks occur, CherryPy runs any filters that are in _cp_filters, and which define a method with the name of the current hook. Not only that, but the filters are applied in the order they are found in the _cp_filters list as seen in Table 17-5.
On the other hand, if you want to create a new filter and have it inserted into the CherryPy input or output filter lists, you can add your function to the call_on_startup list to register it to be run at startup, as follows:
from turbogears.startup import call_on_startup def do_your_thing(): call_on_startup.append(do_your_thing)
You can do_your_thing and insert filters into the CherryPy request phase or set up variables as needed.