Est-ce que cet outil existe en Python ? 13


Le test unitaire le plus simple, c’est de vérifier que son API publique n’a pas changé.

Ça veut dire :

  • vérifier que les modules ont bien les mêmes définitions (un nom qui était importable n’a pas disparu).
  • vérifier que les fonctions et méthodes ont bien la même signature (les arguments avec le même nom n’ont pas changé de place, et les keywords arguments n’ont pas changé de nom).
  • vérifier que les classes ont le même nom, les mêmes méthodes publiques avec les mêmes signatures et les mêmes attributs.

Ce sont des tests super cons qui demandent d’écrire du code du genre :

class Foo:
    bar = True
    def __init__(self, stuff=False):
        self.stuff
 
    def thing(self):
        return "doh"
 
# et dans les tests
self.assertTrue(hasattr(Foo, 'bar'))
self.assertTrue(hasattr(Foo, 'thing'))
self.assertTrue(hasattr(Foo(), 'stuff'))

Et personne ne le fait, car déjà les tests c’est relou, mais écrire des tautologies à la main, c’est au dela du tolérable.

Pourtant, ce genre de tests m’aurait déjà sauvé les gosses plusieurs fois. Une faute de frappe qui se glisse, un attribut qu’on rend privé, un méthode qu’on déplace et on pense avoir tout refactoré, un pote qui change un truc qu’on utilisait, etc.

Je me demandais donc si il existait un truc qui permette de faire :

self.assertStablePublicAPI("package.module") # scanne tout le module et tous les objets
self.assertStablePublicAPI("package.module:Class") # check juste la classe
self.assertStablePublicAPI("package.module:func") # check juste la function

Le but étant que quand on lance les test, ça check si ça rencontre un nouvel objet/attribut/param et sauvegarde tout un dans un JSON. Aux prochains tests, si on a modifier l’API publique, le test foire jusqu’à ce qu’on modifie explicitement le fichier JSON.

On doit bien entendu pouvoir régler le truc pour ignorer ou ajouter explicitement des choses à checker, par exemple par défaut ça ignore tous les machins avec des underscores dans le nom.

J’ai cherché sur le net, mais j’arrive pas à trouver ça. Des pistes ?

13 thoughts on “Est-ce que cet outil existe en Python ?

  • fpp

    Je ne sais pas, mais ce serait un générateur de “tautologies” :-)

  • romgar

    J’avais commencé à utiliser une sorte d’introspection pour récupérer toutes les classes/fonctions disponibles dans Django, afin, a partir d’un nom, de déterminer le package a importer (https://github.com/romgar/django-import-seeker/blob/master/introspection.py, exemple d’utilisation sur http://djangois.youkidea.com). a la maniere d’un IDE qui importe automatiquement a partir d’un nom.

    On ne serait pas si loin de ce que tu cherches non ? sauf que pour l’instant ça ne récupère que les classes/fonctions disponibles.

  • Sam Post author

    Ca fait un l’inverse non ? Prend une classe, et trouve un sous module d’un module qui le contient.

  • Xavier Combelle

    Ca ressemble à un analyseur statique de code (genre pylint/pyflake) mais à l’envers

  • Sam Post author

    Ah, voilà une initiative sympas. Je vais de ce pas ouvrir des tickets.

    EDIT : done. Y a moyen de faire un beau projet là.

  • apeyrard

    Bon, ben voila le post qui m’aura finalement fait commenter ce blog.

    Super initiative ! Je vais de ce pas forker ça !

  • romgar

    @Sam le concept global oui c’est l’inverse, mais la recherche pour savoir si la classe est présente utilise une introspection (assez basique) pour récupérer les classes/fonctions disponibles. Enfin bref, rien de miraculeux, mais j’aime bien l’idée de test de l’API, je vais creuser aussi.

  • Sam Post author

    Ouai, j’ai vu, mais d’après ce que j’ai compris, ça prend toutes les classes et les fonctions du module, donc ça implique aussi les trucs importés dans le module ce qui est probablement pas ce qu’on veut. A mon avis il faudra utiliser le parseur ast pour obtenir ces infos, car difficile de filter un from bidule import * autrement.

  • tsez

    Je suis étonné que personnne n’ai parlé de PyCharm. Il détecte ce genre d’erreur avec coloration syntaxique. Avec PyCharm, je ne me pose plus de questions sur les types, attributs, etc

    Inutile d’exécuter le code Python pour détecter les erreurs.

    Inutile de créer des tests unitaires de ce type.

    Il existe sans doute des cas d’erreur que PyCharm ne détecte pas mais je ne les ai pas encore rencontré.

    Le seul défaut que je lui trouve est le besoin d’une machine puissante, et encore on peut désactiver l’inspection de code automatique pour le lancer à la demande.

  • Sam Post author

    @tsez, commes les commentaires précédents sur le typage, tu passes à côté du problème. En effet, si tu modifies ton API publique et que tout ton code suit cette modification, pycharm ne lèvera aucune erreur. Tout ira bien pour lui car ton programme marchera très bien. Mais tu auras quand même cassé ton API publique, et donc tous les codes tierces partie qui utilise ton code. De plus, et même si on ne parle que de ton propre code, il suffit qu’une partie du projet qui utilise ce code ne soit pas ouvert pour que PyCharm n’y voit que du feu.

  • cladmi

    Je viens d’avoir exactement ce problème sur des applis que je développe.

    J’ai ajouté une fonctionnalité à un package ‘lib’ et “réorganisé” pour mettre dans un module commun des fonction partagées.

    Sauf que j’ai un package qui utilisait cette lib et utilisait cette fonction. Les tests n’ont rien vus parce que je testait avec la version ‘master’ de la lib, ça a pété après déploiement sur le serveur de test.

    Même si je “savais” que bouger ça allait avoir un impact, aucun outil ne m’a confirmé “fais gaffe tu casses tout là”.

Leave a comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.