28

I'd like to display argparse help for my options the same way the default -h,--help and -v,--version are, without the ALLCAPS text after the option, or at least without the duplicated CAPS.

import argparse
p = argparse.ArgumentParser("a foo bar dustup")
p.add_argument('-i', '--ini', help="use alternate ini file")
print '\n', p.parse_args()

This is what I currently get with python foobar.py -h:

usage: a foo bar dustup [-h] [-i INI]

optional arguments:
  -h, --help            show this help message and exit
  -i INI, --ini INI     use alternate ini

And this is what I want:

usage: a foo bar dustup [-h] [-i INI]

optional arguments:
  -h, --help            show this help message and exit
  -i, --ini INI         use alternate ini

This would be acceptable too:

  -i, --ini             use alternate ini

I'm using python 2.7.

matt wilkie
  • 17,268
  • 24
  • 80
  • 115
  • I don't think I agree with the premise of this question. command line arguments are normally passed from a shell, and by convention, variables in shell scripts are usually all caps. I think it's apropriate to distinguish the metavars in caps from the keywords in lowercase. – SingleNegationElimination Mar 10 '12 at 02:37
  • 1
    @TokenMacGuy given that convention, I would be okay with it, except that the UP case is repeated unnecessarily (`-i INI, --ini INI`). I've updated the Q title accordingly as it's the duplication which is more vexing. – matt wilkie Mar 10 '12 at 06:19
  • @TokenMacGuy As a user you should have the flexibility of whatever help message you see fit. Personally I find the CAPS version ugly, not to mention the duplication. Even if you break the shell convention, metavars can be distinguished, e.g. `git commit -h` – Marius Retegan Jul 03 '12 at 20:36

2 Answers2

25

You could customize usage and assign metavar to an empty string:

import argparse

p = argparse.ArgumentParser("a foo bar dustup", usage='%(prog)s [-h] [-i INI]')
p.add_argument('-i', '--ini', help="use alternate ini file", metavar='')
p.print_help()

Output

usage: a foo bar dustup [-h] [-i INI]

optional arguments:
  -h, --help   show this help message and exit
  -i , --ini   use alternate ini file
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • +1 your solution takes care of the usage problem that my answer had. – John Mar 10 '12 at 01:39
  • I've accepted this one as a workable solution for my present project. Given TokenMacGuy's observation on the Q, stripping the CAPS may not be advisable to use everywhere as it breaks with convention, and makes it unclear whether an option requires a follow-on string (e.g. `--download-only` is complete while `--ini` might require a follow on path or filename). – matt wilkie Mar 11 '12 at 06:31
  • What if I have a huge list of argument. Writing a manual usage statement stating all the optional arguments that I have will make it harder to handle and write. Also in future if some of the arguments are to be deleted and some are to be added new then I think instead of manaully handling usage statement, auto generated would be nice. So is there any other way to sort this problem out of having the metachar in usage statement and not in the part where it is explained. – Rakholiya Jenish Jun 07 '15 at 17:45
  • @RakholiyaJenish: you could ask a proper separate StackOverflow question: ink to the current one with the explanation how exactly it is different -- as you did in the comment. – jfs Jun 07 '15 at 19:56
  • Thanks @J.F.Sebastian, i asked a question but didn't get any comments or answers. Would you please try looking at it. http://stackoverflow.com/questions/30704631/changing-the-metavar-value-in-argparse-only-in-argument-listing-and-not-in-its-u – Rakholiya Jenish Jun 08 '15 at 10:24
6

Well from what I can tell you have two options,

import argparse

p = argparse.ArgumentParser(description="a foo bar dustup")
p.add_argument('-i', '--ini', metavar='', help="use alternate ini file")

print '\n', p.parse_args()

or you can write a custom formatter class, I realize the first option may not be a perfect solution, as it gets rid of the CAPS in the usage line. If it's that important here is the source for argparse, from what I can tell the default formatter classes won't do exactly what you want.

Edit:

Well I went ahead and built you your own formatter class, in the same fashion as the others... not sure I'd recommend you using this in production code as there won't be any official python documentation for it =P

import argparse
from argparse import HelpFormatter

class MyFormatter(HelpFormatter):
    """
        for matt wilkie on SO
    """

    def _format_action_invocation(self, action):
        if not action.option_strings:
            default = self._get_default_metavar_for_positional(action)
            metavar, = self._metavar_formatter(action, default)(1)
            return metavar

        else:
            parts = []

            # if the Optional doesn't take a value, format is:
            #    -s, --long
            if action.nargs == 0:
                parts.extend(action.option_strings)

            # if the Optional takes a value, format is:
            #    -s ARGS, --long ARGS
            else:
                default = self._get_default_metavar_for_optional(action)
                args_string = self._format_args(action, default)
                for option_string in action.option_strings:
                    parts.append(option_string)

                return '%s %s' % (', '.join(parts), args_string)

            return ', '.join(parts)

    def _get_default_metavar_for_optional(self, action):
        return action.dest.upper()

p = argparse.ArgumentParser("a foo bar dustup", formatter_class=MyFormatter)
p.add_argument('-i', '--ini', help="use alternate ini file")
p.print_help()
John
  • 13,197
  • 7
  • 51
  • 101
  • +1 for great answer and links to source code. Did you need to override the `_get_default_metavar_for_optional` method? In the source you linked to it was the same method. Did you do it to ensure that uppercase is used even if the HelpFormatter implements something else later? – Cody Piersall Jul 02 '13 at 15:58
  • I included that method for clarity, When I read the method name `_get_default_metavar_for_optional` it doesn't exactly scream `str.upper` to me. Where as I can guess that `_format_args` probably does some string formatting. – John Jul 02 '13 at 16:08
  • How does `_get_default_metavar_for_optional` _not_ scream `str.upper`? Just kidding, of course; you have a good point. – Cody Piersall Jul 02 '13 at 17:02