A Brief Introduction to Apache’s mod_python Module

magine that you are a PHP programmer. You use PHP, because it’s simple?but powerful enough to provide you with most of the features you need to develop Web-based applications for your customers. You have heard of or perhaps even played with more powerful languages, such as Python. Most of your development involves building Web applications, so you are concerned about performance, scalability, and flexibility.

The answer to this problem is mod_python, an Apache Web server module that embeds the Python interpreter within the Apache server in a manner similar to PHP. The advantages to this are many, but briefly, embedding the Python interpreter into Apache provides a persistent execution stack that eliminates the start-up penalty associated with running CGI scripts. It also lets you store specific information about the environment and visitors to your application?creating a pseudo-state mechanism for your Web site.

What exactly are we talking about, when we say a persistent execution stack that eliminates the start-up penalty associated with running CGI scripts? The best way to understand the difference between running a CGI application and an embedded code interpreter is to run some tests. As a benchmark I’ll use a simple CGI script first, and then run the equivalent script executed within the mod_python environment. I’ve used the Apache application Apache Bench (ab).

The following simple Web form posts a user’s selection from a select list to a simple CGI script. The form sends one value, named “month,” to the server, where the CGI script prints out the month within the year 2005.

   A simple "get month" script      



Show which month for 2005?:

A Simple Python CGI Script
On the server, the CGI script extracts the month value from the form data and prints it out.

   #!/usr/bin/python   #   #   # A simple script to output a calendar month based off input from a Web form.   #   #   import cgi,calendar      print "Content-Type: text/html 

"   print "A month"   print "
"      form = cgi.FieldStorage()   month = form.getvalue("month")      try:     calendar.prmonth(2005, int(month),2,3)   except Exception,e:     print "That is not a valid month"         print "

"CGI vs. mod_python: Performance Results
Because other machine operations may influence any single result, you must test the application multiple times, taking the mean value over all the executions to get an accurate value. Executing the CGI version 1000 times using 10 connections:

   (mean time, across all concurrent requests)   Time per request:       77.723 [ms]

Executing an equivalent script within the mod_python environment 1000 times using 10 connections, the execution time drops dramatically:

   (mean time, across all concurrent requests)   Time per request:       5.808 [ms] 

Reviewing the above you can see that the mean time of all concurrent requests for the CGI execution is 77.723 milliseconds; but the mean time of all concurrent requests for the mod_python-enabled script is only 5.8 milliseconds?a huge performance increase.

Installing mod_python
Installing mod_python is simple. You typically don’t have to compile mod_python because most modern Linux and FreeBSD distributions include the module in their package management systems. For example, here’s the command to install mod_python on Ubuntu/Debian:

   apt-get install libapache-mod-python2.4

It’s just as simple on Redhat / Fedora Core 4:

   yum install mod_python

On FreeBSD, the command is:

   cd /usr/ports/www/mod_python3; make install clean

After installing mod_python you must configure Apache to use it. The first step is to enable the module in Apache by adding a LoadModule line to your httpd.conf file. You can just append the LoadModule entry to the end of the other LoadModule entries already in the file.

   LoadModule python_module modules/mod_python.so
Author’s Note: You may have to change the paths to your particular installation. Ensure that the path you are using is the actual path to the mod_python.so file.

Now that Apache has been configured to load the module, you need to configure a mod_python handler to work with your scripts. Mod_python uses three standard handlers to work with your application. They are the Publisher, PSP (Python Server Pages), and CGI Handlers.

The Publisher Handler
From the mod_python documentation the Publisher is the suggested handler to use when writing new mod_python applications. To configure a Web-accessible directory for use with the Publisher handler you would do the following. This of course assumes that /var/www/html is your Apache document root.

        SetHandler mod_python     PythonHandler mod_python.publisher     PythonDebug On   

The preceding configuration would add the mod_python handler and associate the /var/www/html/python directory to it. This means that all files under the directory will be processed by the mod_python handler. The addition of the PythonHandler means that you now have a single point of entry for Python script processing. The last line enables debugging during development via the PythonDebug On directive.

The Publisher handler requires slightly different code to generate the example getmonth script. You can use the same HTML as in the CGI example, but you must change the action attribute of the

tag to:

   

The mod_python code would look like:

   # A simple script to output a calendar month based off input    # from a web form.   #   import calendar   from mod_python import apache   def getMonth(req,month):      req.write(calendar.month(2005, int(month),2,3))
Authors note: You do not have to send the content-type headers. Mod_python will handle this for you.

The PSP Handler
The PSP Handler lets you embed Python code into Web pages in a fashion that should be immediately recognizable and comfortable to PHP and JSP (Java Server Pages) programmers. To configure an Apache accessible directory for use with the Python Server Pages you would do the following.

         AddHandler mod_python .psp      PythonHandler mod_python.psp   

As mentioned above, you can use PSP in a fashion similar to native PHP without using a template system such as Smarty. For example, here’s a simple “hello” script using PSP.

            

<% req.write("Hello!") %>

You could also code the entire getmonth script with PSP, for example:

   A simple get month script      <%   import calendar   if form.has_key('month'):      month = form['month']      req.write("
")      req.write(calendar.month(2005, int(month),2,3))      req.write("

") else: %>


Show which month for 2005?:

The PSP model can be tempting for new programmers?or at least those new to mod_python programming. You can use PSP with other handlers and thus allow some control over how your code gets integrated into larger solutions but that can create a hard-to-manage code base. The PSP model also makes it difficult to create an application where the presentation is cleanly separated from the logic. For more information on this problem you may want to review the Model-View-Controller (MVC) writeup on Wikipedia.

A better way to use PSP is as a template language. You can use standard HTML content and embed it into a PSP file like the one shown earlier. Then post data to a mod_python script on the server that processes the PSP template.

Treating the file as a template, using the same HTML as the Publisher Handler illustration, you can modify the Python code as follows:

   #!/usr/bin/python   #   #   # A simple script to output a calendar month based off input    # from a web form.   #   #   import calendar   from mod_python import apache, psp   def getMonth(req,month):      template = psp.PSP(req, filename='../psp/getmonth.psp')      s = calendar.month(2005, int(month),2,3)      req.content_type = "text/html"      template.run({'displaymonth' : s })

You then need to create the getmonth.psp file as mentioned in the line containing the template variable. .

            
         <%=displaymonth%>      

Treating the PSP file as a template allows you to effectively keep logic out of the presentation.

The CGI Handler
The CGI Handler is the mechanism used for the benchmarking at the beginning of this article. It is designed to allow someone who has written a CGI application in Python to migrate to mod_python with minimal changes to the application. If you are migrating from a standard CGI installation, this method of using mod_python is going to feel the most comfortable. However, the CGI handler is not thread safe and will suffer performance problems with busy Web sites compared to the Publisher Handler.

Here’s the CGI Handler used to execute the example script.

         SetHandler mod_python      PythonHandler mod_python.cgihandler   

The configuration sets a directory for executing python scripts with the cgihandler. You don’t have to specify a cgi-bin directory to enable the CGI Handler; the name was chosen purely for consistency.

It is possible to have more than one handler for your application. During migration you might have one handler that is executing legacy CGI scripts and another that executes your mod_python publisher compatible scripts.

This brief introduction should give you a taste of mod_python’s possibilities. Depending on which handler you’re using, you can run Python scripts in a manner similar to CGI, treat Python as an embedded page language, or use templates and associated code files to achieve a clean separation between presentation and logic.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: