web-dev-qa-db-fra.com

En Python, en utilisant argparse, n'autorise que les entiers positifs

Le titre résume assez bien ce que j'aimerais que cela se produise.

Voici ce que j'ai, et bien que le programme n'explose pas sur un entier non positif, je souhaite que l'utilisateur soit informé qu'un entier non positif est fondamentalement un non-sens.

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-g", "--games", type=int, default=162,
                    help="The number of games to simulate")
args = parser.parse_args()

Et la sortie:

python simulate_many.py -g 20
Setting up...
Playing games...
....................

Sortie avec un négatif:

python simulate_many.py -g -2
Setting up...
Playing games...

Maintenant, évidemment, je pourrais simplement ajouter un si pour déterminer if args.games est négatif, mais j’étais curieux de savoir s’il existait un moyen de le piéger au niveau argparse afin de tirer parti de l’impression automatique.

Idéalement, cela afficherait quelque chose de similaire à ceci:

python simulate_many.py -g a
usage: simulate_many.py [-h] [-g GAMES] [-d] [-l LEAGUE]
simulate_many.py: error: argument -g/--games: invalid int value: 'a'

Ainsi:

python simulate_many.py -g -2
usage: simulate_many.py [-h] [-g GAMES] [-d] [-l LEAGUE]
simulate_many.py: error: argument -g/--games: invalid positive int value: '-2'

Pour le moment je fais ça et je suppose que je suis heureux:

if args.games <= 0:
    parser.print_help()
    print "-g/--games: must be positive."
    sys.exit(1)
126
jgritty

Cela devrait être possible en utilisant type. Vous aurez toujours besoin de définir une méthode qui décide cela pour vous:

def check_positive(value):
    ivalue = int(value)
    if ivalue <= 0:
        raise argparse.ArgumentTypeError("%s is an invalid positive int value" % value)
    return ivalue

parser = argparse.ArgumentParser(...)
parser.add_argument('foo', type=check_positive)

Ceci est fondamentalement juste un exemple adapté de la perfect_square fonction dans le docs sur argparse.

191
Yuushi

type serait l'option recommandée pour gérer les conditions/contrôles, comme dans la réponse de Yuushi.

Dans votre cas spécifique, vous pouvez également utiliser le paramètre choices si votre limite supérieure est également connue:

parser.add_argument('foo', type=int, choices=xrange(5, 10))
49
aneroid

La manière rapide et sale, si vous avez un maximum prévisible et min pour votre argument, est d'utiliser choices avec une plage

parser.add_argument('foo', type=int, choices=xrange(0, 1000))
5
ben author

Une alternative plus simple, en particulier si la sous-classe argparse.ArgumentParser, Consiste à lancer la validation à partir de la méthode parse_args.

Dans une telle sous-classe:

def parse_args(self, args=None, namespace=None):
    """Parse and validate args."""
    namespace = super().parse_args(args, namespace)  # super() works in Python 3
    if namespace.games <= 0:
         raise self.error('The number of games must be a positive integer.')
    return namespace

Cette technique peut ne pas être aussi cool qu'un appelable personnalisé, mais elle fait le travail.


À propos de ArgumentParser.error(message) :

Cette méthode imprime un message d'utilisation comprenant le message à l'erreur standard et termine le programme avec un code d'état de 2.


Crédit: réponse par jonatan

4
Acumenus