Subsections

14. Special variables and functions

CherryPy sets and uses a few special variables and functions. They are very simple and easy to use, but also very powerful. In this chapter, we'll see what these special variables and functions are, and we'll learn how to use them in the next chapter.

14.1 Special variables

14.1.1 request

This is the most commonly used variable. It contains all the informations about the request that was sent by the client. It's a class instance that contains several member variables that are set by CherryPy for each request. The most commonly used member variables are:

14.1.2 response

This is the second most commonly used variable (after request). It contains all informations about the response that will be sent back to the client. It's a class instance that contains several member variables that are set by CherryPy or by your program.

14.2 Special functions

In your code, you can define special functions that will change the server's behavior. To define these functions, just use Python's regular syntax and define them outside all CherryClasses. When you use different modules, you can define the same function in different modules. In this case, CherryPy will just concatenate the bodies of all functions, in the same order it reads the files.

14.2.1 initProgram, initServer, initAfterBind

The code you put in initProgram is copied at the very beginning of the generated file, so it's the first thing that will be executed. You can use that special function if you need to run some code before the CherryClasses are instanciated. Then, the server creates all instances of the CherryClasses and then it calls the special function initServer. This is basically where you perform some initialization tasks if some are needed.

initAfterBind is called after the socket "bind" has been made. For instance, on Unix-based systems, you need start CherryPy as root is you want it to bind its socket to port 80. The initAfterBind special function can be used to change the user back to an unpriviledged user after the "bind" has been done. (the HowTo called "Sample deployment configuration for a real-world website" explains how to do that).

14.2.2 initThread, initProcess

If you use a thread-pool server or process-pool server, then the corresponding special function (respectively initThread or initProcess) will be called by each newly created thread/process.

These functions can be used for instance if you want each thread/process to have its own database connection (the HowTo called "Sample deployment configuration for a real-world website" explains how to do that).

initThread takes an argument called threadIndex containing the index of the thread that's being created. For instance, if you create 10 threads, threadIndex will take values from 0 to 9.

Same thing for initProcess and processIndex

14.2.3 initRequest, initNonStaticRequest, initResponse and initNonStaticResponse

Here is the algorithm that the server uses when it receives a request:

As you can see, initRequest and initNonStaticRequest can be used to tweak the URL or the parameters, or to perform any work that has to be done for each request.

initResponse and initNonStaticResponse can be used to change the response header or body, just before it is sent back to the client.

14.2.4 onError

That function is called by CherryPy when an error occured while building the page. See next section for an example.

14.3 Examples

14.3.1 Playing with URLs

Let's say you want to set up a website for your customers. You want your customers to have their own URL: http://host/customerName, but the page is almost the same for each customer, so you don't want to create a method for each customer.

All you have to do is use the initNonStaticRequest to convert the URL http://host/customerName into http://host?customer=customerName. All that will be transparent to the user.

Just enter the following code:

def initNonStaticRequest():
    if request.path:
        request.paramMap['customer']=request.path
        request.path=""
CherryClass Root:
mask:
    def index(self, customer=""):
        <html><body>
            Hello, <py-eval="customer">
        </body></html>
And that's it !

Compile the file, start the server, and try a few URls, like http://localhost:8000/customer1or http://localhost:8000/world

14.3.2 Sending back a redirect

To send a redirect to the browser, all you have to do is send back a status code of 302 (instead of 200), and set a location value in the response header. This can be done easily using the response.headerMap special variable:
CherryClass Root:
mask:
    def index(self):
        <html><body>
            <a href="loop">Click here to come back to this page</a>
        </body></html>
view:
    def loop(self):
        response.headerMap['status']=302
        response.headerMap['location']=request.base
        return "" # A view should always return a string

14.3.3 Adding timing information to each page

In this example, we'll add one line at the end of each page that's served by the server. This line will contain the time it took to build the page. Of course, we only want this line for dynamic HTML pages.

All we have to do is use initNonStaticRequest to store the start time, and use initNonStaticResponse to add the line containing the build time.

Here is the code:

import time
def initNonStaticRequest():
    request.startTime=time.time()
def initNonStaticResponse():
    if response.headerMap['content-type']=='text/html':
        response.body+='<br>Time: %.04fs'%(time.time()-request.startTime)
CherryClass Root:
mask:
    def index(self):
        <html><body>
            Hello, world
        </body></html>

And voila

14.3.4 Customizing the error message

This is done through the onError special function. Just use response.headerMap and response.body to do what you want.

The following example shows how to set it up so it sends an email with the error everytime an error occurs:

use Mail

def onError():
    # Get the error in a string
    import traceback, StringIO
    bodyFile=StringIO.StringIO()
    traceback.print_exc(file=bodyFile)
    errorBody=bodyFile.getvalue()
    bodyFile.close()
    # Send an email with the error
    myMail.sendMail("erreur@site.com", "webmaster@site.com", "", "text/plain", "An error occured on your site", errorBody)
    # Set the body of the response
    response.body="<html><body><br><br><center>"
    response.body+="Sorry, an error occured<br>"
    response.body+="An email has been sent to the webmaster"
    response.body+="</center></body></html>"


CherryClass MyMail(Mail):
function:
    def __init__(self):
        self.smtpServer='smtp.site.com'

CherryClass Root:
mask:
    def index(self):
        <html><body>
            <a py-attr="request.base+'/generateError'" href="">Click here to generate an error</a>
        </body></html>
    def generateError(self):
        <html><body>
            You'll never see this: <py-eval="1/0">
        </body></html>

This example also shows you how to use the Mail standard module that comes with CherryPy.

See About this document... for information on suggesting changes.