0

There are similar solutions here, but they either deal with much older versions of python, or deal only with parsers but not subparsers. I am writing a program with a simple command line interface. I would like the script to have subcommands. The end result would look something like this:

$ myprogram subcommand1 argument1 

or:

$ myprogram subcommand 2 

etc.

It appears the way to do this is with subparsing. I've read the python3 documentation on subparsing and modeled my script accordingly but am getting errors. It doesn't seem to like that some of my subcommands have arguments and other ones don't. Here is what I have tried:

import argparse

def main():
    parser = argparse.ArgumentParser('Sumarian Translator')
    subparsers = parser.add_subparsers()
    parser_translate = subparsers.add_parser('translate', help='Start Translation from file')
    parser_transfer.add_argument('file_to_translate', type=str, help='Name of the file')
    parser_login = subparsers.add_parser('login', help='Log in to the program')
    parser_userinfo = subparsers.add_parser('userinfo', help='Displays user info')
    parse_translate.set_defaults(func=translate)
    parser_login.set_defaults(func=login)
    parser_userinfo.set_defaults(func=userinfo)
    args = parser.parse_args()
    args.func(args)

def translate(args):
    translate_file = args.file_to_translate
    print("File Translated")

def login(): 
    print("Logged in")

def userinfo():
    print("User info displayed")

if __name__ == '__main__':
    main()

The line giving the trouble is the "args.func(args)" line. If I include args in the parenthesis, the functions that take no arguments won't work. And if I don't include args, obviously the function that accepts a single argument doesn't work.

The individual error when I call login while args.fun has 'args' in the parenthesis is:

TypeError: login() takes 0 positional arguments but 1 was given

And if I remove args and try to call translate, I get: TypeError: transfer() missing 1 required positional argument: 'args'

Lastly, if I include no subcommands like this: $ main.py

I get: AttributeError: 'Namespace' object has no attribute 'func' When ideally I want it to display usage like with --help

Any insights would be helpful. Again, there is lots of documentation on argparse by itself, but I have been experiencing great difficulty finding something that uses subparsers like I am doing. If there's a better way to do subcommands I'm all ears.

Derek1st
  • 63
  • 6
  • You can still define `def login(args)` (even if you don't use `args`). `argparse` does not automatically give a help if you don't provide values. Use '-h' as documented if you want help. During debugging it's a good idea to include a `print(args)`, so you see what is actually happening. Without a subcommand string, `func` is not set, so `args.func` can't be used. – hpaulj Jan 20 '22 at 16:46
  • n case it isn't obvious, `func` is only created when a `set_defaults(func=login)` like line is run. In other words when you actually specify a subcommand. Your problems are not cause by argparse or the version. You just aren't paying enough attention to what is in `args` in the different cases. – hpaulj Jan 20 '22 at 17:14
  • Thank you, that did fix the biggest issue with the arguments. I was careless with what was being passed. good catch. however, I still get an error if there is no sub-argument (because like you said, func=logic etc isnt created until the subcomand is created). So what would be a workaround then for this? how do I make -h the default behavior – Derek1st Jan 20 '22 at 19:00

0 Answers0