Search code examples
pythonargparse

Python argparse: Is there a way to print help for only a specific parameter?


I have a long list of parameters, so the output from mycommand --help is getting very big. I would like to provide my users a way to get the help text for only a specific parameter.

Something like this (doesn't work, shows the whole help text)

mycommand --help --parameter-of-interest

I don't want to split everything into subparsers if at all avoidable.


Solution

  • You can create your own actions to achieve this. Both of these will iterate the optional arguments and suppress any that are not found in sys.argv. I'd recommend the explain action as this doesn't mess with the -h/--help flag.

    Explain Action

    This creates an action ExplainParamsAction with the corresponding -e/--explain options that filters the help text for just specified parameters.

    import sys
    import argparse
    
    class ExplainParamsAction(argparse.Action):
        def __init__(
            self,
            option_strings,
            dest=argparse.SUPPRESS,
            default=argparse.SUPPRESS,
            **kwargs
        ):
            super().__init__(option_strings, dest, default=default, nargs=0, **kwargs)
    
        def __call__(self, parser, namespace, values, option_string=None):
            opts = parser._option_string_actions
            for arg in opts:
                if arg not in sys.argv:
                    setattr(opts[arg], "help", argparse.SUPPRESS)
            parser.print_help()
            parser.exit()
    
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-e",
        "--explain",
        action=ExplainParamsAction,
        help="Show help message for only specified parameters and exit",
    )
    parser.add_argument("--url", help="URL to the resource")
    parser.add_argument("--port", help="Port to the resource")
    parser.add_argument("--timeout", help="Connection timeout")
    args = parser.parse_args()
    

    Override the Help Action

    Alternatively you can override the help action that you supply to your parser. To use with an argparse.ArgumentParser you need to turn off the default helper and provide your own.

    import sys
    import argparse
    
    class _CustomHelpAction(argparse._HelpAction):
        def __call__(self, parser, namespace, values, option_string=None):
            args = sys.argv[1:]
            opts = parser._option_string_actions
            # Check is needed for just -h/--help to work
            if len(args) > 1:
                for arg in opts:
                    if arg not in args:
                        setattr(opts[arg], "help", argparse.SUPPRESS)
            super().__call__(parser, namespace, values, option_string)
    
    
    # Init parser with help turned off
    parser = argparse.ArgumentParser(add_help=False)
    
    # Register your help action and manually add the `-h/--help` option
    parser.register("action", "help", _CustomHelpAction)
    parser.add_argument("-h", "--help", action="help", help="show this help message and exit")
    
    # Add remaining arguments
    parser.add_argument("--url", help="URL to the resource")
    parser.add_argument("--port", help="Port to the resource")
    parser.add_argument("--timeout", help="Connection timeout")
    args = parser.parse_args()
    

    Example usage:

    All help:

    python3 script.py --help
    usage: script.py [-h] [--url URL] [--port PORT] [--timeout TIMEOUT]
    
    optional arguments:
      -h, --help
      --url URL          URL to the resource
      --port PORT        Port to the resource
      --timeout TIMEOUT  Connection timeout
    

    Specific parameters:

    ~ python3 script.py -h --url --timeout
    usage: script.py [--url URL] [--timeout TIMEOUT]
    
    optional arguments:
      --url URL          URL to the resource
      --timeout TIMEOUT  Connection timeout
    
    ~ python3 script.py -h --timeout --port
    usage: script.py [--timeout TIMEOUT] [--port PORT]
    
    optional arguments:
      --port PORT        Port to the resource
      --timeout TIMEOUT  Connection timeout
    

    This naively assumes that you are only using sys.argv, I'm not really sure what would need to be done if it weren't.