Je suppose qu'une solution pourrait être imprécise en raison du manque de règles de typage statiques.
Je ne connais pas d'outil qui vérifie les exceptions, mais vous pourriez proposer votre propre outil correspondant à vos besoins (une bonne chance de jouer un peu avec l'analyse statique).
Dans un premier temps, vous pouvez écrire une fonction qui construit un AST, trouve tous les Raisenœuds, puis essaie de trouver des modèles courants de levée d'exceptions (par exemple, appeler un constructeur directement)
Soit xle programme suivant:
x = '''\
if f(x):
raise IOError(errno.ENOENT, 'not found')
else:
e = g(x)
raise e
'''
Construisez l'AST en utilisant le compilerpackage:
tree = compiler.parse(x)
Définissez ensuite une Raiseclasse de visiteurs:
class RaiseVisitor(object):
def __init__(self):
self.nodes = []
def visitRaise(self, n):
self.nodes.append(n)
Et parcourez les Raisenœuds de collecte AST :
v = RaiseVisitor()
compiler.walk(tree, v)
>>> print v.nodes
[
Raise(
CallFunc(
Name('IOError'),
[Getattr(Name('errno'), 'ENOENT'), Const('not found')],
None, None),
None, None),
Raise(Name('e'), None, None),
]
Vous pouvez continuer en résolvant les symboles en utilisant les tables de symboles du compilateur, en analysant les dépendances de données, etc. Ou vous pouvez simplement en déduire que CallFunc(Name('IOError'), ...)"devrait certainement signifier augmenter IOError", ce qui est tout à fait acceptable pour des résultats pratiques rapides :)
raiseutiliser des chaînes, pas seulement desBaseExceptionsous - classes. Donc, si vous appelez du code de bibliothèque hors de votre contrôle, ceexcept Exceptionn'est même pas suffisant, car il n'attrapera pas les exceptions de chaîne. Comme d'autres l'ont souligné, vous aboyez ici le mauvais arbre.