web-dev-qa-db-fra.com

Afficher un message d'aide avec python argparse lorsque le script est appelé sans argument

Cela pourrait être simple. Supposons que j'ai un programme qui utilise argparse pour traiter les arguments/options de ligne de commande. Ce qui suit imprimera le message 'help':

./myprogram -h

ou:

./myprogram --help

Mais si je lance le script sans aucun argument, il ne fait rien. Ce que je veux, c'est afficher le message d'utilisation lorsqu'il est appelé sans arguments. Comment est-ce fait?

193
musashiXXX

Cette réponse provient de Steven Bethard sur les groupes Google . Je le republie ici pour faciliter l'accès aux personnes sans compte Google.

Vous pouvez remplacer le comportement par défaut de la méthode error:

import argparse
import sys

class MyParser(argparse.ArgumentParser):
    def error(self, message):
        sys.stderr.write('error: %s\n' % message)
        self.print_help()
        sys.exit(2)

parser = MyParser()
parser.add_argument('foo', nargs='+')
args = parser.parse_args()

Notez que la solution ci-dessus imprimera le message d'aide chaque fois que la méthode error est déclenchée. Par exemple, test.py --blah imprimera également le message d'aide si --blah n'est pas une option valide.

Si vous souhaitez imprimer le message d'aide uniquement si aucun argument n'est fourni sur la ligne de commande, c'est peut-être le moyen le plus simple:

import argparse
import sys

parser=argparse.ArgumentParser()
parser.add_argument('foo', nargs='+')
if len(sys.argv)==1:
    parser.print_help(sys.stderr)
    sys.exit(1)
args=parser.parse_args()

Notez que parser.print_help() imprime par défaut sur stdout. Comme init_js le suggère , utilisez parser.print_help(sys.stderr) pour imprimer sur stderr.

243
unutbu

Au lieu d'écrire une classe, un try/except peut être utilisé à la place

try:
    options = parser.parse_args()
except:
    parser.print_help()
    sys.exit(0)

L'avantage, c'est que le flux de travail est plus clair et que vous n'avez pas besoin d'une classe de bout. L'inconvénient est que la première ligne d'utilisation est imprimée deux fois.

Cela nécessitera au moins un argument obligatoire. En l'absence d'arguments obligatoires, fournir zéro argument sur la ligne de commande est valide.

47
vacri

Avec argparse vous pourriez faire:

parser.argparse.ArgumentParser()
#parser.add_args here

#sys.argv includes a list of elements starting with the program
if len(sys.argv) < 2:
    parser.print_usage()
    sys.exit(1)
20
cgseller

Si vous avez des arguments à exécuter pour le script, utilisez le paramètre requis pour ArgumentParser, comme indiqué ci-dessous: -

parser.add_argument('--foo', required=True)

parse_args () signalera une erreur si le script est exécuté sans aucun argument.

15
pd321

Si vous associez des fonctions par défaut pour des (sous) analyseurs, comme indiqué sous add_subparsers , vous pouvez simplement l'ajouter en tant qu'action par défaut:

_parser = argparse.ArgumentParser()
parser.set_defaults(func=lambda x: parser.print_usage())
args = parser.parse_args()
args.func(args)
_

Ajoutez try-except si vous déclenchez des exceptions en raison de l'absence d'arguments de position.

13
AManOfScience

Jeter ma version dans la pile ici:

import argparse

parser = argparse.ArgumentParser()
args = parser.parse_args()
if not vars(args):
    parser.print_help()
    parser.exit(1)

Vous remarquerez peut-être le parser.exit - je le fais principalement comme ça parce qu'il enregistre une ligne d'importation si c'était la seule raison pour sys dans le fichier ...

9
pauricthelodger

La solution la plus propre sera de passer manuellement l'argument par défaut si aucun n'a été donné sur la ligne de commande:

parser.parse_args(args=None if sys.argv[1:] else ['--help'])

Exemple complet:

import argparse, sys

parser = argparse.ArgumentParser()
parser.add_argument('--Host', default='localhost', help='Host to connect to')
# parse arguments
args = parser.parse_args(args=None if sys.argv[1:] else ['--help'])

# use your args
print("connecting to {}".format(args.Host))

Ceci imprimera une aide complète (pas une utilisation courte) si elle est appelée sans arguments.

6
Ievgen Popovych

Il existe une paire de one-liners avec sys.argv[1:] (un idiome très commun de Python pour référencer les arguments de ligne de commande, étant sys.argv[0] le nom du script) qui peut faire le travail.

Le premier est explicite, propre et pythonique:

args = parser.parse_args(None if sys.argv[1:] else ['-h'])

Le second est un peu plus hackier. En combinant le fait précédemment évalué qu'une liste vide est False avec les équivalences True == 1 et False == 0, vous obtenez ceci:

args = parser.parse_args([None, ['-h']][not sys.argv[1:]])

Peut-être trop de crochets, mais assez clair si un choix d'argument précédent a été fait.

_, *av = sys.argv
args = parser.parse_args([None, ['-h']][not av])
2
Nuno André
parser.print_help()
parser.exit()

La méthode parser.exit accepte également une valeur status (code retour) et une valeur message (incluez vous-même une nouvelle ligne finale!).

un exemple d'opinion, :)

#!/usr/bin/env python3

""" Example argparser based python file
"""

import argparse

ARGP = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawTextHelpFormatter,
)
ARGP.add_argument('--example', action='store_true', help='Example Argument')


def main(argp=None):
    if argp is None:
        argp = ARGP.parse_args()  # pragma: no cover

    if 'soemthing_went_wrong' and not argp.example:
        ARGP.print_help()
        ARGP.exit(status=128, message="\nI just don't know what went wrong, maybe missing --example condition?\n")


if __== '__main__':
    main()  # pragma: no cover

Exemple d'appels:

 $ python3 ~/helloworld.py; echo $? 
 usage: helloworld.py [-h] [--example] 
 
 Exemple de fichier basé sur un argparser python. 
 
 arguments optionnels: 
 -h, --help - Affiche ce message d’aide et quitte 
 --exemple. Exemple Argument 
 
 Je ne sais pas quoi. s'est mal passé, peut-être manquant - condition-exemple? 
 128 
 $ python3 ~/helloworld.py --exemple; echo $? 
 0 
1
ThorSummoner

Si votre commande est quelque chose où un utilisateur doit choisir une action, utilisez un groupe mutuellement exclusif avec required = True.

C'est un peu une extension de la réponse donnée par pd321.

import argparse

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--batch", action='store', type=int,  metavar='pay_id')
group.add_argument("--list", action='store_true')
group.add_argument("--all", action='store_true', help='check all payments')

args=parser.parse_args()

if args.batch:
    print('batch {}'.format(args.batch))

if args.list:
    print('list')

if args.all:
    print('all')

Sortie:

$ python3 a_test.py
usage: a_test.py [-h] (--batch pay_id | --list | --all)
a_test.py: erreur: l'un des arguments --batch --list --all est requis

Cela donne seulement l'aide de base. Et certaines des autres réponses vous apporteront toute l'aide nécessaire. Mais au moins, vos utilisateurs savent qu'ils peuvent le faire - h

0
Tim Bray

Voici une autre façon de le faire, si vous avez besoin de quelque chose de flexible pour afficher de l'aide si des paramètres spécifiques sont passés, pas du tout ou plus d'un argument en conflit:

import argparse
import sys

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--days', required=False,  help="Check mapped inventory that is x days old", default=None)
    parser.add_argument('-e', '--event', required=False, action="store", dest="event_id",
                        help="Check mapped inventory for a specific event", default=None)
    parser.add_argument('-b', '--broker', required=False, action="store", dest="broker_id",
                        help="Check mapped inventory for a broker", default=None)
    parser.add_argument('-k', '--keyword', required=False, action="store", dest="event_keyword",
                        help="Check mapped inventory for a specific event keyword", default=None)
    parser.add_argument('-p', '--product', required=False, action="store", dest="product_id",
                        help="Check mapped inventory for a specific product", default=None)
    parser.add_argument('-m', '--metadata', required=False, action="store", dest="metadata",
                        help="Check mapped inventory for specific metadata, good for debugging past tix", default=None)
    parser.add_argument('-u', '--update', required=False, action="store_true", dest="make_updates",
                        help="Update the event for a product if there is a difference, default No", default=False)
    args = parser.parse_args()

    days = args.days
    event_id = args.event_id
    broker_id = args.broker_id
    event_keyword = args.event_keyword
    product_id = args.product_id
    metadata = args.metadata
    make_updates = args.make_updates

    no_change_counter = 0
    change_counter = 0

    req_arg = bool(days) + bool(event_id) + bool(broker_id) + bool(product_id) + bool(event_keyword) + bool(metadata)
    if not req_arg:
        print("Need to specify days, broker id, event id, event keyword or past tickets full metadata")
        parser.print_help()
        sys.exit()
    Elif req_arg != 1:
        print("More than one option specified. Need to specify only one required option")
        parser.print_help()
        sys.exit()

    # Processing logic here ...

À votre santé!

0
radtek

Définissez vos arguments de position avec nargues et vérifiez si les arguments de position sont vides.

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='?')
args = parser.parse_args()
if not args.file:
    parser.print_help()

Référence Python nargs

0
zerocog