Dans la partie précédente, vous avez obtenu un script Python généré par une IA. Ce script est fonctionnel, mais il ne respecte pas forcement les standards modernes de développement logiciel. Votre mission est de le mettre aux normes en appliquant les bonnes pratiques en développement logiciel : environnement reproductible, qualité du code, sécurité, tests, et documentation.
À la fin du TP, votre projet devra pouvoir être repris par n'importe quel développeur et exécuté de façon fiable, sûre et documentée.
- Avoir installé pixi sur votre machine
- Avoir un compte GitHub
Avant de commencer, prenez quelques minutes pour :
- Identifier les dépendances utilisées (imports)
- Repérer les problèmes évidents :
- absence de typage, docstrings manquantes, noms de variables peu explicites, absence de gestion d'erreurs, etc.
Note : Ne modifiez pas encore le code. Cette étape est une phase d'observation.
L'objectif est de garantir que n'importe qui puisse exécuter votre projet dans les mêmes conditions, quelle que soit sa machine. Dans ce TP, nous allons utiliser Pixi.
pixi initCette commande crée un fichier pixi.toml à la racine du projet.
Ajoutez les dépendances nécessaires à votre script. Par exemple, si votre script utilise pandas et requests :
pixi add python pandas requestsAjoutez également les outils de développement dans un environnement dédié :
pixi add --feature dev ruff pyright pytest pytest-cov safety trivy[environments]
default = { features = ["default"] }
dev = { features = ["default", "dev"] }Vérification : Supprimez votre environnement local et relancez
pixi install. Le projet doit fonctionner sans aucune installation manuelle supplémentaire.
Pixi utilise un fichier pyproject.toml pour centraliser la configuration des outils. Créez-le ou enrichissez-le avec les sections suivantes.
[project]
name = "mon-projet"
version = "0.1.0"
description = "Description courte du script"
authors = [{ name = "Prénom Nom", email = "email@exemple.fr" }]
readme = "README.md"
license = { text = "MIT" }
requires-python = ">=3.10"
keywords = ["bioinformatique", "données", "automatisation"][tool.ruff]
line-length = 88
target-version = "py310"
[tool.ruff.lint]
select = ["E", "F", "W", "I", "D", "N"]
ignore = ["D203", "D212"]
[tool.ruff.lint.pydocstyle]
convention = "numpy"[tool.pyright]
pythonVersion = "3.10"
typeCheckingMode = "basic"[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "--cov=. --cov-report=term-missing --cov-report=xml"Le typage statique permet de détecter des erreurs avant l'exécution du code.
Ajoutez des annotations de types à toutes les fonctions du script :
Avant (généré par IA, sans types)
def process_data(data, threshold):
results = []
for item in data:
if item > threshold:
results.append(item)
return resultsAprès (avec types)
def process_data(data: list[float], threshold: float) -> list[float]:
"""Filtre les éléments supérieurs au seuil donné.
Args:
data: Liste de valeurs numériques à filtrer.
threshold: Seuil de filtrage.
Returns:
Liste des éléments strictement supérieurs au seuil.
"""
results: list[float] = []
for item in data:
if item > threshold:
results.append(item)
return resultspixi run -e dev pyright script.pyCorrigez toutes les erreurs remontées avant de passer à l'étape suivante.
Ruff est un linter et un formateur ultra-rapide pour Python. Il remplace à lui seul Black, isort, flake8 et pydocstyle.
pixi run -e dev ruff check .pixi run -e dev ruff check --fix .pixi run -e dev ruff format .Ruff ne peut pas tout corriger automatiquement. Vérifiez que :
- Chaque fonction dispose d'une docstring au format Nympy
- Les noms de variables sont explicites (
df→dataframe_resultats,x→valeur_seuil) - Aucun
# type: ignoren'est utilisé sans justification commentée
Vérification :
ruff check .doit se terminer sans aucune erreur ni avertissement.
Safety vérifie si vos dépendances ont des vulnérabilités connues (CVE).
pixi run -e dev safety check - Aucune vulnérabilité : vous pouvez passer à la suite
- Vulnérabilités détectées : mettez à jour les packages concernés dans
pixi.tomlen spécifiant une version corrigée
pixi add "pandas>=2.1.0" # exemple si pandas <2.1.0 est vulnérableLivrable : Capture d'écran ou sortie de
safety checksans vulnérabilité critique.
Trivy analyse le code source et les fichiers de configuration pour détecter des secrets exposés, des mauvaises configurations ou des dépendances vulnérables.
trivy fs --scanners secret,vuln,misconfig .- Secrets exposés : clés API, mots de passe, tokens dans le code ou dans les fichiers de config
- Vulnérabilités dans les dépendances (croisement avec Safety)
- Mauvaises configurations : fichiers Docker, CI, etc.
Si Trivy détecte des secrets dans le code :
- Supprimez-les immédiatement du code
- Utilisez des variables d'environnement ou un fichier
.env(ajouté au.gitignore) - Si le secret a déjà été commité, utilisez
git filter-repopour purger l'historique
# Mauvaise pratique
API_KEY = "sk-abc123xyz"
# Bonne pratique
import os
API_KEY = os.environ.get("API_KEY")Livrable : Sortie de Trivy sans vulnérabilité critique ni secret exposé.
Les tests garantissent que votre code fait ce qu'il est censé faire et continuera de le faire après des modifications.
projet/
├── script.py
├── tests/
│ ├── __init__.py
│ └── test_script.py
Pour chaque fonction du script, écrivez au minimum :
- Un test avec des données nominales (cas normal)
- Un test avec des valeurs limites (liste vide, zéro, valeur négative…)
- Un test vérifiant qu'une exception est levée si les entrées sont invalides
# tests/test_script.py
import pytest
from script import process_data
def test_process_data_nominal() -> None:
"""Vérifie le comportement nominal de process_data."""
result = process_data([1.0, 5.0, 3.0], threshold=2.0)
assert result == [5.0, 3.0]
def test_process_data_empty_list() -> None:
"""Vérifie que process_data gère une liste vide."""
result = process_data([], threshold=2.0)
assert result == []
def test_process_data_all_below_threshold() -> None:
"""Vérifie qu'aucun élément n'est retourné si tous sont sous le seuil."""
result = process_data([0.5, 1.0, 1.9], threshold=2.0)
assert result == []
def test_process_data_invalid_input() -> None:
"""Vérifie qu'une erreur est levée pour une entrée invalide."""
with pytest.raises(TypeError):
process_data("pas une liste", threshold=2.0) # type: ignore[arg-type]pixi run -e dev pytestLa couverture mesure quelle proportion du code est exercée par vos tests.
pixi run -e dev pytest --cov=. --cov-report=term-missing---------- coverage: platform linux, python 3.10 ----------
Name Stmts Miss Cover Missing
-----------------------------------------
script.py 42 6 86% 45, 67-72
-----------------------------------------
TOTAL 42 6 86%
- Les lignes listées sous "Missing" ne sont pas couvertes par les tests
- Ajoutez des tests pour couvrir ces cas
Objectif minimum : 80% de couverture sur
script.py.
pixi run -e dev pytest --cov=. --cov-report=html
# Ouvrir htmlcov/index.html dans un navigateurPixi permet de définir des commandes personnalisées pour centraliser et documenter les tâches courantes du projet.
[feature.dev.tasks]
lint = "ruff check ."
format = "ruff format ."
typecheck = "pyright script.py"
safety-check = "safety check -r requirements.txt"
test = "pytest"
coverage = "pytest --cov=. --cov-report=term-missing"
all-checks = { depends-on = ["lint", "typecheck", "test"] }pixi run lint # Lancer le linter
pixi run format # Formater le code
pixi run typecheck # Vérifier les types
pixi run test # Lancer les tests
pixi run coverage # Tests + couverture
pixi run all-checks # Tout en une commandeVérification :
pixi run all-checksdoit se terminer sans erreur.
Le README est le premier document qu'un utilisateur ou un développeur lit. Il doit permettre de comprendre et d'utiliser le projet en quelques minutes.
# Nom du projet
Description courte (1-2 phrases) de ce que fait le script.
## Prérequis
- [Pixi](https://pixi.sh) installé
- Python 3.10+
## Installation
```bash
git clone https://github.com/votre-compte/votre-projet.git
cd votre-projet
pixi installpixi run python script.py --input data.csv --output results.csv| Commande | Description |
|---|---|
pixi run lint |
Vérification de la qualité du code |
pixi run format |
Formatage automatique |
pixi run typecheck |
Vérification du typage |
pixi run test |
Lancement des tests unitaires |
pixi run coverage |
Rapport de couverture de tests |
pixi run all-checks |
Tous les contrôles en une commande |
.
├── script.py # Script principal
├── tests/ # Tests unitaires
├── pyproject.toml # Configuration des outils
├── pixi.toml # Environnement et dépendances
└── README.md # Ce fichier| Étape | Livrable attendu |
|---|---|
| 1 | pixi.toml avec dépendances de prod et de dev |
| 2 | pyproject.toml avec sections ruff, pyright, pytest |
| 3 | Code annoté, pyright sans erreur |
| 4 | ruff check . et ruff format . sans erreur |
| 5 | safety check sans vulnérabilité critique |
| 6 | trivy fs . sans secret exposé ni vulnérabilité critique |
| 7 | Suite de tests couvrant les cas nominaux et limites |
| 8 | Couverture ≥ 80% sur le script principal |
| 9 | Commandes Pixi fonctionnelles (pixi run all-checks passe) |
| 10 | README complet permettant de lancer le projet from scratch |