Reputation: 958
very new to working with argparse and the cmd line. I've started to build a parser that allows for a front-end user to enter in data via the cmd terminal. The parser is calling the API() class that I have created (which creates the SQLALCHEMY session and etc.), example shown here:
class API(object):
def __init__(self):
# all the session / engine config here
def create_user(self, username, password, firstname, lastname, email):
new_user = User(username, password, firstname, lastname, email)
self.session.add(new_user)
self.session.commit()
print(username, firstname, lastname)
def retrieve_user(self, username, firstname, lastname):
# code here ... etc .
to implement in the CMD file here:
def main():
parser = argparse.ArgumentParser(prog='API_ArgParse', description='Create, Read, Update, and Delete (CRUD) Interface Commands')
subparsers = parser.add_subparsers(
title='subcommands', description='valid subcommands', help='additional help')
api = API() # calling the API class functions/engine
# Create command for 'user'
create_parser = subparsers.add_parser('create_user', help='create a user')
create_parser.add_argument('username', type=str, help='username of the user')
create_parser.add_argument('password', type=str, help='password')
create_parser.add_argument('firstname', type=str, help='first name')
create_parser.add_argument('lastname', type=str, help='last name')
create_parser.add_argument('email', type=str, help='email address')
#args = parser.parse_args() <--EDIT:removed from here and placed on bottom
api.create_user(args.username, args.password, args.firstname, args.lastname, args.email)
# Retrieve command for 'user'
retrieve_parser = subparsers.add_parser('retrieve_user', help='retrieve a user')
retrieve_parser.add_argument('username', type=str, help='username')
retrieve_parser.add_argument('firstname', type=str, help='first name')
retrieve_parser.add_argument('lastname', type=str, help='last name')
api.retrieve_user(args.username, args.firstname, args.lastname)
NEW EDIT/ADDITION OF args = parser.parse_args() to use both commands to reflect comments below.
args = parser.parse_args()
print(args)
if __name__ == '__main__':
main()
and so on...
My problem is that the terminal is NOT printing the help command for the new parsers (e.g. retrieve_parser, update_parser, etc.). Do I have to create a "args = parser.parse_arg()" per section? Secondly, do I create a "args = create_parser.parse_args()" in-place of just "parser.parse..." I notice they print two different things on the terminal.
Any clarification about where to place the parse_arg() method (taking into consideration the use of the API() function) is greatly appreciated!!
Upvotes: 2
Views: 2648
Reputation: 231355
Normally you call the parse_args
method after you have created the parser
(and that includes any subparsers), and before you need to use the resulting Namespace (usually called args
).
retrieve_parser.add_argument('lastname', type=str, help='last name')
args = parser.parse_args() # <=========
api.retrieve_user(args.username, args.firstname, args.lastname)
The purpose of parse_args
is to read the sys.argv
list (which the shell/interpreter created from your command line), and 'parse' it using the specficiations you created with add_argument
and so on.
The main parser
'knows' about the subparsers, and will pass the argv list to the appropriate one (as selected by names like 'retrieve_user').
If the the command line includes -h
(or --help
) the parser will display a help message and exit. This message lists the subparsers, but does not show their arguments. If -h
follows a subparser name, it's the subparser that will display the help.
python main.py -h # main help
python main.py retrieve_user -h # subparser help
parser.print_help()
can be used in your code to show that same help message. retrieve_parser.print_help()
will do the same for the subparser. Obviously these commands will only work within main
, and are of more use when debugging (not production).
There's no provision in argparse
to display the help for all subparsers. However you could construct such a function from the print_help
commands that I just described. There probably is a SO answer with such a function (but I don't know what would be good search term).
Crudely, main()
could include:
parser.add_argument('--bighelp', action='store_true', help='show help for all subparsers')
....
if args.bighelp:
parser.print_help()
subparser1.print_help()
subparser2.print_help()
....
sys.exit(1) # if want to quit
It's possible to get a list of the subparsers from the parser, but it's probably easier and clearer to maintain your own list.
I was focusing on how to get the parser
working, not on the next step of calling the api
.
You need to modify the add_subparsers
, adding a dest
parameter.
subparsers = parser.add_subparsers(dest='cmd',
title='subcommands', description='valid subcommands', help='additional help')
Then after you have define all subparsers do:
# should call cmd since I have stored `.dest` there e.g.`subparsers = parser.add_subparsers(dest='cmd'...`
args = parser.parse_args()
if args.cmd in ['create_user']: # or just == 'create_user'
api.create_user(args...)
elif args.cmd in ['retrieve_user']:
api.retrieve_user(args...)
The argparse docs shows how you can streamline this by invoking:
args.subcmdfunc(args)
See the last 2 examples in the sub-commands section: https://docs.python.org/3/library/argparse.html#sub-commands
Either way, the idea is to find out from the args
namespace which subcommand the user specified, and then calling the correct api
method.
Keep in mind that parser.parse_args()
is equivalent to parser.parse_args(sys.argv[1:])
. So whatever parser you use, whether the main one or one of subparsers, it must be prepared to handle all the strings that your user might give. It's the main parser that knows how to handle the subparser names. The subparser only has to handle the strings that follow its name. It will probably give an error if given the full argv[1:]
list. So normally you don't call parse_args
for a specific subparser.
Upvotes: 3