0

I've added some args to a script with argparse which function fine. Now I'm trying to format the --help output. I've added metavar='' to each one which has produced a much cleaner output, however there are spaces after the single flags making the text rag oddly.

Problems

Flag will display as -m , --model instead of -m, --model

Flags with type=bool with const and nargs display as -x [], --xip [], having the extra space and [] added.

Not finding much info on how to clean this up. Did find discussions on python.org that the extra space is a known problem and using metavar='' is not ideal.

example code:

import argparse
import colorama
from colorama import init, Fore, Style
init(autoreset=True)

parser = argparse.ArgumentParser(description=Fore.RED + 'Some descriptive Text and such' + Fore.WHITE, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
add_arg = parser.add_argument
add_arg('-m',   '--model',  type=str, default='model_name',                     help="some help text", metavar='')
add_arg('-d',   '--derp',   type=str, default='burp',                           help="some more help text", metavar='')
add_arg('-x',   '--xip',    type=bool, default=False, const=True, nargs='?',    help="some other help text", metavar='')
args = parser.parse_args()

running python script.py -h produces:

usage: script.py [-h] [-m] [-d] [-x ]

Some descriptive Text and such # <-- this line displays as RED

optional arguments:
  -h, --help           show this help message and exit
  -m , --model         some help text (default: model_name)
  -d , --derp          some more help text (default: burp)
  -x [], --xip []      some other help text (default: False)

changing metavar to metavar='\b' produces this:

usage: script.py [-h] [-m] [-d] [-x ]] # <- extra bracket ]

Some descriptive Text and such

optional arguments:
  -h, --help         show this help message and exit
  -m, --model    some help text (default: model_name)   # indent broken
  -d, --derp     some more help text (default: burp)    # indent broken
  -x ], --xip ]  some other help text (default: False)  # indent broken

Coloring Output

I'd also like to know how to properly color the --help output with colorama. Coloring the description is easy enough, but trying to add coloring to the flags and such produced expected errors. Adding color to help worked if added before, like help=Fore.YELLOW + 'some help text', but it colors everything after it, and can't add anymroe Fore after it without errors. Adding it anywhere else produces an error.

Is there a way to define how to color flags and help text, maybe outside of where they are being set?

Besides that, are there any packages for argparse formatting? I found some older ones that didn't work quite right but nothing new.

liquidRock
  • 327
  • 2
  • 12
  • Try `metavar='\b'` to remove the space... not really a fan of spending time formatting `argparse` help. – Bakuriu Nov 15 '21 at 20:34
  • @Bakuriu This removed the space, but it also broke the indentation on the help text (like a tab was deleted before the text). However, for the args with `const` and `nargs` it left the space and took out the left bracket, also broke the help text alignment. I'll edit my post to show what happens. – liquidRock Nov 15 '21 at 20:49
  • You could subclass the HelpFormatter, and modify the relevant method. There's nothing you can do with existing parameters to make this display 'cleaner'. – hpaulj Nov 15 '21 at 21:34
  • Don't use `type=bool`. The only string that yields `False` is `bool('')`, which your user cannot provide. – hpaulj Nov 15 '21 at 21:37

1 Answers1

2

Well, I managed to figure it out after finding some old posts on SO.

The code from This Post sets up an add_argument_group. You then add your args and hide the help text by setting help=argparse.SUPPRESS.

The actual text that is displayed in --help is the title and description of the group. This makes it very easy because you're just concatenating strings at that point and can add in your colorama styling easily with + where needed.

The code from the post:

parser = argparse.ArgumentParser(description='Postfix Queue Administration Tool',
        prog='pqa',
        usage='%(prog)s [-h] [-v,--version]',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        )
parser.add_argument('-l', '--list', action='store_true',
        help='Shows full overview of all queues')
g = parser.add_argument_group(title='information options',
        description='''-q, --queue <queue>     Show information for <queue>
-d, --domain <domain>   Show information about a specific <domain>''')
g.add_argument('-q', '--queue', action='store', metavar='', dest='queue',
        help=argparse.SUPPRESS)
g.add_argument('-d', '--domain', action='store', metavar='<domain>', dest='domain',
        help=argparse.SUPPRESS)
parser.add_argument('-v', '--version', action='version', version='%(prog)s 0.1')
parser.print_help()

My modified example code based on that post:

import argparse
from colorama import init, Fore, Style
init(autoreset=True)

parser = argparse.ArgumentParser(
    description=Fore.LIGHTBLACK_EX + 'Some descriptive Text and such' + Fore.WHITE,
    prog='script.py',
    usage=Fore.WHITE + '%(prog)s [-m] [-d] [-x]',
    formatter_class=argparse.RawDescriptionHelpFormatter,
    )
g = parser.add_argument_group(title=Fore.LIGHTBLACK_EX + 'args',
        description=Fore.RED + '''
-m   --model        ''' + Fore.WHITE + Style.DIM + '''some help text       || default: model_name''' + Fore.RED + Style.NORMAL + '''
-d   --derp         ''' + Fore.WHITE + Style.DIM + '''some more help text  || default: burp''' + Fore.RED + Style.NORMAL + '''
-x   --xip          ''' + Fore.WHITE + Style.DIM + '''some other help text || default: False''' + Fore.RED + Style.NORMAL + '''\n\n''')
g.add_argument('-m',   '--model',   type=str, default='model_name',                      help=argparse.SUPPRESS, metavar='')
g.add_argument('-d',   '--derp',    type=str, default='burp',                            help=argparse.SUPPRESS, metavar='')
g.add_argument('-x',   '--xip',     type=str2bool, default=False, const=True, nargs='?', help=argparse.SUPPRESS, metavar='')

args = parser.parse_args()

The output:

usage: script.py [-m] [-d] [-x]

Some descriptive Text and such

optional arguments:
  -h, --help  show this help message and exit

args:
  
  -m   --model        some help text       || default: model_name
  -d   --derp         some more help text  || default: burp
  -x   --xip          some other help text || default: False

Attached image of what the output looks like in Terminal: enter image description here

Lastly, as per @hpaulj 's advice, I found this function so I can change the type from bool and make sure it always resolves correctly.

def str2bool(v):
    if isinstance(v, bool):
        return v
    if v.lower() in ('yes', 'true', 't', 'y', '1'):
        return True
    elif v.lower() in ('no', 'false', 'f', 'n', '0'):
        return False
    else:
        raise argparse.ArgumentTypeError('Boolean value expected.')
liquidRock
  • 327
  • 2
  • 12