Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python argparse - Mutually exclusive group with default if no argument is given

I'm writing a Python script to process a machine-readable file and output a human-readable report on the data contained within.
I would like to give the option of outputting the data to stdout (-s) (by default) or to a txt (-t) or csv (-c) file. I would like to have a switch for the default behaviour, as many commands do.

In terms of Usage:, I'd like to see something like script [-s | -c | -t] input file, and have -s be the default if no arguments are passed.

I currently have (for the relevant args, in brief):

parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group() group.add_argument('-s', '--stdout', action='store_true') group.add_argument('-c', '--csv', action='store_true') group.add_argument('-t', '--txt', action='store_true') args = parser.parse_args()  if not any((args.stdout, args.csv, args.txt)):     args.stdout = True 

So if none of -s, -t, or -c are set, stdout (-s) is forced to True, exactly as if -s had been passed.

Is there a better way to achieve this? Or would another approach entirely be generally considered 'better' for some reason?

Note: I'm using Python 3.5.1/2 and I'm not worried about compatibility with other versions, as there is no plan to share this script with others at this point. It's simply to make my life easier.

like image 444
Alex B. Avatar asked Jul 21 '16 14:07

Alex B.


People also ask

How do you make an argument optional in Argparse?

To add an optional argument, simply omit the required parameter in add_argument() . args = parser. parse_args()if args.

What does parse_args return?

Adding arguments Later, calling parse_args() will return an object with two attributes, integers and accumulate . The integers attribute will be a list of one or more ints, and the accumulate attribute will be either the sum() function, if --sum was specified at the command line, or the max() function if it was not.

What is Argparse ArgumentParser ()?

The argparse module provides a convenient interface to handle command-line arguments. It displays the generic usage of the program, help, and errors. The parse_args() function of the ArgumentParser class parses arguments and adds value as an attribute dest of the object.

What is Store_true in Python?

The store_true option automatically creates a default value of False. Likewise, store_false will default to True when the command-line argument is not present.


1 Answers

You could have each of your actions update the same variable, supplying stdout as the default value for that variable.

Consider this program:

import argparse  parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group() group.add_argument(     '-s', '--stdout', action='store_const', dest='type', const='s', default='s') group.add_argument(     '-c', '--csv', action='store_const', dest='type', const='c') group.add_argument(     '-t', '--txt', action='store_const', dest='type', const='t') args = parser.parse_args() print args 

Your code could look like:

if args.type == 's':     ofile = sys.stdout elif args.type == 'c':     ofile = ... ... 

First alternative:

Rather than arbitrarily choose one of the .add_argument()s to specify the default type, you can use parser.set_defaults() to specify the default type.

import argparse  parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group() group.add_argument('-s', '--stdout', action='store_const', dest='type', const='s') group.add_argument('-c', '--csv', action='store_const', dest='type', const='c') group.add_argument('-t', '--txt', action='store_const', dest='type', const='t') parser.set_defaults(type='s') args = parser.parse_args() print args 

Second alternative:

Rather than specify the type as an enumerated value, you could store a callable into the type, and then invoke the callable:

import argparse  def do_stdout():     # do everything that is required to support stdout     print("stdout!")     return def do_csv():     # do everything that is required to support CSV file     print("csv!")     return def do_text():     # do everything that is required to support TXT file     print("text!")     return  parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group() group.add_argument('-s', '--stdout', action='store_const', dest='type', const=do_stdout) group.add_argument('-c', '--csv', action='store_const', dest='type', const=do_csv) group.add_argument('-t', '--txt', action='store_const', dest='type', const=do_text) parser.set_defaults(type=do_stdout) args = parser.parse_args() print args args.type() 
like image 110
Robᵩ Avatar answered Sep 23 '22 15:09

Robᵩ