Chase Seibert

Multi-level argparse in Python (parsing commands like git)

It’s a common pattern for command line tools to have multiple subcommands that run off of a single executable. For example, git fetch origin and git commit --amend both use the same executable /usr/bin/git to run. Each subcommand has its own set of required and optional parameters.

This pattern is fairly easy to implement in your own Python command-line utilities using argparse. Here is a script that pretends to be git and provides the above two commands and arguments.

#!/usr/bin/env pythonimportargparseimportsysclassFakeGit(object):def__init__(self):parser=argparse.ArgumentParser(description='Pretends to be git',usage='''git <command> [<args>]
The most commonly used git commands are:
commit Record changes to the repository
fetch Download objects and refs from another repository
''')parser.add_argument('command',help='Subcommand to run')# parse_args defaults to [1:] for args, but you need to# exclude the rest of the args too, or validation will failargs=parser.parse_args(sys.argv[1:2])ifnothasattr(self,args.command):print'Unrecognized command'parser.print_help()exit(1)# use dispatch pattern to invoke method with same namegetattr(self,args.command)()defcommit(self):parser=argparse.ArgumentParser(description='Record changes to the repository')# prefixing the argument with -- means it's optionalparser.add_argument('--amend',action='store_true')# now that we're inside a subcommand, ignore the first# TWO argvs, ie the command (git) and the subcommand (commit)args=parser.parse_args(sys.argv[2:])print'Running git commit, amend=%s'%args.amenddeffetch(self):parser=argparse.ArgumentParser(description='Download objects and refs from another repository')# NOT prefixing the argument with -- means it's not optionalparser.add_argument('repository')args=parser.parse_args(sys.argv[2:])print'Running git fetch, repository=%s'%args.repositoryif__name__=='__main__':FakeGit()

The argparse library gives you all kinds of great stuff. You can run ./git.py --help and get the following:

usage: git <command>[<args>]
The most commonly used git commands are:
commit Record changes to the repository
fetch Download objects and refs from another repository
Pretends to be git
positional arguments:
command Subcommand to run
optional arguments:
-h, --help show this help message and exit

You can get help on a particular subcommand with ./git.py commit --help.

usage: git.py [-h][--amend]
Record changes to the repository
optional arguments:
-h, --help show this help message and exit--amend