5

It appears to me that there's no easy way to use the RawDescriptionHelpFormatter in the argparse module without either violating PEP8 or cluttering your namespace.

Here is the most obvious way to format it:

parser = argparse.ArgumentParser(prog='PROG',
                                 ....
                                 formatter_class=argparse.RawDescriptionHelpFormatter)

This violates the stipulation that lines should not exceed 80 characters

Here's how the example in the argparse documentation looks (spoiler: this is actually correct; see comments below):

parser = argparse.ArgumentParser(
    prog='PROG',
    formatter_class=argparse.RawDescriptionHelpFormatter,
    ....

This violates PEP8 E128 regarding the indentation of continuation lines.

Here'another possibility:

parser = argparse.ArgumentParser(
    prog='PROG',
    formatter_class=
    argparse.RawDescriptionHelpFormatter,
    ....

This violates PEP8 E251 regarding spaces around = for keyward arguments.

(Of course, this doesn't even address the fact that my character-count for the line assumes that the parser token starts on the first column, which is the best case scenario; what if we want to create a parser inside a class and/or a function?)

So the only remaining alternative, as far as I can tell, is to either clutter the namespace:

from argparse import RawDescriptionHelpFormatter, ArgumentParser

...or use a silly temporary variable (which also clutters the namespace):

rawformatter = argparse.RawDescriptionHelpFormatter
parser = argparse.ArgumentParser(prog='PROG',
                                 ....
                                 formatter_class=rawformatter)

Am I missing something? I guess having RawDescriptionHelpFormatter and ArgumentParser directly in the current namespace isn't a big deal, but this seems like an unnecessary frustration.

Kyle Strand
  • 15,941
  • 8
  • 72
  • 167
  • 3
    How does the `argparse` example violate E128? If you put any arguments on the first line, the subsequent arguments have to be indented to match; if you don't, they have to be indented one step in. The latter is exactly what the `argparse` example does. It's identical to the "# Hanging indents should add a level" example in [PEP 8 itself](http://legacy.python.org/dev/peps/pep-0008/#indentation). The `pep8` checker, and the other two linters I have lying around, both agree. So, what makes you think it's bad? – abarnert Aug 29 '14 at 01:02
  • @abarnert Ah. It doesn't. In my actual example file on which I was running a PEP8 checker, I had arguments on the first line. Stupid mistake, but I'm glad I asked here. – Kyle Strand Aug 29 '14 at 01:08
  • I think this question should be closed, but I gave the wrong close reason. This is a "can no longer be reproduced or was a simple typo" case, not an "unclear what you're asking" question. It _is_ clear, it's just not asking about the right code, and if it were, you would have already known the answer… – abarnert Aug 29 '14 at 01:49

2 Answers2

3

Your second example looks fine to me, and seems to match the "# Hanging indents should add a level." example here: http://legacy.python.org/dev/peps/pep-0008/#indentation

Also seems to tally with this similar question/answer: What is PEP8's E128: continuation line under-indented for visual indent?

Community
  • 1
  • 1
Tom Dalton
  • 6,122
  • 24
  • 35
1

A couple of other variations:

from argparse import RawDescriptionHelpFormatter as formatter

parser = argparse.ArgumentFormatter(prog='PROG')
# you can reassign a parser attribute after initialization
parser.formatter_class = formatter 

But there are other inputs to ArgumentParser that may be long enough to require wrapping or assignment to separate variables.

usage = 'PROG [-h] --foo FOO BAR etc'
description = """\
This is a long multiline description
that may require dedenting.
"""
description = textwrap.dedent(description)
parser=Argparse(usage=usage, description=description, formatter_class=formatter)

Take a look at test_argparse.py to see the many ways that a long and multifaceted parser can be defined.


http://bugs.python.org/issue13023 raises the issue of what if you wanted several formatter modifications, e.g.:

This means we can either pass argparse.RawDescriptionHelpFormatter or argparse.ArgumentDefaultsHelpFormatter, but not both.

The recommended solution is to subclass the formatter:

class MyFormatter(argparse.RawDescriptionHelpFormatter, 
    argparse.ArgumentDefaultsHelpformatter):
    pass

Another tactic to keep the namespace clean is to wrap the parser definition in a function or module.

http://ipython.org/ipython-doc/2/api/generated/IPython.core.magic_arguments.html

is an example of how IPython wraps argparse to make new API for its users.

Another parser built on argparse, plac first builds a cfg dictionary:

https://code.google.com/p/plac/source/browse/plac_core.py

def pconf(obj):
    ...
    cfg = dict(description=obj.__doc__, 
               formatter_class=argparse.RawDescriptionHelpFormatter)
    ...
    return cfg

def parser_from(obj, **confparams):
    ...
    conf = pconf(obj).copy()
    conf.update(confparams)
    parser = ArgumentParser(**conf)
hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • Your second code block has a >=80-char line, and doesn't demonstrate wrapping, and you've also got a string with broken continuations that will raise a `SyntaxError` (and that should have been written as a triple-quoted string), plus at least one other exception (a `NameError`). But, most importantly, I can't figure out what it's supposed to be showing. – abarnert Aug 29 '14 at 01:06
  • @abarnert I think hpaulj's point is that it's frequently a good idea to assign `usage` and `description` to separate variables, which is true. In any case, +1 for pointing out that the `formatter_class` can be assigned after initialization. – Kyle Strand Aug 29 '14 at 01:11
  • Opps, I meant to use triple quotes. – hpaulj Aug 29 '14 at 02:03
  • I added a few more examples of complicated `ArgumentParser` definitions. – hpaulj Aug 29 '14 at 02:30
  • Dang. You've got the seed of a decent `argparse` tutorial here. You should write one up and post it somewhere. – Kyle Strand Sep 01 '14 at 18:55