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:
CFLAGS=$(OPT) $(INCLUDES)
into:
CFLAGS=$(OPT) $(INCLUDES) -DEAPI
Then do the build:
make clean make 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 </Location>
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 = {} environ.update(apache.build_cgi_env(req)) - 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 else: self.req.headers_out.add(name, value) - def _sendfile(self, fileobj): - self._send_headers() - self.req.sendfile(fileobj.name) - def _write(self, data): self._send_headers() try:
Caveats
- 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.