0

After looking at about a dozen questions, I can't seem to find an answer.

I have a python CLI i've written using argparse. I have a main command that does nothing but regurgitate help text and then 4 subcommands. My boss wants a very specific output for the help text. He has me write it out as a text file and then we use that text file to display the help text.

However, in some circumstances, it STILL outputs parts of the argparse help text.

For example, if I run my program with no subcommands, it just outputs our help text from the file. But if I use "-h" or "--help" it will output our help text, followed by the list of positional and optional arguments and other argparse stuff. We don't want that.

I could use "add_help=False" but we want the user to be able to type -h and still get our help text. If we set add help to false, it will display our help text followed by the error "-h not recognized".

Also doing this does nothing for when the user uses -h after a subcommand. I set help=None and usage is set to my custom help text for each subcommand, but it still shows the boilerplate argparse info at the end.

This is what I want to happen: user types in the main command with no subcommands prints my custom help text and nothing else. The user types the main command, no subcommand, followed by -h/--help and it prints my custom help text and nothing else. User types in the main command, one of the subcommands, followed by -h/--help and it outputs my help text and nothing else. User types the main command, a subcommand, and then wrong arguments or too many/ too few arguments displays my help text and nothing else. Basically I only ever want it to print nothing, or print just my help text.

how do I do that? here is my main function where the parsers and subparsers are all configured:

def main():
    # Import help text from file
    p = Path(__file__).with_name("help.txt")
    with p.open() as file:
        help_text = file.read()

    # Configure the top level Parser
    parser = argparse.ArgumentParser(prog='myprog', description='My program', usage=help_text)
    subparsers = parser.add_subparsers()

    # Create Subparsers to give subcommands
    parser_one = subparsers.add_parser('subcommandone', prog='subcommandone', usage=help_text, help=None)
    parser_one.add_argument('arg1', type=str)
    parser_one.add_argument('-o', '--option1', default='mydefault', type=str)
    parser_two= subparsers.add_parser('subcommandtwo', usage=help_text, help=None, prog='subcommandtwo')
    parser_three= subparsers.add_parser('subcommandthree', usage=help_text, help=None, prog='subcommandthree')
    parser_four= subparsers.add_parser('subcommandfour', usage=help_text, help=None, prog='subcommandfour')

    # Assign subparsers to their respective functions
    parser_one.set_defaults(func=functionone)
    parser_two.set_defaults(func=functiontwo)
    parser_three.set_defaults(func=functionthree)
    parser_four.set_defaults(func=functionfour)
    parser.set_defaults(func=base_case)

    # Parse the arguments and call appropriate functions
    args = parser.parse_args()
    if len(sys.argv) == 1:
        args.func(args, parser)
    else:
        args.func(args)

Any thoughts?

3
  • 1
    Use "add_help=False" to turn off the automatic help, and define your own '-h', using action='help' or your own custom Action class (see _HelpAction subclass for implementation ideas). You'll have to do the same for the subparsers. In some cases it may be simpler to catch the -h in sys.argv before using parse_args. Commented Mar 7, 2022 at 19:25
  • So it sounds like just catching -h and then printing my text and disabling help altogether might be a wise move, however, it doesn't catch when there's an incorrect amount of arguments. So it sounds like I do need the help function to some degree. Can you tell me wha taction='help' does? Commented Mar 7, 2022 at 19:46
  • 1
    Errors like incorrect amount of arguments go through parser.error and parser.exit. error, creates an error message that includes the standard usage You can specify usage when defining the parser (and subparsers). Commented Mar 7, 2022 at 20:06

1 Answer 1

1

You can use sys.exit() after the help text has been displayed, and before the parsing has begun, to avoid problems with "-h not recognized".

So anywhere before the line

# Parse the arguments and call appropriate functions

add

if len(sys.argv) == 1 or '-h' in sys.argv or '--help' in sys.argv:
    print(help_text)
    sys.exit(1)

In situations where that is not good enough you can subclass argparse.HelpFormatter like so

usage_help_str = 'myscript command [options]'
epilog_str = "More info can be found at https://..."

class Formatter(argparse.HelpFormatter):
    # override methods and stuff

def formatter(prog):
    return Formatter(prog)

parser = argparse.ArgumentParser(formatter_class=formatter, epilog=epilog_str, usage=usage_help_str, add_help=False)

I tried looking around for documentation on subclassing the helpFormatter, but I couldn't find anything. It looks like people are just looking at the source code to figure out how to subclass it.

Sign up to request clarification or add additional context in comments.

1 Comment

That seems a sufficient workaround and I'll probably end up using it. But is there really no way just to tell help to shut up? Like, I know the option to completely disable it is there, but then we don't get the usage text like i want. Maybe... maybe if i disabled help entirely and then made my own optional parameter and name it help/h. Hmm. Anyway thank you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.