The argparse() conundrum

Rangaswamy P V
8 min readAug 11, 2024

--

This article walks you through how to code your command line argument in python using argparse.py .

argparse.py offers a flexibility of the user to give command line arguments in python and get the desired output. argparse.py is the better way than the previous optparse() which is deprecated since python 3.2. optparse() in itself replaced the getopt() module. At the end of the article you should be clear as to how to use argparse() and the various methods it has to offer.

There are three main sections that we need to focus on to get the module to parse and execute the command line arguments that the user inputs during the program compilation

  • Instantiate the Class ( ArgumentParser() )
  • Add the arguments that the Class can take , by invoking the method( add_argument() )
  • Finally Parse the argument, by invoking the method (parse_args() )

If you can do the above three steps then you can have a simplest of an argparse() module for your program. Lets see how that code looks

#!/usr/bin/env python
import argparse

def findsh4(self):
values=5
return values


parser = argparse.ArgumentParser(description='A python code to display Docker stats', epilog='Hope you like this program')


parser.add_argument('-s', type=findsh4)
args = parser.parse_args()
print(args)

To get a full fledged example scroll to the reference section below ….

After parsing the argument depending on the “type” and “action” parameters that are defined in the add_argument those actions are correspondingly executed by the code. The help argument in add_argument is automatically executed if not explicitly coded. Since some of the options are automated at times argparse may feel like a conundrum, but rest assured it is a elegant way to parse the user input.

Now let's understand the module itself.

argparse() itself has the following main classes..

CLASS:of argparse.ArgumentParser
.Namespace
.Action
.FileType
.ArgumentError
.HelperFormatter

Among the above the major focus shifts to the ArgumentParser() and the Action() classes. In this article I am limiting the scope to two Classes namely the ArgumentParser() and Action()

First and foremost you instantiate the ArgumentParser class ..

parser = argparse.ArgumentParser(description='A python code to  display Docker stats', epilog='Hope you like this program')

The Class definition is as shown below

class argparse.ArgumentParser(prog=None, usage=None, description=None, epilog=None, parents=[], formatter_class=argparse.HelpFormatter, prefix_chars='-', fromfile_prefix_chars=None, argument_default=None, conflict_handler='error', add_help=True, allow_abbrev=True, exit_on_error=True)Description of some of the attributes.....prog: NAME OF YOUR PYTHON PROGRAMparents:# It is to tell how to display the help message
formatter_class:
argparse.RawDescriptionHelpFormatter¶
argparse.RawTextHelpFormatter
argparse.ArgumentDefaultsHelpFormatter
argparse.MetavarTypeHelpFormatter
#read the args from a file
fromfile_prefix_chars:
..
..
..
For the description of the rest of the attributes refer to the reference section at the bottom of this article for link to the Official python documentation of argparse().

The main objective is to tell how to read the inputs from the command line when calling the python program; in some case it can also take inputs from a file. Should one expect only integers or strings and to which attribute should I hold these values for further processing. Also sometimes how to display the help and set default values if the inputs are not given ..etc…

Lets jump to the different methods for ArgumentParse as of at-least python 3.12.4 are the following

.add_argument()
.parse_args()
.add_subparsers()
.add_argument_group()
.add_mutually_exclusive_group()
.set_defaults()
.get_defaults()
.print_usuage ()
.print_help ()
.format_usuage ()
.format_help ()
.parse_known_args()
.convert_arg_line_to_args()
.exit()
.error()
.parse_intermixed_args()
.parse_known_intermixed_args()

In this article the focus is on the methods add_argument() and parse_args().

If you need other method functionality kindly refer to the reference section at the bottom of this article for the official python documentation on ArgParse().

Among the above the add_argument() method is the first and foremost method that needs to be invoked to get started with the processing of command line. This method has the following structure….

ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])name or flags - Either a name or a list of option strings, e.g. foo or -f, --foo.* action - The basic type of action to be taken when this argument is encountered at the command line. e.g ..('store', 'store_const', 'store_true', 'append', 'append_const', 'count', 'help', 'version')
* nargs - The number of command-line arguments that should be consumed.
* const - A constant value required by some action and nargs selections.
* default - The value produced if the argument is absent from the command line.
* type - The type to which the command-line argument should be converted.
* choices - A container of the allowable values for the argument.
* required - Whether or not the command-line option may be omitted (optionals only).
* help - A brief description of what the argument does.
* metavar - A name for the argument in usage messages.
* dest - The name of the attribute to be added to the object returned by parse_args().

The add_argument() is basically telling the program how to expect the user inputs, and where to store the attributes so that it can be printed out once whatever the user computation is completed.

Generally a add_argument() will have an attribute and the action to be performed. That is why you will have multiple add_arguments in a program. In some cases when you want more than one value in an attribute then you can use nargs=+ to specify it.

The name is used as a placeholder for positional values that the program may take or flag is used for optional parameters that the program may take to execute certain methods/if-else statements etc…..

The metavar is used to inform the “help” message what it should display in usage in case of Positional parameters should the name itself be displayed else the “type” value should be displayed and in case of optional parameters should the default behavior of “help” value is displayed or the “type” values is to be displayed.

“type” is an interesting way to affect the way the positional or optional argument are treated.

It can say how to store the user input either as string or integer.

  • Can call the in built functions like open() etc
  • And also your own custom methods as a callable.

The “action” keyword can take one of the following values, which can have the following values.

* store,
* store_const,
* store_true/store_false,
* append,
* append_const,
* count,
* help,
* version,
* extend
and also from version 3.8 you can add your own custom function.

The add_argument() method is where you specify all the permutation and combination of how the user inputs the command line arguments. The methods has various arguments that you can customize. In this article we will deep dive into two notable parameters the “ action” and “type” whose usefulness is mentioned below.

The rest of the arguments in add_argument() deals with how the positional and optional arguments in the command line by the user are to be grokked.

To make it a bit more interesting lets write a custom Action

Writing your custom class and getting called in the action

The Action class mentioned in the beginning of this article is what will power the “action” argument in the add_argument call . Let us look at the Action() class structure

class argparse.Action(option_strings, dest, nargs=None, const=None, default=None, type=None, choices=None, required=False, help=None, metavar=None)

All the above details are the theory and the science behind this module in python. Now let's quickly jump into the practical implementation of this.

I will show you one example of using type and one example of using the action=Custom Action class and leave the rest of the option to your imagination to custom suit your specific use case.

Instead of using type keyword, one can directly call action keyword and mention the overriding action class which inherits “argparse.Action” and write custom functionality inside the __call__ method of the newly created class. robustness to the code hence from 3.8 onwards the action=customAction Class was added.

One of the examples of type is as shown below …

The main way to achieve this is by using the action keyword in the add_argument() method of the Argumentparse.

So your program in its simplest form will have the following argparse code to get started…

This is all you need to have in your code to process the command line. See its so simple and looks elegant compared to sys.argv[] .

#!/usr/bin/env python
import argparse

def findsh4(self):
values=5
return values


parser = argparse.ArgumentParser(description='A python code to display Docker stats', epilog='Hope you like this program')


parser.add_argument('-s', type=findsh4)
args = parser.parse_args()
print(args)

The custom function will look similar to this …

#!/usr/bin/env pythonimport os
import subprocess
import sys
import io
import re
import argparse
import shutil
from subprocess import PIPEclass Dangle1(argparse.Action):def __init__(self, option_strings, dest, nargs=None, **kwargs):
if nargs is not None:
raise ValueError("nargs not allowed")
super(Dangle1, self).__init__(option_strings, dest, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
#def Dangle1(a,string):
#value = int(string)
t1 = subprocess.run("ls -l", capture_output=True, shell=True, text=True, check=True)
l = []
count = 0
dest=t1
values=t1
setattr(namespace, self.dest, values)
def findsh4(self):
values=5
return values
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='A python code to display argparse capability', fromfile_prefix_chars='@', epilog='Hope you like this program')
parser.add_argument('-id', action=Dangle1)
parser.add_argument('-s', type=findsh4)args = parser.parse_args() print(args.id)
print(args.s)

In the above example when you mention action=YourCustomAction , the module defines how you write your custom Class. It inherits the argparse.Action .

What the above code does is it instantiates the ArgumentParse and gives the handle to parser variable and which in turn calls the add_argument method to add optional arguments to execute a Action key word which is a callable class . The Action object needs to be a prototype of argparse.Action(). The values that are stored in those optional are then used to pass to a function or call a callable(function) to get the desired output.

The help argument for the action is automatically generated if it is not customized in the program.

metavar simply says how the help is going to be displayed for both the optional and positional argument. For positional argument it is as is and for Optional it is uppercased in the display. In case of optional having tuple value it is presented as is without upper casing if it is lower.

The other parameters of add_argument like the dest, const, nargs have subtle benefits ; Also as mentioned in the figure 2 above about the methods available like resolve conflict, grouping_arguments and mutually_exclusive groups etc ..since this article is not an exhaustive list to argparse and all its different use cases the details can be found in the reference section of the official python documentation.

Conclusion: There are two ways you can run your custom code using argparse(). Either write it as a method and pass it as its name in the “type” of add_argument.

alternatively

write your custom code as a Class that inherits argarpase.Action and override the __call__ dunder to your specific needs and call it in the “action” of add argument

If you have any issues, you can open an issue in the github repo page or alternatively contact me at rangapv@yahoo.com and you can also find me on X.com(twitter) @rangapv

--

--