Edgewall Software

Trac and mod_python 2.7

TracModPython setup is for Apache 2, but it may be possible to work with Apache 1.3.

Installing mod_python

These instructions below have worked for:

  • the Apache installation that comes with MacOS 10.4
  • Python 2.4.3 installed using Fink
  • Trac 0.11dev-r6202

First, make sure that the Python in the $PATH is the Python you want to use (you can revert it later):

sudo mv /usr/bin/python /usr/bin/python.back
sudo ln -s /sw/bin/python2.4 /usr/bin/python

Then download and build the mod_python 2.7 module. Use the most recent 2.7 version, mine was 2.7.11:

curl http://www.axint.net/apache/httpd/modpython/mod_python-2.7.11.tgz > mod_python-2.7.11.tgz
tar -xzf mod_python-2.7.11.tgz
cd mod_python-2.7.11 
./configure -with-apxs=/usr/sbin/apxs

At this stage, I had to edit the build settings, because once installed, I was getting an warning. So in src/Makefile I changed:




Then do the build:

make clean
sudo make install

mod_python is now installed.

Configurating and testing mod_python

You must add the following lines to your httpd.conf:

    LoadModule python_module libexec/mod_python.so

The actual path to mod_python.so may vary, but make install should report at the very end exactly where mod_python.so was placed and how the LoadModule directive should appear, and

    AddModule mod_python.c

You can test that everything is OK using the instructions on http://www.modpython.org/live/mod_python-2.7.8/doc-html/inst-testing.html. Then, modify the settings for your Trac instance into:

<Location /projects/myproject>
   SetHandler python-program
   PythonHandler trac.web.modpython_frontend
   PythonOption TracEnv /var/trac/myproject
   PythonOption TracUriRoot /projects/myproject

Of course, use your own values for /projects/myproject and /var/trac/myproject. TracUriRoot may not be necessary. If you remove it, you will need to modify the patch below.

Restart Apache after each configuration change.

Patching Trac

At this stage, opening http://localhost/projects/myproject in your browser will likely return an error 500. You can look in the error_log file: it is likely a Python exception, because the trac.web.modpython_frontend code tries to use APIs from mod_python that are different in 3.3.

Here's a simple patch for trac/web/modpython_frontend.py. It's just a hack, but it does the job:

--- /sw/lib/python2.4/site-packages/Trac-0.11dev_r6202-py2.4.egg/trac/web/modpython_frontend.py.r6202	2007-11-21 16:11:25.000000000 -0800
+++ /sw/lib/python2.4/site-packages/Trac-0.11dev_r6202-py2.4.egg/trac/web/modpython_frontend.py	2007-12-13 10:44:05.000000000 -0800
@@ -47,25 +47,14 @@
 class ModPythonGateway(WSGIGateway):
-    wsgi_multithread = apache.mpm_query(apache.AP_MPMQ_IS_THREADED) > 0
-    wsgi_multiprocess = apache.mpm_query(apache.AP_MPMQ_IS_FORKED) > 0
     def __init__(self, req, options):
         environ = {}
-        if 'TracEnv' in options:
-            environ['trac.env_path'] = options['TracEnv']
-        if 'TracEnvParentDir' in options:
-            environ['trac.env_parent_dir'] = options['TracEnvParentDir']
-        if 'TracEnvIndexTemplate' in options:
-            environ['trac.env_index_template'] = options['TracEnvIndexTemplate']
-        if 'TracTemplateVars' in options:
-            environ['trac.template_vars'] = options['TracTemplateVars']
-        if 'TracLocale' in options:
-            environ['trac.locale'] = options['TracLocale']
+	environ['trac.env_path'] = options['TracEnv']	
-        if 'TracUriRoot' in options:
+	if True:
             # Special handling of SCRIPT_NAME/PATH_INFO for mod_python, which
             # tends to get confused for whatever reason
             root_uri = options['TracUriRoot'].rstrip('/')
@@ -76,10 +65,6 @@
             environ['SCRIPT_NAME'] = root_uri
             environ['PATH_INFO'] = urllib.unquote(request_uri[len(root_uri):])
-        egg_cache = req.subprocess_env.get('PYTHON_EGG_CACHE')
-        if egg_cache:
-            os.environ['PYTHON_EGG_CACHE'] = egg_cache
         WSGIGateway.__init__(self, environ, InputWrapper(req),
                              _ErrorsWrapper(lambda x: req.log_error(x)))
         self.req = req
@@ -91,17 +76,11 @@
             status, headers = self.headers_sent = self.headers_set
             self.req.status = int(status[:3])
             for name, value in headers:
-                if name.lower() == 'content-length':
-                    self.req.set_content_length(int(value))
-                elif name.lower() == 'content-type':
+                if name.lower() == 'content-type':
                     self.req.content_type = value
                     self.req.headers_out.add(name, value)
-    def _sendfile(self, fileobj):
-        self._send_headers()
-        self.req.sendfile(fileobj.name)
     def _write(self, data):


  • The patch removes a few functionalities, such as setting up the PYTHON_EGG_CACHE: if you need them, you will need to modify the patch.
  • There may be a character set issue: the non-ASCII chars may not be working properly. It is probably easy to fix.
  • In my setup, the performance was not improved by moving to mod_python, but it is likely an issue with the database access.
Last modified 17 months ago Last modified on Feb 22, 2015, 3:11:28 PM