2

When specifying help in argparse, I often use strings like %(default)s or %(const)s in the help= argument to display default arguments. The syntax is a bit weird, though: I assume it's left over from the days where python strings were formatted with %, but since python 2.6 the standard way to format strings has been using the format() function.

So are these libraries just using the 'old' replacement syntax, or does this come from somewhere else? It's been stated that the % replacement operator will disappear at some point, will these libraries change to the '{}'.format() syntax then?

Shep
  • 7,990
  • 8
  • 49
  • 71

2 Answers2

4

Yes, the argparse and ConfigParser libraries use the old-style % string formatting syntax internally. These libraries were developed before str.format() and format() were available, or in the case of argparse the library authors aimed at compatibility with earlier Python versions.

If the % formatting ever is removed, then those libraries will indeed have to move to using string formatting using {} placeholders.

However, for various reasons, the % old-style string formatting style is here to stay for the foreseeable future; it has been 'un-deprecated'; str.format() is to be preferred but % is kept around for backwards compatibility.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 1
    It actually has never been deprecated in the first place. – Sven Marnach Aug 08 '13 at 14:20
  • 1
    Does this syntax have any precedent before python? – Shep Aug 08 '13 at 14:20
  • @SvenMarnach: There are plenty of copies of older documentation that name it as deprecated, but it was never made official. – Martijn Pieters Aug 08 '13 at 14:20
  • 2
    @Shep: Yes, it is an extension on the `printf` C function format to support dictionary keys. – Martijn Pieters Aug 08 '13 at 14:20
  • @SvenMarnach: PEP 3101 talks about 'when it comes time to deprecate the older system', which is indeed not really deprecating it. – Martijn Pieters Aug 08 '13 at 14:26
  • @SvenMarnach: The sentence `str.format()` documentation talks about preference: *This method of string formatting is the new standard in Python 3, and should be preferred to the `%` formatting described in String Formatting Operations in new code.* – Martijn Pieters Aug 08 '13 at 14:27
  • 3
    Recent `logging.formatter` objects take a `style` parameter. `%` is default, but `$` and `{` are alternatives. `argparse` might go that direction, eventually. http://docs.python.org/3.2/library/logging.html#formatter-objects – hpaulj Aug 08 '13 at 19:03
  • http://bugs.python.org/issue13280 Raymond Hettinger 2011-10-27 "There's no reason to switch the implementation. The % formatting isn't going away and we've decided against doing switch-overs in existing code (it risks introducing bugs while conferring zero benefits to users)." – hpaulj Aug 08 '13 at 22:33
1

The approved way of customizing the help formatting is to subclass HelpFormatter. A user can do this without waiting for a future Python release.

This formatter implements the {}.format in 2 places.

class NewHelpFormatter(argparse.HelpFormatter):
    # _format_usage - format usage, but only uses dict(prog=self._prog)
    def _format_text(self, text):
        # for description, epilog, version
        if '{prog}' in text:
            text = text.format(prog=self._prog) # change from %
        text_width = self._width - self._current_indent
        indent = ' ' * self._current_indent
        return self._fill_text(text, text_width, indent) + '\n\n'
    def _expand_help(self, action):
        params = dict(vars(action), prog=self._prog)
        for name in list(params):
            if params[name] is argparse.SUPPRESS:
                del params[name]
        for name in list(params):
            if hasattr(params[name], '__name__'):
                params[name] = params[name].__name__
        if params.get('choices') is not None:
            choices_str = ', '.join([str(c) for c in params['choices']])
            params['choices'] = choices_str
        return self._get_help_string(action).format(**params) # change from %

For example:

parser = argparse.ArgumentParser(prog='NewFormatter',
    formatter_class=NewHelpFormatter,
    description='{prog} description')
parser.add_argument('foo',nargs=3, default=[1,2,3],
    help='nargs:{nargs} prog:{prog!r} defaults:{default} last:{default[2]}')
parser.add_argument('--bar',choices=['yes','no'],
    help='choices: {choices!r}')
parser.print_help()

produces:

usage: NewFormatter [-h] [--bar {yes,no}] foo foo foo

NewFormatter description

positional arguments:
  foo             nargs:3 prog:'NewFormatter' defaults:[1, 2, 3] last:3

optional arguments:
  -h, --help      show this help message and exit
  --bar {yes,no}  choices: 'yes, no'
hpaulj
  • 221,503
  • 14
  • 230
  • 353