TP : Créer son premier package Python — MathTools
Thème : Modularité, documentation et tests
Contexte
En 2026, Python reste le langage le plus populaire au monde grâce à son écosystème de packages. Des millions de développeurs partagent leur code via PyPI (Python Package Index).
Dans ce TP, vous allez créer votre propre mini-package : une bibliothèque d'outils mathématiques appelée MathTools. Vous apprendrez à : - Structurer un projet en modules - Documenter proprement avec des docstrings - Tester automatiquement avec doctest - Créer un point d'entrée principal
Partie 1 : Structure du projet
Organisation des fichiers
Créez la structure de dossiers suivante :
Le fichier __init__.py
Ce fichier spécial indique à Python que le dossier est un package. Il peut rester vide ou contenir des imports.
# mathtools/__init__.py
"""
MathTools - Une bibliothèque d'outils mathématiques.
Modules disponibles :
- geometrie : calculs géométriques (aire, périmètre, volume)
- statistiques : calculs statistiques (moyenne, médiane, écart-type)
- conversion : conversions d'unités (température, distance, poids)
"""
__version__ = "1.0.0"
__author__ = "Votre Nom"
Partie 2 : Module géométrie
Exercice 1 : Créer le module geometrie.py
Implémentez les fonctions suivantes avec leur docstring et doctest :
# mathtools/geometrie.py
"""Module de calculs géométriques."""
import math
import doctest
def aire_rectangle(longueur, largeur):
"""
Calcule l'aire d'un rectangle.
:param longueur: (float) la longueur du rectangle
:param largeur: (float) la largeur du rectangle
:return: (float) l'aire du rectangle
:CU: longueur > 0 et largeur > 0
Exemple:
>>> aire_rectangle(5, 3)
15
>>> aire_rectangle(2.5, 4)
10.0
"""
# À compléter
pass
def aire_cercle(rayon):
"""
Calcule l'aire d'un cercle.
:param rayon: (float) le rayon du cercle
:return: (float) l'aire du cercle
:CU: rayon > 0
Exemple:
>>> round(aire_cercle(1), 4)
3.1416
>>> round(aire_cercle(2), 4)
12.5664
"""
# À compléter
pass
def perimetre_rectangle(longueur, largeur):
"""
Calcule le périmètre d'un rectangle.
Exemple:
>>> perimetre_rectangle(5, 3)
16
"""
# À compléter (ajoutez la docstring complète)
pass
def volume_sphere(rayon):
"""
Calcule le volume d'une sphère.
Formule : V = (4/3) * π * r³
Exemple:
>>> round(volume_sphere(1), 4)
4.1888
"""
# À compléter (ajoutez la docstring complète)
pass
def hypotenuse(a, b):
"""
Calcule l'hypoténuse d'un triangle rectangle.
Utilise le théorème de Pythagore : c² = a² + b²
Exemple:
>>> hypotenuse(3, 4)
5.0
>>> hypotenuse(5, 12)
13.0
"""
# À compléter
pass
if __name__ == "__main__":
doctest.testmod(verbose=True)
Partie 3 : Module statistiques
Exercice 2 : Créer le module statistiques.py
# mathtools/statistiques.py
"""Module de calculs statistiques."""
import doctest
def moyenne(liste):
"""
Calcule la moyenne d'une liste de nombres.
:param liste: (list) une liste de nombres
:return: (float) la moyenne
:CU: liste non vide
Exemple:
>>> moyenne([10, 20, 30])
20.0
>>> moyenne([15, 18, 12, 9])
13.5
"""
# À compléter
pass
def mediane(liste):
"""
Calcule la médiane d'une liste de nombres.
La médiane est la valeur centrale d'une liste triée.
:param liste: (list) une liste de nombres
:return: (float) la médiane
:CU: liste non vide
Exemple:
>>> mediane([1, 2, 3, 4, 5])
3
>>> mediane([1, 2, 3, 4])
2.5
"""
# À compléter
pass
def variance(liste):
"""
Calcule la variance d'une liste de nombres.
Variance = moyenne des carrés des écarts à la moyenne.
Exemple:
>>> variance([2, 4, 4, 4, 5, 5, 7, 9])
4.0
"""
# À compléter
pass
def ecart_type(liste):
"""
Calcule l'écart-type d'une liste de nombres.
Écart-type = racine carrée de la variance.
Exemple:
>>> ecart_type([2, 4, 4, 4, 5, 5, 7, 9])
2.0
"""
# À compléter
pass
def minimum(liste):
"""
Retourne le minimum d'une liste (sans utiliser min()).
Exemple:
>>> minimum([5, 2, 8, 1, 9])
1
"""
# À compléter
pass
def maximum(liste):
"""
Retourne le maximum d'une liste (sans utiliser max()).
Exemple:
>>> maximum([5, 2, 8, 1, 9])
9
"""
# À compléter
pass
if __name__ == "__main__":
doctest.testmod(verbose=True)
Partie 4 : Module conversion
Exercice 3 : Créer le module conversion.py
# mathtools/conversion.py
"""Module de conversions d'unités."""
import doctest
# --- Températures ---
def celsius_vers_fahrenheit(celsius):
"""
Convertit des degrés Celsius en Fahrenheit.
Formule : F = C × 9/5 + 32
Exemple:
>>> celsius_vers_fahrenheit(0)
32.0
>>> celsius_vers_fahrenheit(100)
212.0
>>> celsius_vers_fahrenheit(-40)
-40.0
"""
# À compléter
pass
def fahrenheit_vers_celsius(fahrenheit):
"""
Convertit des degrés Fahrenheit en Celsius.
Formule : C = (F - 32) × 5/9
Exemple:
>>> fahrenheit_vers_celsius(32)
0.0
>>> fahrenheit_vers_celsius(212)
100.0
"""
# À compléter
pass
# --- Distances ---
def km_vers_miles(km):
"""
Convertit des kilomètres en miles.
1 mile = 1.60934 km
Exemple:
>>> round(km_vers_miles(10), 2)
6.21
"""
# À compléter
pass
def miles_vers_km(miles):
"""
Convertit des miles en kilomètres.
Exemple:
>>> round(miles_vers_km(10), 2)
16.09
"""
# À compléter
pass
# --- Poids ---
def kg_vers_livres(kg):
"""
Convertit des kilogrammes en livres.
1 livre = 0.453592 kg
Exemple:
>>> round(kg_vers_livres(1), 2)
2.2
"""
# À compléter
pass
# --- Informatique ---
def octets_vers_kilo(octets):
"""
Convertit des octets en kilooctets (1 Ko = 1024 octets).
Exemple:
>>> octets_vers_kilo(2048)
2.0
"""
# À compléter
pass
def bits_vers_octets(bits):
"""
Convertit des bits en octets (1 octet = 8 bits).
Exemple:
>>> bits_vers_octets(64)
8.0
"""
# À compléter
pass
if __name__ == "__main__":
doctest.testmod(verbose=True)
Partie 5 : Programme principal
Exercice 4 : Créer main.py
Ce fichier sera le point d'entrée de votre package. Il propose un menu interactif.
# mathtools/main.py
"""Programme principal de MathTools."""
from geometrie import *
from statistiques import *
from conversion import *
def menu():
"""Affiche le menu principal."""
print("\n" + "=" * 40)
print(" MATHTOOLS v1.0.0")
print("=" * 40)
print("1. Géométrie")
print("2. Statistiques")
print("3. Conversions")
print("0. Quitter")
print("=" * 40)
def menu_geometrie():
"""Sous-menu géométrie."""
print("\n--- GÉOMÉTRIE ---")
print("1. Aire d'un rectangle")
print("2. Aire d'un cercle")
print("3. Hypoténuse")
print("0. Retour")
choix = input("Votre choix : ")
if choix == "1":
l = float(input("Longueur : "))
L = float(input("Largeur : "))
print(f"Aire = {aire_rectangle(l, L)}")
elif choix == "2":
r = float(input("Rayon : "))
print(f"Aire = {round(aire_cercle(r), 4)}")
elif choix == "3":
a = float(input("Côté a : "))
b = float(input("Côté b : "))
print(f"Hypoténuse = {hypotenuse(a, b)}")
def menu_statistiques():
"""Sous-menu statistiques."""
print("\n--- STATISTIQUES ---")
print("Entrez vos valeurs séparées par des espaces :")
valeurs = input("> ")
liste = [float(x) for x in valeurs.split()]
print(f"Moyenne : {moyenne(liste)}")
print(f"Médiane : {mediane(liste)}")
print(f"Min : {minimum(liste)}")
print(f"Max : {maximum(liste)}")
def menu_conversions():
"""Sous-menu conversions."""
print("\n--- CONVERSIONS ---")
print("1. Celsius → Fahrenheit")
print("2. Fahrenheit → Celsius")
print("3. Km → Miles")
print("0. Retour")
choix = input("Votre choix : ")
if choix == "1":
c = float(input("Température en °C : "))
print(f"{c}°C = {celsius_vers_fahrenheit(c)}°F")
elif choix == "2":
f = float(input("Température en °F : "))
print(f"{f}°F = {fahrenheit_vers_celsius(f)}°C")
elif choix == "3":
km = float(input("Distance en km : "))
print(f"{km} km = {round(km_vers_miles(km), 2)} miles")
def main():
"""Boucle principale."""
while True:
menu()
choix = input("Votre choix : ")
if choix == "1":
menu_geometrie()
elif choix == "2":
menu_statistiques()
elif choix == "3":
menu_conversions()
elif choix == "0":
print("Au revoir !")
break
else:
print("Choix invalide.")
if __name__ == "__main__":
main()
Partie 6 : Tests et validation
Exercice 5 : Tester tous les modules
Exécutez chaque module pour vérifier que tous les doctests passent :
Tous les tests doivent afficher ok.
Exercice 6 : Utiliser le package
Dans un nouveau fichier test_mathtools.py situé en dehors du dossier mathtools :
# test_mathtools.py
from mathtools.geometrie import aire_cercle, hypotenuse
from mathtools.statistiques import moyenne, ecart_type
from mathtools.conversion import celsius_vers_fahrenheit
# Tests
print("Aire cercle r=5 :", round(aire_cercle(5), 2))
print("Hypoténuse 3,4 :", hypotenuse(3, 4))
print("Moyenne [10,20,30] :", moyenne([10, 20, 30]))
print("20°C en Fahrenheit :", celsius_vers_fahrenheit(20))
Bonus : Documentation avancée
Générer une documentation HTML
Installez pydoc (inclus avec Python) et générez la doc :
Cela génère des fichiers HTML consultables dans un navigateur.
Ajouter des assertions
Améliorez vos fonctions avec des vérifications :
def aire_cercle(rayon):
assert rayon > 0, "Le rayon doit être strictement positif"
return math.pi * rayon ** 2
Résumé des notions
| Concept | Application dans ce TP |
|---|---|
| Module | Fichier .py contenant des fonctions |
| Package | Dossier avec __init__.py |
| Import | from module import fonction |
| Docstring | Documentation des fonctions |
| Doctest | Tests dans la documentation |
__name__ |
Permet d'exécuter un module seul |
Pour aller plus loin
- pytest : Framework de tests plus puissant que doctest
- Sphinx : Générateur de documentation professionnelle
- PyPI : Publier son package pour le monde entier
- pip : Installer des packages depuis PyPI
Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster
Licence CC BY NC
Ce cours est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International.