I’ve been using Docopt - a neat library that lets you define command line arguments in a good looking, human readable docstring - in the entry point file of some of my Flask projects lately, and I thought I should share it.

It’s nothing super fancy, but useful in development as it allows me to optionally specify the interface and port of the server. Here’s the entry point file I use for What is my ZIP?:

"""
Whatismyzip.com Website

Usage:
  web.py
  web.py <interface:port>
  web.py -h | --help

Options:
  -h --help    Show this help
"""

import re

from docopt import docopt
from raven.contrib.flask import Sentry

from whatzip import app


if __name__ == '__main__':
    # try to parse host and port, to listen to, from command line
    arguments = docopt(__doc__, help=True)
    listen_to = arguments.get("<interface:port>")
    app_kwargs = {}
    if listen_to:
        matches = re.match("([0-9A-z.-]+):(\d{1,5})", listen_to)
        if matches:
            app_kwargs["host"] = matches.group(1)
            app_kwargs["port"] = int(matches.group(2))

    # run app
    app.run(debug=True, **app_kwargs)
else:
    sentry = Sentry(app)

Then I can start the development server using either:

python web.py 0.0.0.0:8080

or, if I’m happy with the default interface and port, I can do:

python web.py

And in production I run it through gunicorn:

gunicorn -b 0.0.0.0:$PORT -k gevent web:app

The final Sentry(app) row under the else: is there to set up Sentry logging for the app, and that whole else clause can be skipped if you don’t want Sentry logging in production.

Hopefully this can be useful to someone else :).