Mimsy Were the Borogoves

Hacks: Articles about programming in Python, Perl, PHP, and whatever else I happen to feel like hacking at.

Python command-line option parser

Jerry Stratton, December 25, 2006

Just a note about the command-line parser in my iTunes python script. Back in Python 2.2 (Mac OS X 10.2) I needed a simpler and more versatile command-line parser than getopt, so I wrote commandline.py. Erik Osheim points out that I don’t need to use it any more: as of Python 2.3 there is a new command-line options parser called optparse that does everything I need, and it comes standard with Python 2.3 and greater.

It’s also easier to use and works better. Last weekend I took a close look at it and will be replacing commandline.py in my other scripts when I have time. Here’s a simple example of how it works, from a more recent script:

[toggle code]

  • from optparse import OptionParser
  • #set up command-line options
  • parser = OptionParser()
  • parser.add_option("-s", "--slug", help="start with page matching slug", metavar="SLUG", dest="pageslug")
  • parser.add_option("-l", "--local", help="do not upload", default=True, action="store_false", dest="upload")
  • parser.add_option("-r", "--no-recurse", help="do not publish child pages", default=True, action="store_false", dest="recurse")
  • #grab options
  • (options, args) = parser.parse_args()
  • #do web pages
    • if options.pageslug:
      • page = getPageFromSlug(options.pageslug)
    • else:
      • page = getPageFromPath("", host="www.hoboes.com")
    • if page:
      • makePage(page, upload=options.upload, recurse=options.recurse)
    • else:
      • print "Could not find a base page"

This is from the publish script that I use to publish the on-line version of Negative Space from my local Django-managed database. It sets up three options:

  • a “slug” option that tells the script to start with a specific page (identified by its “slug”);
  • a “local only” flag that tells the script not to upload files to the server;
  • a “do not recurse” flag that tells the script to do only the specified page and not any of its subpages.

Most of it is self-explanatory, but the “metavar” is the name used in the help for that option’s required text, and “dest” is the name of the property you’ll use to access the value of that option. You can see that I check “options.pageslug” to decide whether to start from a specific page or start from the home page, and I use options.upload and options.recurse to set those arguments in the “makePage” function.

The parser automatically sets up a “--help” option, and the “parse_args()” method automatically stops the script if --help is requested or if the user specifies invalid options.

Here is the help generated by the above script:

7: bin/publish -help
usage: publish [options]

	-h, --help           show this help message and exit
	-sSLUG, --slug=SLUG  start with page matching slug
	-l, --local          do not upload
	-r, --no-recurse     do not publish child pages

You can also specify a “type” for each option requiring that the value be a number or a choice from a list of choices.

One thing it doesn’t do, which I’d been hoping for (my commandline.py doesn’t do it either), is a “conditional default” that is conditional to the option being specified. For example, I have an option called “--upcoming” in my iTunes script that takes a number as its value: the number of upcoming tracks to display. I’d like to be able to specify --upcoming both with and without a number, applying a default of 10 only if --upcoming was specified on the command-line but was specified with no number.

This would of course be difficult to parse (it would need to determine whether it should or should not consume the next item on the command line) but would be useful. It might be possible to add this feature by extending the available actions, or perhaps I’m missing something in the on-line docs.

In response to Using appscript in Python to control GUI applications: The appscript module for Python lets you control scriptable applications on the command line without having to coordinate your command-line script with your Applescript applications.

  1. Appscript Translator ->