Running Pydoc under mod_python
I’ve written about pydoc before. In my opinion it’s one of Python’s best kept secrets: a way of instantly browsing the properties, methods and documentation strings of any module available to the Python environment. It can even run a local HTTP server to allow for easy browsing of available documentation.
That’s all well and good for code running on your local machine, but most developers won’t want to run a Pydoc server on a remote machine. We ran in to this problem recently at work; we wanted to run Pydoc on our development server but didn’t want it exposed to the world at large.
Initially we considered running the regular Pydoc server locally on some random port, blocking that port to external IPs with a firewall rule and then using Apache’s mod_proxy to open it up to outside access in a controlled manner. The downside with this is that we would have to run a special process and a firewall rule just to enable a relatively minor function. Instead, I spent some time working through the pydoc.py source code and came up with a mod_python wrapper for the HTML documentation part of the module.
(Aside: Safari will try to render the above as HTML, even though the Content-Type header says text/plain. This is because Safari is brain-dead—it inherited this particular grotesqueness from Internet Explorer. I still use it though.)
Since we were already running mod_python on our development server, adding this extra module required no extra server configuration or additional server processes. It also allowed us to tie authentication for the resulting Pydoc instance to our existing authentication database, using mod_auth_pgsql.
For the inquisitive, here’s a rough approximation of the relevant parts of our httpd.conf file for that server:
LoadModule access_module modules/mod_access.so LoadModule auth_module modules/mod_auth.so LoadModule alias_module modules/mod_alias.so LoadModule auth_pgsql_module modules/mod_auth_pgsql.so LoadModule python_module modules/mod_python.so RedirectMatch permanent /pydoc$ /pydoc/ <Location "/pydoc/"> SetHandler python-program PythonHandler utils.modpydoc PythonPath "sys.path+['/path/to/our/codebase/']" AuthName "Code Browser" AuthType basic Auth_PG_database ourdb Auth_PG_user dbuser Auth_PG_pwd_table users Auth_PG_uid_field username Auth_PG_pwd_field password_md5 Auth_PG_pwd_whereclause " AND can_browse_code = 't' " Auth_PG_hash_type MD5 require valid-user </Location>