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>
More recent articles
- Weeknotes: Parquet in Datasette Lite, various talks, more LLM hacking - 4th June 2023
- It's infuriatingly hard to understand how closed models train on their input - 4th June 2023
- ChatGPT should include inline tips - 30th May 2023
- Lawyer cites fake cases invented by ChatGPT, judge is not amused - 27th May 2023
- llm, ttok and strip-tags - CLI tools for working with ChatGPT and other LLMs - 18th May 2023
- Delimiters won't save you from prompt injection - 11th May 2023
- Weeknotes: sqlite-utils 3.31, download-esm, Python in a sandbox - 10th May 2023
- Leaked Google document: "We Have No Moat, And Neither Does OpenAI" - 4th May 2023
- Midjourney 5.1 - 4th May 2023
- Prompt injection explained, with video, slides, and a transcript - 2nd May 2023