Software I've written myself, or projects to which I've made a reasonable contribution.


Available in a git repository.
Repository: rss2email
Browsable repository: rss2email
Author: W. Trevor King

Since November 2012 I've been maintaining rss2email, a package that converts RSS or Atom feeds to email so you can follow them with your mail user agent. Rss2email was created by the late Aaron Swartz and maintained for several years by Lindsey Smith. I've added a mailing list (hosted with mlmmj) and PyPI package and made the GitHub location the homepage.

Overall, setting up the standard project infrastructure has been fun, and it's nice to see interest in the newly streamlined code picking up. The timing also works out well, since the demise of Google Reader may push some talented folks in our direction. I'm not sure how visible rss2email is, especially the fresh development locations, hence this post ;). If you know anyone who might be interested in using (or contributing to!) rss2email, please pass the word.


Available in a git repository.
Repository: mutt-ldap
Browsable repository: mutt-ldap
Author: W. Trevor King

I wrote this Python script to query an LDAP server for addresses from Mutt. In December 2012, I got some patches from Wade Berrier and Niels de Vos. Anything interesting enough for others to hack on deserves it's own repository, so I pulled it out of my blog repository (linked above, and mirrored on GitHub).

The README is posted on the PyPI page.


Available in a git repository.
Repository: curses-check-for-keypress
Browsable repository: curses-check-for-keypress
Author: W. Trevor King

There are some points in my experiment control code where the program does something for an arbitrary length of time (e.g, waits while the operator manually adjusts a laser's alignment). For these situations, I wanted to be able to loop until the user pressed a key. This is a simple enough idea, but the implementation turned out to be complicated enough for me to spin it out as a stand-alone module.


Available in a git repository.
Repository: pyassuan
Browsable repository: pyassuan
Author: W. Trevor King

I've been trying to come up with a clean way to verify detached PGP signatures from Python. There are a number of existing approaches to this problem. Many of them call gpg using Python's multiprocessing or subprocess modules, but to verify detached signatures, you need to send the signature in on a separate file descriptor, and handling that in a way safe from deadlocks is difficult. The other approach, taken by PyMe is to wrap GPGME using SWIG, which is great as far as it goes, but development seems to have stalled, and I find the raw GPGME interface excessively complicated.

The GnuPG tools themselves often communicate over sockets using the Assuan protocol, and I'd already written an Assuan server to handle pinentry (originally for my gpg-agent post, not part of pyassuan). I though it would be natural if there was a gpgme-agent which would handle cryptographic tasks over this protocol, which would make the pgp-mime implementation easier. It turns out that there already is such an agent (gpgme-tool), so I turned my pinentry script into the more general pyassuan package. Now using Assuan from Python should be as easy (or easier?) than using it from C via libassuan.

The README is posted on the PyPI page.


Available in a git repository.
Repository: pygrader
Browsable repository: pygrader
Author: W. Trevor King

The last two courses I've TAd at Drexel have been scientific computing courses where the students are writing code to solve homework problems. When they're done, they email the homework to me, and I grade it and email them back their grade and comments. I've played around with developing a few grading frameworks over the years (a few years back, one of the big intro courses kept the grades in an Excel file on a Samba share, and I wrote a script to automatically sync local comma-separated-variable data with that spreadsheet. Yuck :p), so I figured this was my change to polish up some old scripts into a sensible system to help me stay organized. This system is pygrader.

During the polishing phase, I was searching around looking for prior art ;), and found that Alex Heitzmann had already created pygrade, which is the name I under which I had originally developed my own project. While they are both grade databases written in Python, Alex's project focuses on providing a more integrated grading environment.

Pygrader accepts assignment submissions from students through its mailpipe command, which you can run on your email inbox (or from procmail). Students submit assignments with an email subject like

[submit] <assignment name>

mailpipe automatically drops the submissions into a student/assignment/mail mailbox, extracts any MIME attachments into the student/assignment/ directory (without clobbers, with proper timestamps), and leaves you to get to work.

Pygrader also supports multiple graders through the mailpipe command. The other graders can request a student's submission(s) with an email subject like

[get] <student name>, <assignment name>

Then they can grade the submission and mail the grade back with an email subject like

[grade] <student name>, <assignment name>

The grade-altering messages are also stored in the student/assignment/mail mailbox, so you can peruse them later.

Pygrader doesn't spawn editors or GUIs to help you browse through submissions or assigning grades. As far as I am concerned, this is a good thing.

When you're done grading, pygrader can email (email) your grades and comments back to the students, signing or encrypting with pgp-mime if either party has configured a PGP key. It can also email a tab-delimited table of grades to the professors to keep them up to speed. If you're running mailpipe via procmail, responses to grade request are sent automatically.

While you're grading, pygrader can search for ungraded assignments, or for grades that have not yet been sent to students (todo). It can also check for resubmissions, where new submissions come in response to earlier grades.

The README is posted on the PyPI page.


Some of the classes I TA use Maple. (Caveat: I prefer Python, as a more general language. Use SymPy or Sage if you need symbolic processing.) Anyhow, I get Maple worksheets to grade. SSHing into the department computer lab to fire up xmaple is a pain, so I wrote to extract the Maple commands from the worksheet. It benefits from the fact that worksheets are fairly clean XML. Graphs and equations are more difficult, since they have complicated layout and are stored as encoded blobs. Other than that, things work pretty well. Here's the output from my example worksheet, picking out the math-mode sections (in red) and unprocessed blocks (in yellow) from the comments (uncolored).

$ --color 
Hi there
> restart;
> interface(prettyprint=0):
> 1;# one  + plus 2 two ;
> 3 + 4;  bold

Available in a git repository.
Repository: update-copyright
Browsable repository: update-copyright
Author: W. Trevor King

A few years ago I was getting tired of having missing or out-of-date copyright blurbs in packages that I was involved with (old license text, missing authors, etc.). This is important stuff, but not the kind of thing that is fun to maintain by hand. I wrote a script for bugs everywhere that automated the process, using the version control system to extract lists of authors and dates for each file. The script was great, so I ported it into a few other projects I was involved in.

This month I realized that it would be much easier to just break the script out into its own package, and only maintain a config file in each of the projects that use it. I don't know why this didn't occur to me years ago :p. Anyhow, here it is! Enjoy.

The README, with usage details, is posted on the PyPI page.


Mailcap files, defined in RFC 1524, allow you to tell you mail clients, web browsers, and other programs how you want to view and edit various MIME types. Since interaction with your mailcap files often occurs deep within the bowels of your program, I've written up a very simple Python script to test your mailcap entries: Enjoy!

Related utilities include xdg-open, mimeopen, and sensible-utils.


Quoting in mailcap files is a tricky issue. From the Mutt man page:

Secure use of mailcap

The interpretion of shell meta-characters embedded in MIME parameters can lead to security problems in general. Mutt tries to quote parameters in expansion of %s syntaxes properly, and avoids risky characters by substituting them, see the mailcap_sanitize variable.

Although mutt's procedures to invoke programs with mailcap seem to be safe, there are other applications parsing mailcap, maybe taking less care of it. Therefore you should pay attention to the following rules:

Keep the %-expandos away from shell quoting. Don't quote them with single or double quotes. Mutt does this for you, the right way, as should any other program which interprets mailcap. Don't put them into backtick expansions. Be highly careful with eval statements, and avoid them if possible at all. Trying to fix broken behaviour with quotes introduces new leaks - there is no alternative to correct quoting in the first place.

If you have to use the %-expandos' values in context where you need quoting or backtick expansions, put that value into a shell variable and reference the shell variable where necessary, as in the following example (using $charset inside the backtick expansion is safe, since it is not itself subject to any further expansion):

text/test-mailcap-bug; cat %s; copiousoutput; test=charset=%{charset} \
    && test "`echo $charset | tr '[A-Z]' '[a-z]'`" != iso-8859-1

In the course of my research, I've spend a good deal of time developing clean, Python interfaces to much of our lab equipment. I also tend to have strong opinions on the One True Way® to solve a problem. This means that I occasionaly end up writing script to run other people's experiment, especially when they don't take all that much time to write.

I wrote slow_bend for Liming Zhao, who was a postdoc in our lab from 2008 to 2010. Liming coated one side of an AFM cantilever with a film of cellulose and used slow (version 0.2) to monitor the cantilever deflection as he flushed in different buffers (paper). Unfortunately, the paper claims the data aquisition was carried out in LabView.

slow_bend is not a complicated program; it polls analog input channels using pycomedi (and optionally reads temperatures using backends from pypid). The polling continues until slow_bend recieves a KeyboardInterrupt.

$ --version
$ 0 3
#time (second)  chan 0 (bit)    chan 0 (volt)   chan 3 (bit)    chan 3 (volt)
1.81198e-05 34727   0.598001    39679   2.10925
4.00409 34956   0.667887    38033   1.60693
8.00408 35074   0.703899    36780   1.22454
12.0041 35041   0.693828    35814   0.929732
16.0041 34917   0.655985    35044   0.694743

Available in a git repository.
Repository: cookbook
Browsable repository: cookbook
Author: W. Trevor King

I've been running a home-rolled recipe webapp for a year now, and it worked fairly well in a bare-bones sort of way. However, I recently had to make some changes to my personal website (since EveryDNS and aparently most other free DNS providers were bought by Dyn), which prompted me to translate cookbook into a Django app. Thanks to the wonders of Django, Grappelli, and django-taggit, the code is now leaner, meaner, and prettier!

See the README for details.