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 initRequest, initNonStaticRequest, initResponse and initNonStaticResponse

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

Static content  All content  Dynamic content 
  a. Request coming in  
  b. Set all member variables of request  
  c. Call initRequest (which may change request.path and request.paramMap)  
  d. Determine if this request corresponds to static or dynamic content (based on request.path and the staticContent section of the config file)  
  e. Call initNonStaticRequest (which may change request.path and request.paramMap)
e. Read the static file and set response.headerMap values and response.body accordingly f. Call the method of the CherryClass instance, with some arguments (based on request.path and request.paramMap) and set response.headerMap values and response.body according to the result
f. Call initResponse (which may change response.headerMap and response.body) g. Call initResponse (which may change response.headerMap and response.body)
g. Send the response to the browser (based on response.headerMap and response.body) h. Send the response to the browser (based on response.headerMap and response.body)

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.2 onError

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

14.2.3 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.4 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.5 initRequestBeforeParse (advanced usage only)

This special function is called by the server when it receives a POST request, before it parses the POST data. This allows you for instance to tell the server not to parse the POST data (by setting request.parsePostData to 0) and then you can parse the POST data yourself (by reading on request.rfile). Check out the HowTo called "How to stream uploaded files directly to disk" for more information about this

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.