web-dev-qa-db-fra.com

Python argparse: Comment insérer une nouvelle ligne dans le texte d'aide?

J'utilise argparse dans Python 2.7 pour analyser les options d'entrée. Une de mes options est un choix multiple. Je veux faire une liste dans son texte d'aide, par exemple.

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()

Cependant, argparse supprime toutes les nouvelles lignes et les espaces consécutifs. Le résultat ressemble à

 ~/Téléchargements: 52 $ python2.7 x.py -h 
 Utilisation: x.py [-h] [-g {a, b, g, d, e}]. ____.] 
 test 
 
 arguments optionnels: 
 -h, --help - aide à afficher ce message d'aide et à quitter 
 -g {a, b , g, d, e} Une option, où a = alpha b = bêta g = gamma d = delta e 
 = epsilon 

Comment insérer des nouvelles lignes dans le texte d'aide?

301
kennytm

Essayez d’utiliser RawTextHelpFormatter :

from argparse import RawTextHelpFormatter
parser = ArgumentParser(description='test', formatter_class=RawTextHelpFormatter)
344

Si vous souhaitez simplement remplacer cette option, vous ne devez pas utiliser RawTextHelpFormatter. Sous-classe plutôt la HelpFormatter et fournissez une introduction spéciale pour les options qui doivent être gérées "brutes" (j'utilise "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)

Et utilisez-le:

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()

Tous les autres appels à .add_argument() où l'aide ne commence pas par R| seront traités normalement.

Cela fait partie de mes améliorations sur argparse . SmartFormatter complet prend également en charge l’ajout des valeurs par défaut à toutes les options, ainsi que la saisie brute de la description des utilitaires. La version complète a sa propre méthode _split_lines, de sorte que toute mise en forme effectuée, par exemple. les chaînes de version sont conservées:

parser.add_argument('--version', '-v', action="version",
                    version="version...\n   42!")
68
Anthon

Un autre moyen facile de le faire est d’inclure textwrap.

Par exemple,

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 cette manière, nous pouvons éviter le long espace vide devant chaque ligne de sortie.

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 ...
28
Wang Zong'an

J'ai rencontré un problème similaire (Python 2.7.6). J'ai essayé de décomposer la description de la section en plusieurs lignes à l'aide de RawTextHelpFormatter:

parser = ArgumentParser(description="""First paragraph 

                                       Second paragraph

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

options = parser.parse_args()

Et j'ai:

 usage: play-with-argparse.py [OPTIONS] 
 
 Premier paragraphe 
 
 Deuxième paragraphe 
 
 Troisième paragraphe 
 
 Arguments optionnels: 
 -H, --help montrer ce message d’aide et quitter 

Donc, RawTextHelpFormatter n'est pas une solution. Parce qu'il affiche la description telle qu'elle apparaît dans le code source, en préservant tous les caractères d'espacement (je souhaite conserver des onglets supplémentaires dans mon code source pour des raisons de lisibilité, mais je ne souhaite pas les imprimer tous. De plus, le programme de formatage brut n'enroule pas la ligne quand trop long, plus de 80 caractères par exemple).

Merci à @Anton qui a inspiré la bonne direction ci-dessus . Mais cette solution nécessite une légère modification afin de formater la section de description .

Quoi qu'il en soit, un formateur personnalisé est nécessaire. J'ai étendu la méthode HelpFormatter existante et écrasé la méthode _fill_text comme ceci:

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

Comparez avec le code source original provenant de argparse module:

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)

Dans le code d'origine, toute la description est encapsulée. Dans le formateur personnalisé ci-dessus, tout le texte est divisé en plusieurs morceaux, chacun étant formaté indépendamment.

Donc, avec l'aide d'un formateur personnalisé:

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

options = parser.parse_args()

la sortie est:

 usage: play-with-argparse.py [OPTIONS] 
 
 Premier paragraphe 
 
 Deuxième paragraphe 
 
 Troisième paragraphe 
 
 Arguments optionnels: 
 -H, --help montrer ce message d’aide et quitter 
11
flaz14

Je voulais avoir à la fois des sauts de ligne manuels dans le texte de description et un retour automatique à la ligne; mais aucune des suggestions ici ne fonctionnait pour moi - j'ai donc fini par modifier la classe SmartFormatter donnée dans les réponses ici; les problèmes avec les noms de méthode argparse n'étant pas une API publique nonobstant, voici ce que j'ai (en tant que fichier appelé 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()

Voici comment cela fonctionne dans 2.7 et 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
2
sdbbs

À partir de SmartFomatter décrit ci-dessus, j'ai abouti à cette solution:

class SmartFormatter(argparse.HelpFormatter):
    '''
         Custom Help Formatter used to split help text when '\n' was 
         inserted in it.
    '''

    def _split_lines(self, text, width):
        r = []
        for t in text.splitlines(): r.extend(argparse.HelpFormatter._split_lines(self, t, width))
        return r

Notez étrangement que l'argument formatter_class transmis à l'analyseur de niveau supérieur n'est pas hérité par les sous_parsers. Vous devez le transmettre à nouveau pour chaque sous_parser créé.

0
ermitz