from argparse to dictionary in python 2.7

I’ve used python’s argparse module in the past to get command line options for scripts. It provides built-in help, which is nice, and support for both positional and optional arguments. The inelegant way I’ve used it in the past, though, involves a lot of if statements to test for the various arguments and call to call the right function. I don’t like that implementation, and reading through the docs and tutorials never really helped.

Today, I was playing around with argparse again, trying to cleanup and simplify some code and stumbled across what seems to me to be a better way.

The reason I used all those if statements in the past is because the parser returns a Namespace which isn’t iterable:

import argparse

p = argparse.ArgumentParser(description="parse some things.")

p.add_argument("cmd", help=argparse.SUPPRESS, nargs="*")
p.add_argument("-d","--date")
p.add_argument("-p","--project")
p.add_argument("-c","--context")
p.add_argument("-l","--list")

opts = p.parse_args()

print opts

Run this code with input like this:

add "A task to be done." -d=today -p=myproject -l=mylist

(obviously, I’m dealing with task management in the real script) and the parser will return a Namespace object:

Namespace(cmd=['add', 'A task to be done.'], context=None, date='today', list='mylist', project='myproject')

Type Namespace isn’t iterable, and I want a convenient way to get rid of arguments that returned None. Finally stumbled across the answer today– vars. We can extract from the Namespace object to a dictionary by passing the object to vars:

opts = vars(p.parse_args())

Why bother? Well, now we have a dictionary that can more elegantly be dealt with, and we don’t have to hard code all possible keyword arguments for the script. opts is now:

{'date': 'today', 'project': 'myproject', 'cmd': ['add', 'A task to be done.'], 
'list': 'mylist', 'context': None}

Now, in two quick steps we can pop the positional argument (cmd), and cull the unused optional arguments:

command = opts.pop('cmd')
options = { k : opts[k] for k in opts if opts[k] != None }

That gives us a list of the positional argument and its associated text, and a dictionary of the utilized optional arguments. Beginning with Python 2.7, dictionaries get comprehensions much as lists had for a long time. The second line of that couplet uses a dictionary comprehension to get the key:value pairs from opts that aren’t empty. This is nice, because we can call the correct function now using the list command, along with passing it arguments from both command and options.

command[0] gives us a string that names the function we need. So, how can we then call that function (without using eval/exec)? It’s easy with a dictionary that points to the functions we’ve defined. By way of example:

def add(task, *args):
    print task
    for arg in args:
        print arg

functions = { 'add':add }

The add function here obviously doesn’t really add a task. Just for show. Nonetheless, we can call it with our command/options variables thusly:

functions[command[0]](command[1],options)

I like this, because it makes parsing a wide range of potential positional arguments without having to add each one of them to the ArgumentParser. That does, however, cause problems for help output. We won’t have a help script for every possible command this way. My solution for this is to move the help cues into the program description, and exclude the “cmd” argument from the help output:

p = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,description='''
    Parse tasks. Options include:
        add: add a task, followed by the task
        list: list the tasks. Filter with list, project, or context options
        del: delete task by number
        clear: clear tasks
''')

p.add_argument("cmd", help=argparse.SUPPRESS, nargs="*")

That’s it for now. And really, most of this is just so I’ll remember it.

About these ads
About

Associate Professor of Early Latin America Department of History University of Tennessee-Knoxville

Tagged with: , , ,
Posted in programming
6 comments on “from argparse to dictionary in python 2.7
  1. [...] I mentioned in my last post, I’ve been re-working a script to add tasks to a task manager. I’m using The Hit List [...]

  2. Gerald Hofmair says:

    Hi!
    I just skimmed over your blog entry and noticed that you “want a convenient way to get rid of arguments that returned None”. The argparse module docs mention that “Providing default=argparse.SUPPRESS causes no attribute to be added if the command-line argument was not present”.. Best regards, Gerald Hofmair

  3. ctb says:

    Gerald–

    Thanks! I missed that when looking around the docs and google.

  4. Enno says:

    Thanks! Didn’t know about vars(). This really helped me.

  5. errstr says:

    Thanks. I was looking exactly for this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

parecer:
parecer:

Hacer juicio ú dictamen acerca de alguna cosa... significando que el objeto excita el juicio ú dictamen en la persona que le hace.

Deducir ante el Juez la accion ú derecho que se tiene, ó las excepciones que excluyen la accion contrária.

RAE 1737 Academia autoridades
Buy my book!



Chad Black

About:
I, your humble contributor, am Chad Black. You can also find me on the web here.
Follow

Get every new post delivered to your Inbox.

Join 50 other followers

%d bloggers like this: