Outre le bricolage avec la source argparse
, existe-t-il un moyen de contrôler le code d'état de sortie en cas de problème lorsque parse_args()
est appelé, par exemple, un commutateur requis manquant?
Je ne connais aucun mécanisme pour spécifier un code de sortie par argument. Vous pouvez intercepter l'exception SystemExit
déclenchée sur .parse_args()
mais je ne sais pas comment vous pourriez alors déterminer ce que spécifiquement a provoqué l'erreur.
EDIT: Pour tous ceux qui recherchent une solution pratique, voici la situation:
ArgumentError()
est correctement levé lorsque l'analyse de l'argument échoue. Il est passé l'instance d'argument et un messageArgumentError()
ne pas stocke l'argument en tant qu'attribut d'instance, bien qu'il soit passé (ce qui serait pratique)ArgumentError
en sous-classant ArgumentParser
, en remplaçant .error () et en récupérant l'exception depuis sys.exc_info ()Tout cela signifie que le code suivant - tout en étant laid - nous permet d'attraper l'exception ArgumentError, de saisir l'argument et le message d'erreur incriminés et de faire ce que nous jugeons opportun:
import argparse
import sys
class ArgumentParser(argparse.ArgumentParser):
def _get_action_from_name(self, name):
"""Given a name, get the Action instance registered with this parser.
If only it were made available in the ArgumentError object. It is
passed as it's first arg...
"""
container = self._actions
if name is None:
return None
for action in container:
if '/'.join(action.option_strings) == name:
return action
Elif action.metavar == name:
return action
Elif action.dest == name:
return action
def error(self, message):
exc = sys.exc_info()[1]
if exc:
exc.argument = self._get_action_from_name(exc.argument_name)
raise exc
super(ArgumentParser, self).error(message)
## usage:
parser = ArgumentParser()
parser.add_argument('--foo', type=int)
try:
parser.parse_args(['--foo=d'])
except argparse.ArgumentError, exc:
print exc.message, '\n', exc.argument
Non testé d'aucune manière utile. L'indemnité habituelle de ne pas me blâmer en cas de rupture s'applique.
Toutes les réponses expliquent bien les détails de la mise en œuvre argparse .
En effet, comme proposé dans PEP (et pointé par Rob Cowie), il faut hériter ArgumentParser et remplacer le comportement de erreur ou sortie méthodes.
Dans mon cas, je voulais juste remplacer l'impression d'utilisation par une aide complète en cas d'erreur:
class ArgumentParser(argparse.ArgumentParser):
def error(self, message):
self.print_help(sys.stderr)
self.exit(2, '%s: error: %s\n' % (self.prog, message))
En cas de remplacement, le code principal continuera à contenir le minimaliste.
# Parse arguments.
args = parser.parse_args()
# On error this will print help and cause exit with explanation message.
Peut-être attraper l'exception SystemExit
serait une solution de contournement simple:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('foo')
try:
args = parser.parse_args()
except SystemExit:
print("do something else")
Fonctionne pour moi, même dans une session interactive.
Edit: On dirait que @Rob Cowie m'a battu à l'interrupteur. Comme il l'a dit, cela n'a pas beaucoup de potentiel de diagnostic, sauf si vous voulez devenir idiot et essayer de glaner des informations sur le traçage.
Vous pouvez utiliser l'une des méthodes de sortie: http://docs.python.org/library/argparse.html#exiting-methods . Cependant, il devrait déjà gérer les situations où les arguments ne sont pas valides (en supposant que vous ayez défini vos arguments correctement).
Utilisation d'arguments non valides:
% [ $(./test_argparse.py> /dev/null 2>&1) ] || { echo error }
error # exited with status code 2
Il faudrait bricoler. Regarder argparse.ArgumentParser.error
, qui est appelé en interne. Ou vous pouvez rendre les arguments non obligatoires, puis vérifier et quitter en dehors d'argparse.
Bien que argparse.error soit une méthode et non une classe, il n'est pas possible "d'essayer", sauf "toutes les" erreurs "d'arguments non reconnus". Si vous le souhaitez, vous devez remplacer la fonction d'erreur d'argparse:
def print_help(errmsg):
print(errmsg.split(' ')[0])
parser.error = print_help
args = parser.parse_args()
sur une entrée invalide, il imprimera maintenant:
unrecognised
J'avais besoin d'une méthode simple pour détecter une erreur d'argparse au démarrage de l'application et transmettre l'erreur à un formulaire wxPython. La combinaison des meilleures réponses ci-dessus a abouti à la petite solution suivante:
import argparse
# sub class ArgumentParser to catch an error message and prevent application closing
class MyArgumentParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
super(MyArgumentParser, self).__init__(*args, **kwargs)
self.error_message = ''
def error(self, message):
self.error_message = message
def parse_args(self, *args, **kwargs):
# catch SystemExit exception to prevent closing the application
result = None
try:
result = super().parse_args(*args, **kwargs)
except SystemExit:
pass
return result
# testing -------
my_parser = MyArgumentParser()
my_parser.add_argument('arg1')
my_parser.parse_args()
# check for an error
if my_parser.error_message:
print(my_parser.error_message)
l'exécuter:
>python test.py
the following arguments are required: arg1