LowEndBox - Cheap VPS, Hosting and Dedicated Server Deals

Command-Line Argument Processing for the Lazy: Python’s argparse Module

Tags: , , , Date/Time: May 7, 2022 @ 2:34 pm, by raindog308

Like many of you, I write a lot of throwaway scripts to do a task.  These are quick undocumented 20-line blobs of code that do janitorial or maintenance tasks and they’re deleted almost as soon as they’re written.

But if something is going to endure, I try to take a more professional approach: documentation and comments, logging, checking sub-command errors, failing gracefully – and handling command-line arguments.

In fact, I’ve found that whether a script handles command-line arguments or not often determines if it’s permanent code or throwaway.  Something designed to do one thing once has no need of configuration knobs, while code that can work many different ways often  means we have a durable tool.

In this article, I’d like to show you how to use python’s very cool argparse module.  If you’re coming from a shell/perl background, you’ll find it’s a little different than typical getopts.  It’s more like Golang or other “big” language parsing.

In this case, we’re going to write some code with these options:

  • -f will specify a file we’re going to process
  • -v will turn on verbose (debugging) output

As you’ll see, Python will automagically include help output (-h).

Let’s look at some simple code.  Python 2 is now obsolete and we’re going to using Python 3.  Here is how we might implement the above requirements

I’ve stored the following in gronkulator.py (a suitable nonsense word that is used in everything from technical documentation to TV shows):

#!/usr/bin/python3

import argparse
import os
import sys

def debug(message):
    if args.wants_debug:
        print (message)

parser = argparse.ArgumentParser ( description = 'reciprocating trans-quantum     gronkulator' )
parser.add_argument('-f', help="file to process", dest="file_name", 
    action='store', required=True)
parser.add_argument('-v', help="enable debugging", dest="wants_debug", 
    action='store_true', required=False, default=False)
args = parser.parse_args()

debug ("Debugging output turned on")
if os.path.exists(args.file_name) == False:
    print ("Error!  File '%s' does not exist - aborting" % ( args.file_name ))
    sys.exit(1)

print ("Processing file '%s'" % ( args.file_name ))

I’ve wrapped a few lines to make things easy to understand.  Let’s do a quick walkthrough.

parser = argparse.ArgumentParser ( description = 'reciprocating trans-quantum gronkulator' )

This creates our parser object.  BTW, you can parse the command-line arguments as many times as you want, so don’t be afraid to include argparse deep in some subroutine if you want to parse again locally.

parser.add_argument('-f', help="file to process", dest="file_name",
    action='store', required=True)
parser.add_argument('-v', help="enable debugging", dest="wants_debug",
    action='store_true', required=False, default=False)

Here we add the arguments.  Just reading the code you can probably figure it out.  -f specifies the file name we’re going to work with.  This parameter is required (=True) and the action is to “store” it in a the variable “args.file_name” (see below).

The next line adds the -v argument.  This is optional and if set, it sets the variable “args.wants_debug” to True, otherwise it is set to False.  This is very pleasant.  After that line, you know the args.wants_debug variable is guaranteed to exist with teh right value and you can reference it anywhere.

args = parser.parse_args()

And this does the actual argument-parsing.  The ‘args’ variable created will then have values that correspond to the “dest” variables (so args.file_name, args.wants_debug, etc.)

After this, we exercise the debug() function and then test to see if file_name exists.  If not, we error out, otherwise we do whatever we need to do with it.

Let’s try the code:

# ./gronkulator.py
usage: gronkulator.py [-h] -f FILE_NAME [-v]
gronkulator.py: error: the following arguments are required: -f

So note that we wrote none of the “usage” code – it’s all generated by python.  Let’s try with -h:

# ./gronkulator.py -h
usage: gronkulator.py [-h] -f FILE_NAME [-v]

reciprocating trans-quantum gronkulator

optional arguments:
  -h, --help    show this help message and exit
  -f FILE_NAME  file to process
  -v            enable debugging

Nice.  Python has given us a complete help chart.

# ./gronkulator.py -f /tmp/junk 
Processing file '/tmp/junk'
# ./gronkulator.py -v -f /tmp/junk 
Debugging output turned on
Processing file '/tmp/junk'

Appears to be working as intended.  We get debugging output if we turn on -v and don’t get it if we don’t, and the script picks up the -f argument.

There is a ton more you can do – everything from adding abbreviations and long-flags to adding epilog to help, parsing non-sys.argv streams, handling variables that are already-set, and so much more.  Indeed, the main problem is that argparse itself has so many options that some readers are overwhelmed.  But I think the basics – require some flags, access their values later – is very simple and easy to copy-paste from a recipe like the above.  Enjoy!

No Comments

    Leave a Reply

    Some notes on commenting on LowEndBox:

    • Do not use LowEndBox for support issues. Go to your hosting provider and issue a ticket there. Coming here saying "my VPS is down, what do I do?!" will only have your comments removed.
    • Akismet is used for spam detection. Some comments may be held temporarily for manual approval.
    • Use <pre>...</pre> to quote the output from your terminal/console, or consider using a pastebin service.

    Your email address will not be published.