108 votes

Python argparse: Faire au moins un argument requis

J'ai été en utilisant argparse pour un programme en Python qui peut -prepare, -upload ou deux:

parser = argparse.ArgumentParser(description='Log archiver arguments.')
parser.add_argument('-process', action='store_true')
parser.add_argument('-upload',  action='store_true')
args = parser.parse_args()

Le programme est vide de sens sans la présence d'au moins un paramètre. Comment puis-je configurer argparse de la force au moins un paramètre d'être choisi?

Mise à JOUR:

Suivant les commentaires: Quel est le Pythonic façon de paramétrer un programme avec au moins une option?

133voto

phihag Points 89765
if not (args.process or args.upload):
    parser.error('No action requested, add -process or -upload')

38voto

brentlance Points 901
args = vars(parser.parse_args())
if not any(args.values()):
    parser.error('No arguments provided.')

20voto

Jacek Konieczny Points 4002

Si ce n'est le "ou les deux" partie (j'ai d'abord manqué), vous pouvez utiliser quelque chose comme ceci:

parser = argparse.ArgumentParser(description='Log archiver arguments.')
parser.add_argument('--process', action='store_const', const='process', dest='mode')
parser.add_argument('--upload',  action='store_const', const='upload', dest='mode')
args = parser.parse_args()
if not args.mode:
    parser.error("One of --process or --upload must be given")

Bien que, probablement, il serait préférable d'utiliser des sous-commandes à la place.

10voto

Jan Vlcinsky Points 7932

Exigences De L'Examen

  • utiliser argparse (je vais ignorer celui-ci)
  • permettre à une ou deux actions à être appelé (au moins un).
  • essayez par Pythonic (je préfère l'appeler "POSIX"-like)

Il y a aussi quelques exigences implicites lorsque l'on vit sur la ligne de commande:

  • expliquer l'utilisation de l'utilisateur d'une manière qui est facile à comprendre
  • les options sont facultatives
  • permettre la spécification des drapeaux et des options
  • permettent de combiner avec d'autres paramètres (comme le nom de fichier ou les noms).

Exemple de solution à l'aide d' docopt (fichier managelog.py):

"""Manage logfiles
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  Password

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>
"""
if __name__ == "__main__":
    from docopt import docopt
    args = docopt(__doc__)
    print args

Essayez de le lancer:

$ python managelog.py
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h

Afficher l'aide:

$ python managelog.py -h
Manage logfiles
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  P    managelog.py [options] upload -- <logfile>...

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>

Et de l'utiliser:

$ python managelog.py -V -U user -P secret upload -- alfa.log beta.log
{'--': True,
 '--pswd': 'secret',
 '--user': 'user',
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': False,
 'upload': True}

Court de rechange short.py

Il peut être encore plus courte variante:

"""Manage logfiles
Usage:
    short.py [options] (process|upload)... -- <logfile>...
    short.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  Password

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>
"""
if __name__ == "__main__":
    from docopt import docopt
    args = docopt(__doc__)
    print args

L'utilisation ressemble à ceci:

$ python short.py -V process upload  -- alfa.log beta.log
{'--': True,
 '--pswd': None,
 '--user': None,
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': 1,
 'upload': 1}

Remarque, qu'au lieu de valeurs booléennes pour les "processus" et "télécharger" clés il existe des compteurs.

Il s'avère, nous ne pouvons pas éviter la duplication de ces mots:

$ python short.py -V process process upload  -- alfa.log beta.log
{'--': True,
 '--pswd': None,
 '--user': None,
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': 2,
 'upload': 1}

Conclusions

La conception d'une bonne interface de ligne de commande peut être difficile parfois.

Il y a plusieurs aspects de base de ligne de commande programme:

  • une bonne conception de la ligne de commande
  • la sélection et à l'utilisation appropriée de l'analyseur

argparse offre beaucoup, mais limite les scénarios possibles et peuvent devenir très complexes.

Avec docopt les choses vont beaucoup plus courts tout en préservant la lisibilité et offrant un haut degré de flexibilité. Si vous parvenez à obtenir analysé les arguments de dictionnaire et faire un peu de conversions (en entier, à l'ouverture des fichiers..) à la main (ou par d'autres bibliothèque appelée schema), vous trouverez peut - docopt bon pour la ligne de commande de l'analyse.

5voto

NuclearPeon Points 547

Si vous avez besoin d'un programme en python pour exécuter avec au moins un paramètre, ajouter un argument qui n'a pas l'option préfixe (- ou -- par défaut) et définissez nargs=+ (au moins un argument obligatoire). Le problème avec cette méthode que j'ai trouvé est que si vous ne spécifiez pas l'argument, argparse va générer un "trop peu d'arguments" d'erreur et de ne pas imprimer le menu aide. Si vous n'avez pas besoin de cette fonctionnalité, voici comment le faire dans le code:

import argparse

parser = argparse.ArgumentParser(description='Your program description')
parser.add_argument('command', nargs="+", help='describe what a command is')
args = parser.parse_args()

Je pense que lorsque vous ajoutez un argument de l'option de préfixes, nargs régit l'ensemble de l'argument de l'analyseur et pas seulement de l'option. (Ce que je veux dire, si vous avez un --option pavillon nargs="+", alors --option drapeau attend au moins un argument. Si vous avez option avec nargs="+", il s'attend au moins un argument en général.)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X