Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Du 22 au 24 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !
  1. Livres et vidéos
  2. Python et Raspberry Pi
  3. Documenter et tester ses scripts en Python
Extrait - Python et Raspberry Pi Apprenez à développer sur votre nano-ordinateur (3e édition)
Extraits du livre
Python et Raspberry Pi Apprenez à développer sur votre nano-ordinateur (3e édition)
2 avis
Revenir à la page d'achat du livre

Documenter et tester ses scripts en Python

Introduction

L’écriture de tests unitaires est désormais incontournable dans l’élaboration d’un programme informatique. Dans ce domaine, Python est livré avec des modules de choix qui répondent aux attentes des développeurs les plus ambitieux. Python offre aussi la possibilité d’inspecter son code interactivement avec le REPL, et de vérifier instantanément le contenu d’un objet, son type et les méthodes qu’il offre. Pour assister le développeur dans les tâches liées à la documentation, à l’analyse de performance et à la résolution de problèmes en rapport avec le code, la gamme des modules proposés par le langage est assez vaste. Par exemple, lorsque la taille d’un projet devient critique, l’usage de tests unitaires permet d’implémenter plus rapidement de nouvelles fonctionnalités, et de détecter les régressions de code dès le début de l’implémentation. Ce qui fait ainsi gagner du temps et de la productivité. La recherche de performance va aider le développeur à identifier les fonctions gourmandes en exécution de celles qui le sont moins, afin de procéder à de la refactorisation et/ou de la réécriture de code. Dans le cas de l’écriture de scripts destinés...

Consulter de la documentation avec pydoc3

Tout d’abord, l’outil le plus courant qui permet de chercher dans la documentation des modules porte le nom de pydoc3. L’utilisation de pydoc3 intervient lorsque l’on souhaite afficher la documentation d’un module, d’une classe ou d’un mot-clé. Par exemple, la documentation de tous les mots-clés passés en revue dans les chapitres précédents (with, def, lambda, etc.) peut être consultée avec pydoc3. Point important à noter avant d’aller plus loin : la majorité de la documentation installée avec le système par défaut de Python est écrite dans la langue anglaise. 

Cet outil s’utilise exclusivement en ligne de commande. Ouvrez une console en cliquant sur Menu - Accessoires - LXTerminal, comme expliqué au chapitre Raspberry Pi 3, premier contact. Tapez ensuite la commande :

pi@raspberrypi:~ $ pydoc3 

Ce qui devrait afficher le résultat suivant :

images/ch9_1.png

pydoc3 permet donc de chercher et d’afficher la documentation de nombreux topics ou sujets. Le sujet recherché correspond au terme passé en paramètre de la commande. Dans cet exemple, le terme with est recherché et affiche la documentation qui lui est associée :

images/ch9_2.png

Par défaut, la lecture de la documentation repose sur l’utilisation d’un programme nommé less, qui est le pager par défaut. La navigation dans less peut être difficile pour les néophytes qui débutent avec la ligne de commande. Voici un tableau rassemblant...

Documenter et tester son code en une seule fois avec le module doctest

La documentation du code est une étape essentielle lors de l’élaboration d’un programme Python. En entreprise et dans de nombreux projets open source, documenter son code est primordial car celui-ci est distribué à un très grand nombre de développeurs. Il est important que le code soit clair et compréhensible, et une bonne documentation facilite grandement cette étape. En Python, l’écriture de documentation passe par l’utilisation des docstrings. Les concepteurs du langage considèrent les docstrings tellement importantes qu’il existe même une PEP qui explique les standards d’écriture de celles-ci. PEP 0257 - Docstring Conventions, disponible à l’adresse https://www.python.org/dev/peps/pep-0257/.

Pour mieux comprendre à quoi sert une docstring, il est utile d’écrire un module contenant deux fonctions, fois_deux et fois_cinq, qui multiplient respectivement un entier par 2 ou par 5, et retournent le résultat. Jusqu’à présent, les exemples que nous avons écrits n’étaient pas documentés afin d’optimiser la place et les caractères. Ici, le module est documenté dans son intégralité (Chapitre_9/doctest_1.py) :

1 #!/usr/bin/env python3 
2 import operator 
3  
4  
5 """ Exemple issu du livre 'Développer en Python sur Raspberry Pi'. 
6  
7 Ce fichier liste certaines opérations arithmétiques de base. 
8 """ 
9  
10  
11 def int_fois_deux(x): 
12     """ 
13     Multiplie la variable x par 2 et retourne le résultat. 
14  
15     @param: x, la variable à multiplier. 
16     @return: un entier. 
17     """ 
18     return int(x * 2) 
19  
20  
21 def int_fois_cinq(x): 
22     """ 
23     Multiplie la variable x par 5 et retourne le résultat. 
24  
25     @param: x, la variable à multiplier. 
26    ...

Écriture de tests unitaires avec le module unittest

Souvent appelé PyUnit, le module unittest est une bibliothèque faisant partie de la bibliothèque standard depuis la version 2.1 du langage. Désormais incontournables, les tests unitaires sont très prisés dans le monde du développement logiciel pour la validation de code et représentent presque une discipline à part. Ce chapitre se concentre sur la présentation de la bibliothèque en négligeant cependant la méthodologie à adopter lors de l’écriture de tests unitaires. Il en existe de très nombreuses et face aux besoins en permanente évolution des entreprises, il est difficile de conseiller telle ou telle méthodologie : vaut-il mieux Agile ? TDD ? Waterflow ?

Pour en savoir davantage sur ce vaste sujet, nous vous conseillons la lecture du livre de Benoît Gantaume, JUnit - Mise en œuvre pour automatiser les tests en Java. Même si le livre se concentre sur un langage différent (Java) et un framework particulier, mais au final très proche de PyUnit (Junit), les chapitres Python : bases et concepts avancés et Documenter et tester ses scripts en Python posent certaines bases et expliquent l’intérêt d’écrire des tests unitaires ainsi que la méthodologie à adopter en fonction du projet à élaborer.

Le premier exemple de cette série reprend le même code que celui utilisé pour expliquer le module doctest (Chapitre_9/unittest_1.py) :

1 #!/usr/bin/env python3 
2 import unittest 
3 
4 
5 def int_fois_deux(x): 
6     return int(x * 2) 
7 
8 
9 def int_fois_cinq(x): 
10     return int(x * 5) 
11 
12 
13 class MyUnitTests(unittest.TestCase): 
14     @unittest.skip("non fonctionnel") 
15     def testEquals(self): 
16         self.assertEqual(int_fois_deux(2), 4) 
17         self.assertEqual(int_fois_deux(6), 12) 
18         self.assertEqual(int_fois_cinq(5), 25) 
19         self.assertEqual(int_fois_cinq(10), 50) 
20         self.assertEqual(int_fois_deux(10), 50) 
21 ...

Benchmarker son code avec le module timeit

Pour les développeurs souhaitant exploiter au maximum les ressources de Python, du Raspberry Pi et de leur code, il est possible de mesurer le temps d’exécution d’un programme avec le module timeit. Savoir de combien de temps un programme a besoin pour s’exécuter, et surtout identifier quel endroit d’un programme nécessite le plus de ressources, peut parfois permettre de gagner de précieuses secondes.

timeit peut s’utiliser de deux manières : directement depuis la ligne de commande ou chargé depuis un script. Bien que l’utilisation en ligne de commande soit séduisante à première vue, elle convient aux scripts one liners mais elle est peu adaptée lorsque le code à tester s’étale sur plusieurs lignes.

En réalité, le module ne mesure pas le temps d’exécution d’un programme en entier mais le temps d’exécution d’un bloc de code en particulier. Il est recommandé d’utiliser timeit sur de petits blocs et de se concentrer sur ce qui est le plus condensé en termes de code : une fonction.

Pour démontrer comment améliorer le temps d’exécution d’une fonction, nous allons réutiliser une fonction issue de ce chapitre, la fonction int_fois_deux() du module doctest_1.py que nous allons ensuite améliorer. Pour rappel, voici la définition de la fonction :

 1 def int_fois_deux(x): 
2     """ 
3     Multiplie la variable x par 2 et retourne le résultat. 
4  
5     @param: x, la variable à multiplier. 
6     @return: un entier. 
7     """ 
8     return int(x * 2) 

Afin de chronométrer le temps d’exécution de cette fonction, un script doit importer la fonction en question depuis le fichier module doctest_1.py. Le benchmarking se déroule de la manière suivante (Chapitre_9/timeit_1.py) :

1 #!/usr/bin/env...

Déboguer ses programmes avec le module pudb

Que faire lorsque le programme écrit ne se comporte pas comme prévu ? La solution la plus simple consiste à déboguer le programme, c’est-à-dire à basculer dans une console permettant d’exécuter le programme, à dépiler chaque appel de fonction, étape par étape, et à interroger le contenu de chaque variable jusqu’à arriver à l’appel ou la variable qui pose problème. Les deux débogueurs les plus connus sont pdb (Python DeBugger) et pudb (Python Urwid DeBugger).

Le module pudb est plus intuitif et surtout interactif par rapport au module pdb. En effet, pudb propose de dépiler un programme étape par étape, à la manière d’un débogueur traditionnel C++ ou Java, de configurer des points de contrôle et d’analyser les valeurs contenues dans les différentes variables du programme.

Attention. le module pudb ne fait pas partie de la bibliothèque standard. Vous devez d’abord l’installer avec la commande suivante : sudo pip3 install pudb.

Essayons le module pudb avec le programme suivant (Chapitre_9/pudb_1.py) :

1 #!/usr/bin/env python3 
2 def explosion(arg="kaboom!", elem=1): 
3     elem = elem + 1 
4     raise Exception(arg) 
5 
6 
7 def main(): ...

Conclusion

Ce chapitre explique comment documenter, tester, déboguer et mesurer la performance de son code à travers l’utilisation de quatre modules qui sont doctest, unittest, pudb et timeit. L’outil standard pour lire de la documentation en Python, pydoc3, est aussi passé en revue.