Programming, Python

Optional at no extra charge

Some applications are simple enough to run without asking the user to make any decisions.

Arguably, that’s even safer.

On the other hand, giving the user control extends the usefulness of your work by eliminating hard-coded values. It also can give the user a sense of context. Having a little control over destiny gives your users a better feeling.

Command line options take a little care, though, or errors can be introduced. For instance, Python’s getopt module will be completely happy with this command line:

processbuffer --outut=log.txt

However, if your code expected a command line argument called output, not outut, your code should notice and call a graceful halt to the proceedings. You wouldn’t want to burn an hour of processing only to find you had nowhere to write your summary.

It’s nice to fold related functions into a single application by using command line arguments, but you can easily end up with mutually exclusive options.

These problems, and a few others, are addressed by my Options module.

Let’s define three options for a Python application called processbuffer, each with a short and a long name. There’s a for assemble, t for transmogrify, and r for report.

For full details, see the attached documentation for the Options module. Here’s a quick look at how to set this up. The Param class takes these arguments of interest:

  • shortName
  • longName
  • required companion arguments
  • optional companion arguments
  • flag to allow an associated value
  • paramFunc, a function to process the option

There’s more flexibility, but these cover the bases. First, an array of parameters to allow on the command line:

params=(Param('a', 'assemble', '', 't', 
              paramFunc=assemble),
        Param('t', 'transmogrify', '', 'a',
              paramFunc=transmogrify),
        Param('r', 'report', '', '',
              paramFunc=report, paramFlag=True))

Now, let’s parse the command line, allowing options a and t to coexist, blocking r if either a or t is specified, and naming the report output file if the report option is active:

opt=Options(sys.argv[1:], params)

Now let’s run whichever functions are required:

opt.execParams()

Now, wasn’t that easy? We listed the parameters we’re interested in. Each parameter had a list of options it was compatible with and a list it had to coexist with. The r option’s paramFlag option means it needs an output file name.

Two additional lines of code parsed the command line and decided which functions to run.

Here’s how we would assemble and transmogrify (whatever those operations really are), using the short, single-character, names for the options:

processbuffer -at

Here’s the command line for writing a report file, using a long option name:

processbuffer --report=outputlog.txt

Any single project might not merit the effort to create anything like this Options module. However, ten applications in the course of a year, each made a little nicer and easier to use, is definitely worth the trouble.

No single use case justifies modules like Options, but having things like this around adds up to a valuable resource. I hope you find code like this useful, too.

Want to know more? Better yet, need a developer on staff with this kind of initiative? I’m available for hire! Let me know how I can help in the comments below, by email to carl@carlhaddick.com, or via the Get in Touch! link at the top of this page.

Source to options.py with detailed PDF documentation is available for download here.