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 Raise
nœuds, puis essaie de trouver des modèles courants de levée d'exceptions (par exemple, appeler un constructeur directement)
Soit x
le programme suivant:
x = '''\
if f(x):
raise IOError(errno.ENOENT, 'not found')
else:
e = g(x)
raise e
'''
Construisez l'AST en utilisant le compiler
package:
tree = compiler.parse(x)
Définissez ensuite une Raise
classe de visiteurs:
class RaiseVisitor(object):
def __init__(self):
self.nodes = []
def visitRaise(self, n):
self.nodes.append(n)
Et parcourez les Raise
nœ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 :)
raise
utiliser des chaînes, pas seulement desBaseException
sous - classes. Donc, si vous appelez du code de bibliothèque hors de votre contrôle, ceexcept Exception
n'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.