2010-10-25 4 views
2

HI, les gars. J'utilise cmd et optparse pour développer un CLI.py ​​pour une collection de classes déjà fonctionnelles (CDContainer, CD, etc.). Voici quelques parties du code. J'ai un problème. Lorsqu'il y a des exceptions (mauvais type d'entrée ou valeurs manquantes), l'optparse quittera le programme entier au lieu de la méthode de commande spécifique.gestion des exceptions pour optparse de python

import cmd 
class CLI(cmd.Cmd): 

    def do_addcd(self, line): 
     args=line.split() 
     parser = OptionParser() 
     parser.add_option("-t", "--track", dest="track_number", type="int", 
      help="track number") 
     parser.add_option("-n", "--cdname", dest="cd_name", type="string", 
      help="CD name") 
     (options, positional_args) = parser.parse_args(args[0:]) 
     cd_obj= CD() 
     cd_obj.addCD(options.track_number, options.cd_name) 

Sous "> python", si je tape CLI.py, alors j'aurai (Cmd), donc je pourrais taper la commande comme "(Cmd) addcd 3 -t thriller -n". mais si je tape "addcd -t r -n 3", alors optparse mettra fin à l'ensemble CLI.py ​​et quittera. Ce n'est pas bon pour moi. Je veux rappeler à l'utilisateur pour chaque méthode, au lieu de mettre fin à l'ensemble du programme. Cependant, la documentation d'optparse indique que «l'ensemble du programme se termine». donc je ne pouvais pas utiliser optparse "aveuglément". Que puis-je faire?

Répondre

10

La documentation optparse dit ceci:

Si le comportement de gestion des erreurs par défaut de optparse ne répond pas à vos besoins, vous aurez besoin de sous-classe OptionParser et passer outre sa sortie() et/ou une erreur() méthodes

vous aviez Idéalement définir un nouveau type d'exception, sous-classe optparse, soulever l'exception dans la méthode exit() ou error() que vous avez remplacée, puis l'attraper et de traiter au besoin.

Vous pouvez tricher, cependant. Si vous voulez que le message d'erreur soit imprimé mais que vous ne voulez pas que le programme quitte, vous pouvez attraper l'exception SystemExit pour attraper où optparse essaie de quitter et de l'arrêter.

Ainsi, par exemple:

try:  
    (options, positional_args) = parser.parse_args(args[0:]) 
except SystemExit: 
    return 

cd_obj= CD() 
cd_obj.addCD(options.track_number, options.cd_name) 

ou pour remplacer la méthode:

import optparse 

class OptionParsingError(RuntimeError): 
    def __init__(self, msg): 
     self.msg = msg 

class OptionParsingExit(Exception): 
    def __init__(self, status, msg): 
     self.msg = msg 
     self.status = status 

class ModifiedOptionParser(optparse.OptionParser): 
    def error(self, msg): 
     raise OptionParsingError(msg) 

    def exit(self, status=0, msg=None): 
     raise OptionParsingExit(status, msg) 

puis:

try: 
    parser = ModifiedOptionParser() 
    parser.add_option("-t", "--track", dest="track_number", type="int", 
     help="track number") 
    (options, positional_args) = parser.parse_args(args[0:]) 
except OptionParsingError, e: 
    print 'There was a parsing error: %s' % e.msg 
    return 
except OptionParsingExit, e: 
    print 'The option parser exited with message %s and result code %s' % (e.msg, e.status) 
    return 

cd_obj= CD() 
cd_obj.addCD(options.track_number, options.cd_name) 
+0

Je vois. et je n'utilise pas l'optparse? J'analyse les args par moi-même et je l'analyse en conséquence.si j'utilise optparse, comme vous l'avez dit, je devrais remplacer ses méthodes de sortie ou d'erreur en quelque sorte, dont je ne suis pas si confiant que je pourrais le faire. – pepero

+1

Je voudrais rester avec optparse. Cela gardera le comportement d'analyse des options cohérent, et écrire un analyseur d'arguments qui suit les conventions normales demanderait beaucoup de travail. J'ai mis à jour ma réponse avec un exemple de substitution de la méthode d'erreur. –

+0

salut, Robie, merci beaucoup pour ta réponse détaillée avec code !!! ça marche avec mon intention! mais juste une chose, quand j'appelle la méthode -help, par exemple, addcd -h, il énumère les options, puis quitte le programme. est-il également possible de le résoudre pour "aide". Merci beaucoup! – pepero

0

Cela a probablement à voir avec les types que vous passez à la classe CD: sans le voir, il y a de très bonnes chances qu'il échoue. Avant de créer cet objet et de transmettre les arguments, il est vraiment recommandé de nettoyer ces données, de vérifier qu'elles correspondent au type correct et d'effectuer toutes les vérifications que vous jugez raisonnables.

0
try: 
    parser = ModifiedOptionParser() 
    parser.add_option("-t", "--track", dest="track_number", type="int", 
     help="track number") 
    (options, positional_args) = parser.parse_args(args[0:]) 
except OptionParsingError, e: 
    print 'There was a parsing error: %s' % e.msg 
    return 
except OptionParsingExit, e: 
    print 'The option parser exited with message %s and result code %s' % (e.msg, e.status) 
    return 

La classe d'exception personnalisée ne peut toujours pas gérer l'option '-h --help' qui affiche la valeur par défaut contexte d'aide Ce que j'ai fait J'ai utilisé sys.argv avant d'essayer - sauf le bloc pour gérer la fonction d'aide.

if sys.argv[1] == '-h' or sys.argv[1] == '--help': 
    raise Exception('help') 

parser = ModifiedOptionParser() 
... 
except Exception as value: 
    status = str(value) 
    if status is 'help': 
     parser.print_help() 
     return -1 # I need to set different return value 

Merci pour les conseils d'ailleurs.