Python argparse: ¿Cómo insertar una nueva línea en el texto de ayuda?


Estoy usando argparse en Python 2.7 para analizar las opciones de entrada. Una de mis opciones es una opción múltiple. Quiero hacer una lista en su texto de ayuda, por ejemplo

from argparse import ArgumentParser

parser = ArgumentParser(description='test')

parser.add_argument('-g', choices=['a', 'b', 'g', 'd', 'e'], default='a',
    help="Some option, where\n"
         " a = alpha\n"
         " b = beta\n"
         " g = gamma\n"
         " d = delta\n"
         " e = epsilon")

parser.parse_args()

Sin embargo, argparse elimina todas las líneas nuevas y los espacios consecutivos. El resultado parece

~/Downloads:52$ python2.7 x.py -h
usage: x.py [-h] [-g {a,b,g,d,e}]

test

optional arguments:
  -h, --help      show this help message and exit
  -g {a,b,g,d,e}  Some option, where a = alpha b = beta g = gamma d = delta e
                  = epsilon

¿Cómo insertar nuevas líneas en el texto de ayuda?

Author: Anthon, 2010-10-04

5 answers

Intente usar RawTextHelpFormatter:

from argparse import RawTextHelpFormatter
parser = ArgumentParser(description='test', formatter_class=RawTextHelpFormatter)
 299
Author: Michał Kwiatkowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-23 19:23:51

Si solo desea anular la opción one, no debe usar RawTextHelpFormatter. En su lugar, subclase el HelpFormatter y proporcione una introducción especial para las opciones que deben manejarse " raw " (uso "R|rest of help"):

import argparse

class SmartFormatter(argparse.HelpFormatter):

    def _split_lines(self, text, width):
        if text.startswith('R|'):
            return text[2:].splitlines()  
        # this is the RawTextHelpFormatter._split_lines
        return argparse.HelpFormatter._split_lines(self, text, width)

Y úsalo:

from argparse import ArgumentParser

parser = ArgumentParser(description='test', formatter_class=SmartFormatter)

parser.add_argument('-g', choices=['a', 'b', 'g', 'd', 'e'], default='a',
    help="R|Some option, where\n"
         " a = alpha\n"
         " b = beta\n"
         " g = gamma\n"
         " d = delta\n"
         " e = epsilon")

parser.parse_args()

Cualquier otra llamada a .add_argument() donde la ayuda no comience con R| se empaquetará de forma normal.

Esto es parte de mis mejoras en argparse. El SmartFormatter completo también admite la adición el valor predeterminado es todas las opciones, y la entrada sin procesar de la descripción de utilidades. La versión completa tiene su propio método _split_lines, por lo que cualquier formato realizado para, por ejemplo, cadenas de versión se conserva:

parser.add_argument('--version', '-v', action="version",
                    version="version...\n   42!")
 58
Author: Anthon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-26 21:00:44

Otra manera fácil de hacerlo es incluir textwrap.

Por ejemplo,

import argparse, textwrap
parser = argparse.ArgumentParser(description='some information',
        usage='use "python %(prog)s --help" for more information',
        formatter_class=argparse.RawTextHelpFormatter)

parser.add_argument('--argument', default=somedefault, type=sometype,
        help= textwrap.dedent('''\
        First line
        Second line
        More lines ... '''))

De esta manera, podemos evitar el largo espacio vacío delante de cada línea de salida.

usage: use "python your_python_program.py --help" for more information

Prepare input file

optional arguments:
-h, --help            show this help message and exit
--argument ARGUMENT
                      First line
                      Second line
                      More lines ...
 24
Author: Wang Zong'an,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-20 20:39:15

Me he enfrentado a un problema similar (Python 2.7.6). He intentado descomponer descripción sección en varias líneas usando RawTextHelpFormatter:

parser = ArgumentParser(description="""First paragraph 

                                       Second paragraph

                                       Third paragraph""",  
                                       usage='%(prog)s [OPTIONS]', 
                                       formatter_class=RawTextHelpFormatter)

options = parser.parse_args()

Y consiguió:

usage: play-with-argparse.py [OPTIONS]

First paragraph 

                        Second paragraph

                        Third paragraph

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

Así que RawTextHelpFormatter no es una solución. Porque imprime la descripción tal como aparece en el código fuente, conservando todos los caracteres de espacio en blanco (quiero mantener pestañas adicionales en mi código fuente para facilitar la lectura, pero no quiero imprimirlos todos. También el formateador raw no envuelve la línea cuando es demasiado larga, más de 80 caracteres para ejemplo).

Gracias a @Anton quien inspiró la dirección correcta arriba. Pero esa solución necesita una ligera modificación con el fin de formatear descripción sección.

De todos modos, se necesita un formateador personalizado. Extendí la clase HelpFormatter existente y anulé el método _fill_text de esta manera:

import textwrap as _textwrap
class MultilineFormatter(argparse.HelpFormatter):
    def _fill_text(self, text, width, indent):
        text = self._whitespace_matcher.sub(' ', text).strip()
        paragraphs = text.split('|n ')
        multiline_text = ''
        for paragraph in paragraphs:
            formatted_paragraph = _textwrap.fill(paragraph, width, initial_indent=indent, subsequent_indent=indent) + '\n\n'
            multiline_text = multiline_text + formatted_paragraph
        return multiline_text

Comparar con el código fuente original procedente de argparse módulo:

def _fill_text(self, text, width, indent):
    text = self._whitespace_matcher.sub(' ', text).strip()
    return _textwrap.fill(text, width, initial_indent=indent,
                                       subsequent_indent=indent)

En el código original la descripción completa está siendo empaquetada. En la costumbre formateador por encima de todo el texto se divide en varios trozos, y cada uno de ellos se formatea de forma independiente.

Así que con la ayuda de formateador personalizado:

parser = ArgumentParser(description= """First paragraph 
                                        |n                              
                                        Second paragraph
                                        |n
                                        Third paragraph""",  
                usage='%(prog)s [OPTIONS]',
                formatter_class=MultilineFormatter)

options = parser.parse_args()

La salida es:

usage: play-with-argparse.py [OPTIONS]

First paragraph

Second paragraph

Third paragraph

optional arguments:
  -h, --help  show this help message and exit
 9
Author: flaz14,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:48

Quería tener tanto saltos de línea manuales en el texto de la descripción, y el ajuste automático de la misma; pero ninguna de las sugerencias aquí funcionó para mí - así que terminé modificando la clase SmartFormatter dada en las respuestas aquí; los problemas con los nombres de los métodos argparse no siendo una API pública, test.py):

import argparse
from argparse import RawDescriptionHelpFormatter

# call with: python test.py -h

class SmartDescriptionFormatter(argparse.RawDescriptionHelpFormatter):
  #def _split_lines(self, text, width): # RawTextHelpFormatter, although function name might change depending on Python
  def _fill_text(self, text, width, indent): # RawDescriptionHelpFormatter, although function name might change depending on Python
    #print("splot",text)
    if text.startswith('R|'):
      paragraphs = text[2:].splitlines()
      rebroken = [argparse._textwrap.wrap(tpar, width) for tpar in paragraphs]
      #print(rebroken)
      rebrokenstr = []
      for tlinearr in rebroken:
        if (len(tlinearr) == 0):
          rebrokenstr.append("")
        else:
          for tlinepiece in tlinearr:
            rebrokenstr.append(tlinepiece)
      #print(rebrokenstr)
      return '\n'.join(rebrokenstr) #(argparse._textwrap.wrap(text[2:], width))
    # this is the RawTextHelpFormatter._split_lines
    #return argparse.HelpFormatter._split_lines(self, text, width)
    return argparse.RawDescriptionHelpFormatter._fill_text(self, text, width, indent)

parser = argparse.ArgumentParser(formatter_class=SmartDescriptionFormatter, description="""R|Blahbla bla blah blahh/blahbla (bla blah-blabla) a blahblah bl a blaha-blah .blah blah

Blah blah bla blahblah, bla blahblah blah blah bl blblah bl blahb; blah bl blah bl bl a blah, bla blahb bl:

  blah blahblah blah bl blah blahblah""")

options = parser.parse_args()

Así es como funciona en 2.7 y 3.4:

$ python test.py -h
usage: test.py [-h]

Blahbla bla blah blahh/blahbla (bla blah-blabla) a blahblah bl a blaha-blah
.blah blah

Blah blah bla blahblah, bla blahblah blah blah bl blblah bl blahb; blah bl
blah bl bl a blah, bla blahb bl:

  blah blahblah blah bl blah blahblah

optional arguments:
  -h, --help  show this help message and exit
 0
Author: sdbbs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-31 11:01:04