Ode to docopt
Every week, we have an hour of developer learning at work – maybe a talk, a workshop, or some other session about of topic of interest to developers. Last week, we did a round of lightning talks. We’re quite a mixed group of developers – in background, technical stacks, and what we actually work on – so coming up with a topic that’s useful to all can be tricky.
For my slot, I decided to wax lyrical about the docopt library. Once upon a time, I was sceptical, but it’s become my go-to library for any sort of command-line interface. Rather than fiddling with argparse and the like, I just write a docopt help string, and the hard work is done for me. I’ve used it in multiple languages, and thought it might be handy for other devs at work. Ergo, this talk.
You can download my slides as a PDF, or read the notes below.


If you’ve seen other CLI tools, you might be able to work out how to use it:
- There’s a command called
new, which takes a mandatory<path>parameter and an optional--themeparameter. - There’s a second command
build, which can be called standalone or with the--continuousflag. - There’s a third command
serve, which has two optional parameters:--hostand--port. We can also see that both of these flags have defaults. - Finally, we could use
-hor--helpto get a help message, and--versionto see the version string.
So how would we implement this in code?

Parsing arguments like this is hard, because you have to define your own parsing rules. Code like this is hard to read – it’s not obvious what it’s doing, or how to use the program, unless you actually run it. If you have to edit code like this, it can be tricky to know exactly where to make a change, and be sure you haven’t inadvertently broken something elsewhere.
And argparse is complicated – I never get it right first time.

Luckily for us, such a module already exists!

This is much nicer than our previous example. It’s much easier to see how the code works or add new options, and we write less parsing code (and so less bugs!). And because the interface is auto-generated from the help string, it always stays up-to-date.

In languages with stronger typing, you can define a custom structure, and docopt will create an instance of that structure from the parsed arguments. For example, this is the struct I’d define in Rust:
pub struct Args {
pub cmd_new: bool,
pub arg_path: String,
pub flag_theme: Option<String>,
pub cmd_build: bool,
pub flag_continuous: bool,
pub cmd_serve: bool,
pub flag_host: Option<String>,
pub flag_port: Option<String>,
pub flag_version: bool,
}
It relies on the format of our help string. Remember how we were able to read this help string, because it looked like help strings from other programs?
There’s a standard for writing these help strings, as part of POSIX. By sticking to these rules, docopt can work out how our program is meant to be used, and build an appropriate parser.




This includes lots of the languages we use at Wellcome, including PHP and Scala.
[CoffeeScript is the closest to a JavaScript port in the GitHub organisation. I thought this meant docopt was an exception to Atwood’s Law, but I’ve since found a Node.js port.]

(Another nice thing: docopt is often delivered as a single file, so you can add it to a project even if you don’t/can’t use a package manager.)
