67 votes

Trouver le code mort dans un grand projet python

J'ai vu Comment trouver les fonctions inutilisées dans le code Python ? mais c'est vraiment vieux, et ça ne répond pas vraiment à ma question.

J'ai un grand projet python avec plusieurs bibliothèques qui sont partagées par plusieurs scripts de point d'entrée. Ce projet a été accrédité pendant de nombreuses années avec de nombreux auteurs, il y a donc tout un tas de code mort. Vous connaissez la chanson.

Je sais que trouver tout le code mort est indécidable. Tout ce dont j'ai besoin est un outil qui trouvera toutes les fonctions qui ne sont appelées nulle part. Nous ne faisons rien de fantaisiste en appelant des fonctions sur la base de la chaîne de caractères du nom de la fonction, donc je ne m'inquiète pas de quelque chose de pathologique...

Je viens d'installer pylint, mais il semble être basé sur les fichiers, et ne pas prêter beaucoup d'attention aux dépendances inter-fichiers, ou même aux dépendances de fonctions.

Il est clair que je pourrais chercher def dans tous les fichiers, récupérer tous les noms de fonctions et faire un grep pour chacun de ces noms de fonctions. J'espère juste qu'il y a déjà quelque chose d'un peu plus intelligent que ça.

ETA : Veuillez noter que je n'attends pas ou ne veux pas quelque chose de parfait. Je connais mon problème de halte-proof tout aussi bien que n'importe qui (Non vraiment, j'ai enseigné la théorie du calcul, je sais quand je regarde quelque chose qui est récursivement énumérable). Toute chose qui essaie de s'en approcher en exécutant réellement le code va prendre beaucoup trop de temps. Je veux juste quelque chose qui parcourt syntaxiquement le code et dise "Cette fonction est certainement utilisée. Cette fonction POURRAIT être utilisée, et cette fonction n'est définitivement PAS utilisée, personne d'autre ne semble même savoir qu'elle existe !". Et les deux premières catégories ne sont pas importantes.

38voto

Keith Gaughan Points 5314

Vous pouvez essayer vautour . Il ne peut pas tout attraper en raison de la nature dynamique de Python, mais il en attrape une bonne partie sans avoir besoin d'une suite de tests complète comme coverage.py et d'autres pour fonctionner.

15voto

Peter Wood Points 4536

Essayez de courir Ned Batchelder 's couverture.py .

Coverage.py est un outil pour mesurer la couverture de code des programmes Python. Il surveille votre programme, notant les parties du code qui ont été exécutées, puis analyse la source pour identifier le code qui aurait pu être exécuté mais ne l'a pas été.

8voto

Sven Marnach Points 133943

Il est très difficile de déterminer quelles fonctions et méthodes sont appelées sans exécuter le code, même si le code ne fait pas de choses fantaisistes. Les invocations de fonctions simples sont plutôt faciles à détecter, mais les appels de méthodes sont vraiment difficiles. Un exemple simple :

class A(object):
    def f(self):
        pass

class B(A):
    def f(self):
        pass

a = []
a.append(A())
a.append(B())
a[1].f()

Il ne se passe rien d'extraordinaire ici, mais tout script qui tente de déterminer si A.f() o B.f() est appelé aura du mal à le faire sans exécuter réellement le code.

Bien que le code ci-dessus ne fasse rien d'utile, il utilise certainement des modèles qui apparaissent dans le code réel - à savoir mettre des instances dans des conteneurs. Le code réel fait généralement des choses encore plus complexes -- décapage et dépiquage, structures de données hiérarchiques, conditionnels.

Comme indiqué précédemment, la détection des invocations de fonctions simples de la forme

function(...)

ou

module.function(...)

sera plutôt facile. Vous pouvez utiliser le ast pour analyser vos fichiers sources. Vous devrez enregistrer toutes les importations, ainsi que les noms utilisés pour importer d'autres modules. Vous devrez également suivre les définitions de fonctions de haut niveau et les appels à l'intérieur de ces fonctions. Vous obtiendrez ainsi un graphe de dépendances, que vous pourrez utiliser comme suit NetworkX pour détecter les composantes connectées de ce graphe.

Bien que cela puisse sembler assez complexe, il est probablement possible de le faire avec moins de 100 lignes de code. Malheureusement, presque tous les grands projets Python utilisent des classes et des méthodes, donc cela ne sera pas d'une grande utilité.

6voto

Brian Postow Points 3765

Voici la solution que j'utilise, du moins provisoirement :

grep 'def ' *.py > defs
# ...
# edit defs so that it just contains the function names
# ...
for f in `cat defs` do
    cat $f >> defCounts
    cat *.py | grep -c $f >> defCounts
    echo >> defCounts
done

Ensuite, je regarde les fonctions individuelles qui ont très peu de références (< 3 say)

c'est moche, et ça ne me donne que des réponses approximatives, mais je pense que c'est suffisant pour un début. Qu'en pensez-vous ?

1voto

yedpodtrzitko Points 2427

Si votre code est couvert par de nombreux tests (ce qui est tout à fait utile), exécutez-les avec le plugin code-coverage et vous pourrez alors voir le code inutilisé ).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X