Argparse: moyen d'inclure les valeurs par défaut dans '--help'?

307

Supposons que j'aie l'extrait d'argparse suivant:

diags.cmdln_parser.add_argument( '--scan-time',
                     action  = 'store',
                     nargs   = '?',
                     type    = int,
                     default = 5,
                     help    = "Wait SCAN-TIME seconds between status checks.")

Actuellement, --helprenvoie:

usage: connection_check.py [-h]
                             [--version] [--scan-time [SCAN_TIME]]

          Test the reliability/uptime of a connection.



optional arguments:
-h, --help            show this help message and exit
--version             show program's version number and exit
--scan-time [SCAN_TIME]
                    Wait SCAN-TIME seconds between status checks.

Je préférerais quelque chose comme:

--scan-time [SCAN_TIME]
                    Wait SCAN-TIME seconds between status checks.
                    (Default = 5)

Jetant un coup d'œil au code du formateur d'aide a révélé des options limitées. Existe-t-il un moyen intelligent argparsed'imprimer la valeur par défaut d' --scan-timeune manière similaire, ou dois-je simplement sous- helpclasser le formateur?

JS.
la source
5
Vous pouvez être intéressé par docopt . Je n'ai plus jamais revu argparse.
Paulo Scardine
14
@PauloScardine - Être intégré à la langue est un avantage majeur pour argparse.
jordanm
1
@PauloScardine: Tirer une bibliothèque non standard dans mon projet actuel sera en effet une douleur, mais j'aime bien l'aspect de la sortie de docopt. Merci pour le conseil!
JS.
@JS. vous dites "Tirer une bibliothèque non standard dans mon projet actuel sera en effet une douleur" Vraiment? Il existe de nombreuses bibliothèques très utiles sur pypi. Dans mon contexte, il est facile d'extraire une bibliothèque non standard. C'est triste, si c'est difficile dans votre contexte.
guettli
3
@guettli: Ce projet était destiné à un projet commercial intégré. Vous avez raison, l'installation a été facile. Obtenir l'approbation de l'entreprise juridique était un cauchemar.
JS.

Réponses:

447

Utilisez le argparse.ArgumentDefaultsHelpFormatterformateur :

parser = argparse.ArgumentParser(
    # ... other options ...
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)

Pour citer la documentation:

L'autre classe de formateur disponible, ArgumentDefaultsHelpFormatterajoutera des informations sur la valeur par défaut de chacun des arguments.

Notez que cela s'applique uniquement aux arguments dont le texte d'aide est défini ; sans helpvaleur pour un argument, il n'y a pas de message d'aide pour ajouter des informations sur la valeur par défaut à .

La sortie exacte de votre option de temps de numérisation devient alors:

  --scan-time [SCAN_TIME]
                        Wait SCAN-TIME seconds between status checks.
                        (default: 5)
Martijn Pieters
la source
12
Puis-je contrôler que seuls les arguments avec un explicite default=affichent la valeur par défaut? Puisque je n'aime pas les textes «par défaut: Aucun».
ziyuang
14
Vous pouvez définir le defaultà SUPPRESS: default=argparse.SUPPRESS. Notez que dans ce cas, aucun attribut ne sera ajouté au résultat de l'espace de noms si cet argument a été omis, consultez la defaultdocumentation .
Martijn Pieters
4
Notez que vous devez également le spécifier pour chaque sous-analyseur créé.
KomodoDave
1
Créez ensuite une nouvelle question, y compris un exemple reproductible minimal qui illustre le problème. Comme je l'ai dit, cela fonctionne pour moi avec Python 2.7.
Martijn Pieters
3
@ David J'avais le même problème. Ajoutez l' helpargument add_argumentet cela devrait fonctionner.
Pablo Díaz Ogni
190

Ajoutez '%(default)s'au paramètre d'aide pour contrôler ce qui est affiché.

parser.add_argument("--type", default="toto", choices=["toto","titi"],
                              help = "type (default: %(default)s)")
polux.moon
la source
9
J'aime cette option car j'avais déjà utilisé le format_class = argparse.RawTestHelpFormatter et je n'avais pas envie de péter avec la POO.
mqsoh
23
N'oubliez pas d'inclure la variable 'type' dans votre chaîne de formatage - par exemple '% (par défaut) s' pour une chaîne, ou '% (par défaut) d' pour un chiffre.
strongMA
1
J'aime beaucoup mieux cette solution, elle est beaucoup plus simple et je n'ai pas à gérer explicitement des arguments sans valeurs par défaut.
void.pointer
L'héritage multiple @mqsoh vient de fonctionner, mais n'est malheureusement pas une API publique: stackoverflow.com/a/52025430/895245
Ciro Santilli i 冠状 病 六四 事件 法轮功
1
J'aime ça parce que changer la classe du formateur ajoute un tas de "(par défaut: aucun)" partout qui encombre l'aide.
6005
11

Classe Wrapper

C'est l'approche la plus fiable et la plus sèche que j'ai trouvée jusqu'à présent pour à la fois afficher les valeurs par défaut et utiliser un autre formateur comme en argparse.RawTextHelpFormattermême temps:

#!/usr/bin/env python3

import argparse

class ArgumentParserWithDefaults(argparse.ArgumentParser):
    def add_argument(self, *args, help=None, default=None, **kwargs):
        if help is not None:
            kwargs['help'] = help
        if default is not None and args[0] != '-h':
            kwargs['default'] = default
            if help is not None:
                kwargs['help'] += ' Default: {}'.format(default)
        super().add_argument(*args, **kwargs)

parser = ArgumentParserWithDefaults(
    formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument('-a', default=13, help='''my help
for a''')
parser.add_argument('-b', default=42, help='''my help
for b''')
parser.add_argument('--no-default', help='''my help
for no-default''')
parser.add_argument('--no-help', default=101)

parser.print_help()
print()
print(parser.parse_args())

Production:

usage: main.py [-h] [-a A] [-b B] [--no-default NO_DEFAULT]
               [--no-help NO_HELP]

optional arguments:
  -h, --help            show this help message and exit
  -a A                  my help
                        for a Default: 13
  -b B                  my help
                        for b Default: 42
  --no-default NO_DEFAULT
                        my help
                        for no-default
  --no-help NO_HELP

Namespace(a=13, b=42, no_default=None, no_help=101)

ArgumentDefaultsHelpFormatter+ RawTextHelpFormatterhéritage multiple

L'héritage multiple fonctionne, mais il ne semble pas être une API publique:

#!/usr/bin/env python3

import argparse

class RawTextArgumentDefaultsHelpFormatter(
        argparse.ArgumentDefaultsHelpFormatter,
        argparse.RawTextHelpFormatter
    ):
        pass

parser = argparse.ArgumentParser(
    formatter_class=RawTextArgumentDefaultsHelpFormatter
)
parser.add_argument('-a', default=13, help='''my help
for a''')
parser.add_argument('-b', default=42, help='''my help
for b''')
parser.print_help()

Production:

usage: a.py [-h] [-a A] [-b B]

optional arguments:
  -h, --help  show this help message and exit
  -a A        my help
              for a (default: 13)
  -b B        my help
              for b (default: 42)

Cela fonctionne, cela fonctionne parce que, comme nous pouvons le voir trivialement à partir des sources https://github.com/python/cpython/blob/v3.6.5/Lib/argparse.py#L648, cela:

  • RawTextHelpFormatter met en oeuvre _split_lines
  • ArgumentDefaultsHelpFormatter met en oeuvre _get_help_string

nous pouvons donc deviner qu'ils fonctionneront très bien ensemble.

Cependant, cela ne semble pas être une API publique, et les méthodes ne le sont pas non plus formatter_class, donc je ne pense pas qu'il existe actuellement une méthode API publique pour le faire. argparsedocstring dit:

Toutes les autres classes de ce module sont considérées comme des détails d'implémentation. (Notez également que HelpFormatter et RawDescriptionHelpFormatter ne sont considérés comme publics que comme noms d'objet - l'API des objets du formateur est toujours considérée comme un détail d'implémentation.)

Voir aussi: Personnaliser le message d'aide argparse

Testé sur Python 3.6.5.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
1
Génial ! Enfin, imprimez la docstring formatée et les arguments par défaut. Merci
Sylvain