2009-10-24 3 views
4

Je souhaite implémenter des messages d'erreur plus conviviaux si l'utilisateur essaie d'exécuter un script python qui tente d'importer des modules qui n'ont pas été installés. Cela inclut l'impression des instructions sur la façon d'installer le module manquant.Messages d'erreur plus conviviaux lors de l'importation de modules manquants

Une façon de le faire serait de mettre un bloc try..catch autour des importations, mais cela est un peu laid, car il tournerait quelque chose de simple comme

import some_module 

dans

try: 
    import some_module 
except ImportError, e: 
    handle_error(e) 

et il devrait être ajouté à chaque fichier. En outre, ImportError ne semble pas stocker le nom du module manquant n'importe où (sauf dans le message), donc vous devriez mettre un try..catch séparé autour de chaque importation si vous avez besoin de connaître le nom (comme je le fais) . L'analyse du nom du module n'est pas une option car le message porté par ImportError peut changer pour la version python en version et en fonction des paramètres régionaux de l'utilisateur. Je suppose que je pourrais utiliser sys.excepthook pour attraper toutes les exceptions et les transmettre sauf ImportError. Ou serait-il possible de définir quelque chose comme

safe_import some_module 

qui se comporterait comme je veux?

Est-ce que quelqu'un connaît des solutions existantes à ce problème?

Répondre

2

Je voudrais mettre des modules supplémentaires dans le paquet qui, lors de l'importation, imprimer le message le plus utile, puis déclencher une ImportError régulière. Lorsque le vrai module est installé, vos modules seront ombrés (assurez-vous d'ajouter le répertoire où ils vivent à l'adresse et de sys.path).

+0

Je pense que ce qui est probablement la meilleure solution proposée. Il ne s'appuie pas sur des «trucs» spéciaux et à cause de cela devrait être assez robuste. En même temps, il ne nécessite aucun changement dans le code source (sauf peut-être en ajoutant le bon chemin à sys.path qui peut être traité facilement). – pafcu

5

Vous pouvez mettre, quelque part que ce sera toujours exécuté (par exemple dans site.py ou sitecustomize.py):

import __builtin__ 

realimport = __builtin__.__import__ 

def myimport(modname, *a): 
    try: 
    return realimport(modname, *a) 
    except ImportError, e: 
    print "Oops, couldn't import %s (%s)" % (modname, e) 
    print "Here: add nice directions and whatever else" 
    raise 

__builtin__.__import__ = myimport 

Voir les __import__ docs here.

+0

Je suppose qu'un problème avec ceci est qu'il ne joue pas bien si quelqu'un d'autre a la même idée. Si un autre paquet utilise la même astuce, vous n'avez pas de chance (puisqu'il installerait une autre version si __import__). – pafcu

3

Vous n'avez pas besoin d'importer ImportError pour chaque importation. Vous pouvez utiliser un bloc global try..except dans le point d'entrée de votre script.

Vous pouvez obtenir le nom du module manquant à partir d'une instance ImportError en utilisant la propriété message.

Par exemple, si le point d'entrée de votre script est main.py:

if __name__ == '__main__': 
    try: 
     import module1 
     import module2 

     module1.main() 
    except ImportError as error: 
     print "You don't have module {0} installed".format(error.message[16:]) 

Ne pas importer quoi que ce soit en dehors du bloc try..except. Cela couvrira module1 et module2 et tous les modules importés par eux et ainsi de suite.

Comme vous l'avez dit, vous pouvez définir votre propre fonction import_safe:

def import_safe(module): 
    try: 
     return __import__(module) 
    except ImportError as error: 
     print "You don't have module {0} installed".format(error.message[16:]) 

Ensuite, vous pouvez utiliser la fonction:

sys = import_safe('sys') 
gtk = import_safe('gkt') 

À mon avis, la stratégie de poing est mieux. Le second rendrait votre code difficile à lire.Et va changer une partie essentielle de la langue.

+0

Le problème avec la première approche est qu'il essaie d'analyser le message d'erreur (même pas cela, il suppose simplement que le nom du module est à une position spécifique). Ce n'est simplement pas une hypothèse qui peut être faite: Les messages d'erreur peuvent être localisés ou changer entre les versions python – pafcu

+0

plutôt que 'print" Vous n'avez pas le module {0} installé ".format (error.message [16:]) 'juste **' print (erreur) '** fonctionne à la fois sur 2.7.10 et 3.5.0 – CrandellWS

1

Remplacer sys.excepthook:

orig_excepthook = sys.excepthook 

def my_excepthook(type, value, tb): 
    orig_excepthook(type, value, tb) 
    if issubclass(type, ImportError): 
     # print some friendly message 

sys.excepthook = my_excepthook 
Questions connexes