Module : Vibe-Coding / Claude Code / Notebooks CLI Niveau : Avance Duree : 30 min Prerequis : Notebooks 01-04 completes
Objectifs d’Apprentissage
Pourquoi automatiser avec Claude CLI ? - Repetabilite : Mêmes analyses appliquees systematiquement a tout un projet - Integration CI/CD : Revues de code automatiques avant merge - Scalabilite : Traitement de centaines de fichiers sans intervention manuelle - Coherence : Mêmes critères appliques a chaque revue
Architecture d’automatisation typique :
Declencheur (git hook, CI, cron)
|
v
Script Python/Bash
|
v
Claude CLI (subprocess)
|
v
Sortie structuree (JSON/Markdown)
|
v
Action (commit, notification, rapport)
La sortie Claude CLI pret: True confirme que l’environnement est correctement configuré pour interagir avec l’API Claude. Cette vérification préalable évite les erreurs de configuration avant d’exécuter des appels API.
Prérequis d’environnement d’exécution : ce notebook invoque réellement la CLI Claude via helpers/claude_cli.py (sys.path.insert(0, 'helpers') est fait par la cellule de configuration — l’import réussit, aucune ModuleNotFoundError n’est attendue). La précondition est une CLI claudeinstallée, exécutable et authentifiée : verify_installation() teste désormais l’exécutabilité réelle (claude --version) et non la seule présence sur le PATH. Rien n’est simulé (SIMULATION_MODE = False) : les pipelines et revues ci-dessous produisent de vraies réponses, avec leurs durées réelles. Les cellules d’exercice, elles, restent des stubs à compléter (# TODO etudiant) — leurs sorties None sont l’état pédagogique attendu.
2. Pipelines avec Subprocess
Les pipelines permettent de chainer des opérations Claude pour des workflows complexes :
Decomposition : Chaque étape est specialisee et testable independamment
Flexibilite : Facile d’ajouter/supprimer des étapes
Tracabilite : Résultats intermediaires conserves pour debug
Considerations importantes
Attention au cout API
Chaque étape = un appel API. Un pipeline de 3 étapes sur 10 fichiers = 30 appels. Utilisez haiku pour les étapes intermediaires et sonnet pour l’étape finale si qualite requise.
def create_pipeline(*steps, timeout=180):""" Cree un pipeline de prompts Claude. Args: steps: Liste de tuples (nom, prompt_template) timeout: Timeout en secondes par appel Claude (les etapes de synthese sur un resultat deja long depassent facilement 60 s). Returns: Fonction qui execute le pipeline. """def execute(initial_input): current_data = initial_input results = []for step_name, prompt_template in steps: prompt = prompt_template.format(input=current_data) stdout, stderr, code = run_claude(prompt, model="haiku", timeout=timeout)if code !=0:return {"error": f"Etape '{step_name}' echouee", "stderr": stderr} results.append({"step": step_name, "output": stdout}) current_data = stdoutreturn {"success": True, "results": results, "final_output": current_data}return executeprint("Fonction create_pipeline definie")
Fonction create_pipeline definie
✓ Lecture ancrée — Pipeline de prompts
La fonction create_pipeline permet de chaîner plusieurs étapes de traitement via des prompts Claude. Chaque étape produit un résultat intermédiaire qui est passé à l’étape suivante, créant ainsi un flux de traitement structuré.
Utilisation du pipeline
La cellule suivante créé un pipeline concret de revue de code en 3 étapes. Le pipeline est instancie avec create_pipeline défini ci-dessus : chaque argument est un tuple (nom, template) ou {input} sera remplace par le résultat de l’étape précédente.
# Exemple de pipeline : Analyse → Resume → Ameliorationscode_review_pipeline = create_pipeline( ("analyse", "Analyse ce code et liste ses caracteristiques principales:\n{input}"), ("resume", "Resume cette analyse en 3 points cles:\n{input}"), ("ameliorations", "Propose 2 ameliorations basees sur ce resume:\n{input}"))print("Pipeline de revue de code defini")
Pipeline de revue de code defini
✓ Lecture ancrée — Pipeline de revue de code
Le pipeline code_review_pipeline est configuré avec 3 étapes : analyse du code, résumé en 3 points clés, puis proposition de 2 améliorations. Cette structure en cascade permet une revue de code progressive et complète.
Comment fonctionne ce pipeline ?
La fonction create_pipeline encapsule un schema de traitement classique en 3 phases :
Analyse : Claude identifie les caractéristiques du code (structure, patterns, anti-patterns)
Synthese : Un second appel resume les points essentiels (filtrage du bruit)
Action : Un troisieme appel genere des recommandations concretes
Point cle : chaque étape recoit le résultat de la précédente dans {input}. Cela créé une chaîne de raffinement progressif. Le choix du modèle haiku pour les étapes intermediaires reduit le cout tout en conservant la coherence.
Attention au contexte : le résultat de chaque étape est passe entierement a la suivante. Si une étape produit une sortie trop longue, les étapes suivantes manqueront de contexte. Pour des analyses complexes, utilisez des prompts plus directifs a chaque étape.
# Test du pipeline (3 appels API reels)sample_code ='''def process_data(items): result = [] for item in items: if item > 0: result.append(item * 2) return result'''output = code_review_pipeline(sample_code)if output.get("success"):for r in output["results"]:print(f"\n=== {r['step'].upper()} ===")print(r['output'][:300])else:print(f"Pipeline en echec: {output.get('error')} / {output.get('stderr')}")
=== ANALYSE ===
Cette fonction `process_data` traite une liste d'éléments :
**Caractéristiques principales :**
- **Signature** : prend un seul argument `items` (itérable/liste)
- **Filtre** : ne conserve que les éléments strictement positifs (`item > 0`)
- **Transformation** : double chaque élément retenu (`item
=== RESUME ===
Voici le résumé en 3 points clés :
1. **Fonction pure, filtre + transformation** — `process_data(items)` retourne une **nouvelle liste** sans mutation ni effet de bord : il double (`*2`) chaque élément strictement positif (`> 0`), et ignore silencieusement zéros, négatifs et non-nombres.
2. **Aucu
=== AMELIORATIONS ===
Deux améliorations — la première est en fait un correctif d'incohérence entre les points 1 et 3 du résumé.
**1. Rendre le filtre réellement insensible aux non-nombres**
La compréhension du point 3 ne tient pas la promesse du point 1. Sur `["a", 1, -2, 0]`, l'expression `item > 0` lève `TypeError`
✓ Lecture ancrée — Exécution du pipeline
L’exécution du pipeline sur l’exemple process_data produit une analyse complète avec : - ANALYSE : identification des caractéristiques principales (signature, filtre, transformation) - RESUME : synthèse en 3 points clés de la fonction - AMELIORATIONS : suggestions concrètes basées sur l’analyse. Les 3 appels API sont exécutés séquentiellement pour construire cette analyse.
3. Integration Scripts Shell
Claude Code peut etre integre dans des scripts Bash ou PowerShell pour des workflows système.
Note syntaxe : Les $ dans les exemples ci-dessous sont des variables shell standard (Bash/PowerShell), pas du formatage special.
Exemple Bash (Linux/macOS/WSL)
#!/bin/bash# Script de revue automatiqueFILE=$1# Premier argument = fichierREVIEW=$(claude-p"Revue de code pour: $(cat$FILE)")# Exécution Claudeecho"$REVIEW">"${FILE}.review.md"# Sauvegarde résultat
Exemple PowerShell (Windows)
# Analyse de tous les fichiers Python du repertoire courantGet-ChildItem-Filter *.py|ForEach-Object{$content=Get-Content$_.FullName-Raw # Lecture fichier entier$review= claude -p "Resume ce fichier: $content"$review|Out-File"$($_.BaseName).review.md"}
Bonnes pratiques scripts
Pratique
Raison
Toujours verifier le code de retour
Detecter les echecs Claude
Utiliser des quotes doubles
Preserver les espaces dans le code
Limiter la taille du contenu
Eviter les timeouts sur gros fichiers
Logger les appels
Debug et audit
# Generer un script de revue automatiquebash_script ='''#!/bin/bash# Script de revue de code automatique avec ClaudeFILE="$1"if [ -z "$FILE" ]; then echo "Usage: $0 <fichier.py>" exit 1fiif [ ! -f "$FILE" ]; then echo "Fichier non trouve: $FILE" exit 1fiecho "Analyse de $FILE..."CONTENT=$(cat "$FILE")REVIEW=$(claude -p "Effectue une revue de code pour ce fichier Python. Identifie: bugs potentiels, problemes de style, ameliorations possibles.Code:$CONTENT")OUTPUT="${FILE%.py}.review.md"echo "# Code Review: $FILE" > "$OUTPUT"echo "" >> "$OUTPUT"echo "$REVIEW" >> "$OUTPUT"echo "Revue sauvegardee dans: $OUTPUT"'''print(bash_script)
#!/bin/bash
# Script de revue de code automatique avec Claude
FILE="$1"
if [ -z "$FILE" ]; then
echo "Usage: $0 <fichier.py>"
exit 1
fi
if [ ! -f "$FILE" ]; then
echo "Fichier non trouve: $FILE"
exit 1
fi
echo "Analyse de $FILE..."
CONTENT=$(cat "$FILE")
REVIEW=$(claude -p "Effectue une revue de code pour ce fichier Python.
Identifie: bugs potentiels, problemes de style, ameliorations possibles.
Code:
$CONTENT")
OUTPUT="${FILE%.py}.review.md"
echo "# Code Review: $FILE" > "$OUTPUT"
echo "" >> "$OUTPUT"
echo "$REVIEW" >> "$OUTPUT"
echo "Revue sauvegardee dans: $OUTPUT"
✓ Lecture ancrée — Script Bash de revue
Le script génère un fichier de revue au format Markdown à partir d’un appel CLI à Claude. Il prend en entrée un fichier Python et produit un rapport structuré avec l’analyse complète du code.
Version Python equivalente
La cellule suivante reecrit le même script de revue automatique en Python. La version Python offre une meilleure gestion d’erreurs (Path.exists(), codes de retour), une portabilite cross-plateforme, et la possibilite de traiter les résultats programmatiquement (JSON, rapports structures). Comparez les deux approches : le Bash est plus concis pour les scripts simples, le Python plus robuste pour les pipelines complexes.
# Version Python equivalentedef auto_review(filepath):"""Effectue une revue de code automatique.""" path = Path(filepath)ifnot path.exists():return {"error": f"Fichier non trouve: {filepath}"} content = path.read_text() stdout, stderr, code = run_claude(f"""Effectue une revue de code pour ce fichier Python.Identifie:1. Bugs potentiels2. Problemes de style (PEP 8)3. Ameliorations possibles4. SecuriteFormat: sections avec titres markdown.Code:{content}""", model="sonnet" )if code ==0: output_path = path.with_suffix('.review.md') output_path.write_text(f"# Code Review: {path.name}\n\n{stdout}")return {"success": True, "review": stdout, "output_file": str(output_path)}else:return {"error": stderr}print("Fonction auto_review definie")
Fonction auto_review definie
✓ Lecture ancrée — Revue automatique en Python
La fonction auto_review encapsule la logique de revue de code en utilisant directement l’API Claude. Elle vérifie l’existence du fichier, lit son contenu, et génère une revue structurée avec les sections Bugs, Style, Security et Performance.
Bash vs Python : quand utiliser quoi ?
Critere
Bash
Python
Rapidite de prototypage
Excellent (one-liner)
Plus lourd (fonctions, imports)
Pipeline de fichiers
Ideal (find + claude)
Verbeux
Logique complexe
Limité (conditions, boucles)
Excellent
Gestion d’erreurs
Basique ($?)
Riche (try/except, custom errors)
Integration API
Via jq et curl
Natif (requests, subprocess)
Portabilite
Linux/macOS/WSL
Toutes plateformes
Recommandation : Utilisez Bash pour les scripts simples (revue d’un fichier, generation de rapport) et Python des que vous avez besoin de logique conditionnelle, de parallelisation, ou de traitement d’erreur avance.
4. Slash Commands
Claude Code propose des commandes integrees accessibles avec / en mode interactif :
Commande
Description
Exemple d’utilisation
/init
Genere un CLAUDE.md pour le projet
Debut de projet
/commit
Créé un commit avec message genere
Après modifications
/review
Revue des changements en cours
Avant commit
/status
Statut de connexion et quota
Debug connexion
/mcp
Statut des serveurs MCP
Verifier outils disponibles
/help
Liste toutes les commandes
Decouverte
Mode interactif uniquement : Ces commandes fonctionnent dans claude (sans -p), pas dans claude -p "...".
Exemple de workflow typique
# En mode interactif$ claude> /review # Voir les changements non commites> /commit # Generer message et commiter> /status # Verifier que tout est OK
Ces commandes sont utilisees en mode interactif (claude sans -p).
# /commit : generer un message de commit (appel API reel)def generate_commit_message(diff_content):"""Genere un message de commit a partir d'un diff.""" stdout, stderr, code = run_claude(f"""Genere un message de commit conventionnel pour ces changements.Format attendu:type(scope): description courteDescription detaillee si necessaire.Types: feat, fix, docs, style, refactor, test, choreDiff:{diff_content}""", model="haiku" )return stdout if code ==0elsef"Erreur: {stderr}"# Exemple de diffexample_diff ='''--- a/utils.py+++ b/utils.py@@ -15,6 +15,10 @@ def calculate_statistics(data):+ if not data:+ raise ValueError("Empty data")+ mean = sum(data) / len(data)'''message = generate_commit_message(example_diff)print(message)
fix(utils): guard against empty data in calculate_statistics
Raise ValueError when data is empty, preventing a ZeroDivisionError on the mean calculation.
✓ Lecture ancrée — Génération de message de commit
Le message généré fix(utils): guard against empty data in calculate_statistics suit la convention commit conventionnelle. Il inclut une description détaillée : “Raise ValueError when data is empty, preventing a ZeroDivisionError on the mean calculation.” Le modèle haiku (rapide) est utilisé pour cette génération.
Generation automatique de messages de commit
La fonction generate_commit_message illustre un pattern d’automatisation courant : fournir un diff Git a Claude et demander un message au format conventionnel (type(scope): description). Le prompt specifie explicitement les types acceptes (feat, fix, docs, etc.) pour guider la sortie. En mode interactif, la commande /commit fait exactement cela de maniere transparente.
5. Hooks (Concept)
Les hooks permettent d’intercepter les actions de Claude pour les modifier ou les valider avant/après exécution.
Types de hooks
Type
Declenchement
Cas d’usage
PreToolUse
Avant l’utilisation d’un outil
Validation, confirmation, audit
PostToolUse
Après l’utilisation
Logging, notification, cleanup
Notification
Sur certains événements
Alertes, metriques
Configuration
Les hooks se configurent dans .claude/settings.json au niveau du projet :
Le hook recoit les paramètres en JSON sur stdin et doit retourner : - Code 0 : Action approuvee - Code non-0 : Action refusee (avec message sur stderr)
Cas d’usage courants
Securite : Bloquer l’ecriture de secrets dans le code
Audit : Logger toutes les commandes Bash executees
Validation : Verifier le format des fichiers avant ecriture
# Exemple de hook de validationdef validate_write_hook(filepath, content):"""Hook qui valide le contenu avant ecriture.""" issues = []# Verifications de securiteif'password'in content.lower() and'='in content: issues.append("Possible mot de passe en clair detecte")if'api_key'in content.lower(): issues.append("Possible cle API detectee")# Verifications de styleif filepath.endswith('.py'):if'import *'in content: issues.append("Import wildcard detecte (mauvaise pratique)")return {"approved": len(issues) ==0,"issues": issues }# Testtest_content ='''from utils import *api_key = "sk-1234"'''result = validate_write_hook("config.py", test_content)print(f"Approuve: {result['approved']}")print(f"Problemes: {result['issues']}")
Le hook détecte 2 problèmes : une possible cle API en clair et un import wildcard (mauvaise pratique). Il retourne Approuve: False, bloquant ainsi la validation jusqu’à ce que ces problèmes soient corrigés.
Que nous dit ce résultat ?
Le hook a detecte 2 problemes dans un simple extrait de 3 lignes :
from utils import * : Import wildcard - rend impossible de savoir quelles fonctions sont utilisees, peut causer des conflits de noms
api_key = "sk-1234" : Cle API en dur - un classique de la mise en production accidentelle de secrets
Dans un vrai hook Claude, ce type de validation s’execute avant chaque ecriture de fichier. Si le hook retourne approved: False, Claude ne procede pas a l’ecriture et affiche les problemes detectes. C’est un filet de securite essentiel pour les équipes.
Limites : La detection par mots-cles est basique. Un hook robuste utiliserait un parseur AST (avec le module ast de Python) pour analyser la structure du code plutot que de chercher des chaînes de caractères.
Exercice 1 : Hook de validation de commits conventionnels
Les hooks permettent d’appliquer des règles avant que Claude n’execute une action. Objectif : Completez la fonction validate_commit_message qui verifie qu’un message de commit respecte le format conventionnel (type(scope): description). Ce hook pourrait etre utilise dans un pipeline CI/CD pour assurer la coherence des messages de commit.
# Exercice 6 : Validation de messages de commitimport redef validate_commit_message(message):"""Valide qu'un message de commit respecte le format conventionnel. Format attendu : type(scope): description Types valides : feat, fix, docs, style, refactor, test, chore, perf, ci Args: message: Message de commit a valider. Returns: Dictionnaire {"valid": bool, "type": str, "scope": str, "errors": list}. """# TODO etudiant : validez le format du message de commit# Etape 1 : Verifiez que le message correspond au pattern "type(scope): description"# Etape 2 : Extrayez le type et le scope# Etape 3 : Verifiez que le type est dans la liste des types valides# Indice : Utilisez re.match(r'^(\w+)\(([^)]+)\):\s*(.+)$', message) result =None# TODO etudiant : remplacez par l'implementationreturn result# Testsmessages = ["feat(api): add user authentication endpoint","BUGFIX: correction crash", # Invalide : type non standard"add feature", # Invalide : pas de format type(scope)"docs(readme): update installation instructions"]for msg in messages: validation = validate_commit_message(msg)print(f" {msg} -> {validation}")
✓ Lecture ancrée — Validation de messages de commit
La validation teste plusieurs formats : un message correct feat(api): add user authentication endpoint, un message incorrect BUGFIX: correction crash (type invalide), un message sans type add feature, et un message correct docs(readme): update installation instructions. Cela permet de filtrer les messages qui ne respectent pas la convention.
6. Script de Revue Automatise Complet
Cette section presente un exemple complet et reutilisable de revue de code automatisee.
Architecture du CodeReviewer
CodeReviewer
|
+-- review_file(path) # Revue d'un fichier unique
| |
| +-- check: bugs
| +-- check: style
| +-- check: security
| +-- check: performance
|
+-- review_project(dir) # Revue de tout un projet
|
+-- generate_report() # Generation rapport Markdown
Extensibilite : La classe est concue pour etre etendue. Ajoutez vos propres checks dans l’exercice 3.
Schema : structure de l’agent CodeReviewer
L’agent expose deux entrees (revue d’un fichier, revue d’un projet) et un export de rapport ; la revue d’un fichier enchaine quatre verifications.
class CodeReviewer:"""Revue de code automatisee avec Claude."""def__init__(self, model="sonnet", timeout=180):self.model = modelself.timeout = timeoutself.checks = [ ("bugs", "Identifie les bugs potentiels"), ("style", "Verifie le style PEP 8"), ("security", "Analyse les problemes de securite"), ("performance", "Identifie les optimisations possibles"), ]def review_file(self, filepath):"""Effectue une revue complete d'un fichier.""" path = Path(filepath)ifnot path.exists():return {"error": "Fichier non trouve"} content = path.read_text() results = {"file": str(path), "checks": {}}for check_name, check_desc inself.checks: stdout, stderr, code = run_claude(f"{check_desc} dans ce code (reponse courte):\n\n{content}", model="haiku", # Rapide pour chaque check timeout=self.timeout ) results["checks"][check_name] = stdout if code ==0elsef"Erreur: {stderr}"return resultsdef review_project(self, directory, pattern="*.py"):"""Revue tous les fichiers d'un projet.""" path = Path(directory) files =list(path.rglob(pattern))return {"directory": str(path),"files_count": len(files),"files": [str(f) for f in files]# En production, on appellerait review_file pour chaque fichier }def generate_report(self, results):"""Genere un rapport markdown.""" lines = [f"# Code Review: {results['file']}\n"]for check, output in results.get("checks", {}).items(): lines.append(f"## {check.title()}\n") lines.append(output +"\n")return"\n".join(lines)print("CodeReviewer defini")
CodeReviewer defini
✓ Lecture ancrée — Classe CodeReviewer
La classe CodeReviewer est initialisée avec le modèle sonnet et un timeout de 180 secondes. Elle propose 4 types de vérifications : bugs, style, securite et performance, couvrant ainsi tous les aspects d’une revue complète.
Architecture du CodeReviewer
La classe CodeReviewer encapsule quatre axes de revue dans self.checks. Chaque check est un tuple (nom, description) qui sera passe comme prompt a Claude. Le flux d’exécution pour review_file :
Lecture du fichier source via Path.read_text()
Pour chaque check : appel run_claude avec la description du check et le contenu
Agregation des résultats dans un dictionnaire {"file": ..., "checks": {...}}
generate_report() transforme les résultats en Markdown structure
Le choix de haiku pour chaque check individuel est delibere : 4 appels rapides coutent moins qu’un seul appel sonnet avec un prompt complexe “analyse tout”.
# Test du reviewer (ATTENTION: multiple appels API)reviewer = CodeReviewer()# Voir les fichiers disponiblesproject_info = reviewer.review_project(EXAMPLES_DIR)print(f"Fichiers dans le projet: {project_info['files_count']}")for f in project_info['files']:print(f" - {f}")
Fichiers dans le projet: 3
- examples\sample_project\main.py
- examples\sample_project\utils.py
- examples\sample_project\tests\test_utils.py
✓ Lecture ancrée — Analyse du projet
Le reviewer identifie 3 fichiers dans le projet : main.py, utils.py et tests/test_utils.py. Cette analyse de structure permet d’avoir une vue d’ensemble avant de procéder à la revue détaillée.
Lecture du résultat
Le reviewer a trouve 2 fichiers Python dans le projet d’exemple (main.py et utils.py, plus les tests). Chaque fichier sera analyse independamment sur les 4 axes définis dans self.checks.
Note sur le cout : review_file effectue 4 appels API par fichier (un par check). Pour un projet de 50 fichiers, cela represente 200 appels. C’est pourquoi chaque check utilise model="haiku" (rapide et economique). Si vous n’avez besoin que d’un seul axe d’analyse, appelez run_claude directement plutot que de passer par review_file.
# Revue d'un fichier (4 appels API reels)results = reviewer.review_file(EXAMPLES_DIR /"utils.py")report = reviewer.generate_report(results)print(report)
# Code Review: examples\sample_project\utils.py
## Bugs
Bugs potentiels :
1. **Écart-type = population (÷n), pas échantillon (÷n−1).** Si le but est un écart-type d'échantillon, c'est un bug. Formule : `variance = ... / n` → devrait être `/ (n - 1)`.
2. **`calculate_statistics` ne filtre pas NaN/Inf.** Elle suppose que la donnée est déjà passée par `validate_data`. Appelée directement avec une liste brute (NaN, inf, ou une chaîne), elle renvoie des statistiques NaN ou lève `TypeError` sur `sum()`. Couplage fragile entre `validate_data` et `calculate_statistics`.
3. **`normalize_data` ne protège pas contre NaN/Inf** — si l'entrée en contient, `min/max` renvoient NaN et le résultat est tout NaN (pas de guard, contrairement à `validate_data`).
4. **`validate_data` accepte les bools** : `float(True) → 1.0`, `float(False) → 0.0`. Si `[True, False]` est passé, il devient `[1.0, 0.0]` sans erreur — probablement non désiré.
5. **Alignement du rapport** (cosmétique) : la ligne `"Nombre d'elements : "` fait 20 caractères alors que les autres (`"Moyenne : "`) font 19 — colonnes désalignées d'un caractère.
Le plus important : le point 1 (formule statistique) et le point 2 (couplage validation/calcul).
## Style
Vérification PEP 8 du code (le point principal d'abord) :
**1. Ordre des imports (violation)**
```python
from typing import List, Dict, Any # ← doit venir après
import math
```
La convention (isort) veut, à groupe égal de la lib standard, `import` avant `from` :
```python
import math
from typing import List, Dict, Any
```
**2. Le reste est conforme :**
- 2 lignes vides entre fonctions ✓
- Docstrings Google/NumPy bien structurées ✓
- Espacement opérateurs (`(x - mean) ** 2`) ✓
- Aucune ligne > 79 caractères ✓
- Type hints présents ✓
**Mini-détail (hors PEP 8, plus exactitude de type)** : `"count": n` renvoie un `int` dans un `Dict[str, float]` — incohérent avec l'annotation.
Aucune autre réserve. Seule la correction de l'import est réellement requise.
## Security
Ce code est une pure fonction utilitaire de calcul numérique : il n'y a **aucun danger d'injection réel** — pas de `eval`/`exec`, pas d'accès shell, pas de I/O fichier/réseau, pas de SQL/HTML, pas de secret, pas d'appel externe. Aucun vecteur d'attaque classique (OS command injection, path traversal, injection SQL/NoSQL, XSS, SSRF, désérialisation) ne s'applique ici.
Les seuls points notables sont **de robustesse/correction**, pas de sécurité :
1. **`calculate_statistics` n'appelle pas `validate_data`.** Si on lui passe directement une liste contenant `NaN`/`inf` (en court-circuitant la validation), la moyenne/écart-type dérivent (`NaN` se propage) et `round()` lève `ValueError` sur `inf`. Ce n'est pas une exploitation, mais un contrat implicite fragile — la validation existe ailleurs, les deux fonctions ne sont pas chaînées.
2. **Typage non vérifié.** `data: List[float]` est un hint, pas une contrainte runtime : `sorted()`/`sum()` accepteront n'importe quoi d'additive. De nouveau robustesse, pas sécurité.
3. **`validate_data` silencieux sur `float("nan")`/conversions.** Il ignore silencieusement les items non convertibles — acceptable pour de la saisie utilisateur, mais `bool` passe (`float(True) == 1.0`), certainement involontaire.
En résumé : **pas de vulnérabilité de sécurité** dans ce module. Si le contexte est une app de démo exposant ces valeurs à un UI/report, le point à surveiller serait le **rendu** de `format_report` — mais la valeur renvoyée (`stats.get('count', 'N/A')`) est interpolée dans une chaîne, donc sans injection tant que le consommateur ne fait pas d'évaluation de templates.
## Performance
Optimisations principales :
**1. Redondance dans `calculate_statistics`** — `min(data)` et `max(data)` re-scannent la liste alors que `sorted_data` est déjà triée : utiliser `sorted_data[0]` et `sorted_data[-1]` (0 itération en plus).
**2. Réutiliser la stdlib `statistics`** — `mean`, `median`, `pstdev` remplacent tout le calcul manuel (`import math` devient inutile) : moins de code, moins de bugs d'arrondi, plus lisible.
**3. Ambiguïté `std_dev`** — le calcul fait une **variance population** (`/n`), mais le nom suggère l'écart-type **échantillon** (`/n-1`, via `statistics.stdev`). Trancher le sémantique, sinon le rapport induit en erreur.
**4. `validate_data`** — boucle `for` + `append` → compréhension de liste (`[float(it) for it in data]` avec helper `try_float`) : plus court et plus rapide.
**5. `normalize_data`** — déjà propre (cas `range_val == 0` géré). Rien à changer.
En résumé : les gains réels sont **réutiliser `statistics`** (élimine le code fait-main) et **corriger la redondance min/max**. Le reste est du nettoyage cosmétique.
✓ Lecture ancrée — Revue détaillée du fichier utils.py
La revue complète du fichier utils.py révèle plusieurs catégories de problèmes : - Bugs : calcul d’écart-type (population vs échantillon), absence de filtrage NaN/Inf, validation insuffisante - Style : ordre des imports non conforme PEP 8, incohérence de typage - Security : pas de vulnérabilité réelle mais des problèmes de robustesse (NaN/Inf non gérés) - Performance : redondance dans calculate_statistics (min/max re-scannent la liste triée). Les recommandations prioritaires concernent la correction de la formule statistique et le découplage validation/calcul.
7. Exercices
# EXERCICE 1 : Pipeline de generation de docstrings## Objectif : Creer un pipeline qui:# 1. Lit un fichier Python# 2. Identifie les fonctions sans docstring# 3. Genere les docstrings manquantes## Indices :# - Utilisez create_pipeline() defini plus haut# - Etape 1 : "Liste les fonctions sans docstring dans ce code"# - Etape 2 : "Pour chaque fonction, genere une docstring Google-style"# - Testez avec examples/sample_project/utils.py# Votre code ici# docstring_pipeline = create_pipeline(# ("identify", "Liste les fonctions sans docstring:\n{input}"),# ("generate", "Genere des docstrings Google-style pour:\n{input}")# )print("Decommentez et completez le code pour executer l'exercice")
Decommentez et completez le code pour executer l'exercice
Exercice 2 : Hook de verification des tests
Dans cet exercice, vous créez un hook qui verifie l’existence de fichiers de test associes. Le hook doit retourner un dictionnaire {"approved": bool, "reason": str} et gerer les cas particuliers (__init__.py, fichiers dans tests/).
# EXERCICE 2 : Hook de verification des tests## Objectif : Creer un hook qui verifie que tout fichier Python# a au moins un fichier de test associe.## Regles :# - fichier.py doit avoir test_fichier.py ou fichier_test.py# - Les fichiers __init__.py sont exemptes# - Les fichiers dans un dossier tests/ sont exemptes## Signature :# def check_test_exists(filepath: str) -> dict:# """Retourne {"approved": bool, "reason": str}"""# Votre code ici# from pathlib import Path# def check_test_exists(filepath):# path = Path(filepath)# if path.name == "__init__.py":# return {"approved": True, "reason": "init file"}# # Completez...print("Decommentez et completez le code pour executer l'exercice")
Decommentez et completez le code pour executer l'exercice
Exercice 3 : Script de generation de changelog
L’automatisation de la generation de changelog est un cas d’usage classique en integration CI/CD. Objectif : Completez la fonction generate_changelog_entry qui analyse un diff Git et produit une entree de changelog au format Markdown.
# Exercice 5 : Generation automatique de changelogdef generate_changelog_entry(diff_text, version="unreleased"):"""Genere une entree de changelog a partir d'un diff Git. Args: diff_text: Contenu du diff Git (sortie de git diff). version: Numero de version pour l'entree. Returns: Chaine Markdown formattee pour le changelog. """# TODO etudiant : analysez le diff et generez une entree structuree# Etape 1 : Identifiez les fichiers modifies dans le diff# Etape 2 : Appelez Claude pour generer un resume des changements# Indice : Demandez a Claude de classer les changements par type (ajout, fix, refactoring)# en specifiant le format Markdown attendu changelog =None# TODO etudiant : remplacez par l'implementationreturn changelog# Test avec un diff exemplesample_diff ="""diff --git a/utils.py b/utils.py--- a/utils.py+++ b/utils.py@@ -10,3 +10,8 @@ def parse_config(path):+def validate_config(config):+ if 'api_key' not in config:+ raise ValueError("Missing api_key")+ return True"""entry = generate_changelog_entry(sample_diff, version="1.2.0")print(f"Changelog : {entry}")
Changelog : None
✓ Lecture ancrée — Génération de changelog
La fonction de génération de changelog est conçue pour analyser un diff Git et produire une entrée structurée. Actuellement en mode placeholder, elle retournera None tant que non implémentée, mais son architecture permet une intégration future avec l’API Claude.
Exercice 4 : Extension du CodeReviewer
Dans ce dernier exercice, vous etendez la classe CodeReviewer avec un check personnalise. L’approche recommandee est l’heritage : créez une sous-classe ExtendedReviewer qui appelle super().__init__() puis ajoute vos checks a self.checks.
# EXERCICE 3 : Extension de CodeReviewer## Objectif : Ajouter un check supplementaire a CodeReviewer.## Suggestions de checks :# - "documentation" : Verifie que les fonctions publiques ont des docstrings# - "complexity" : Identifie les fonctions trop longues (>50 lignes)# - "typing" : Verifie la presence de type hints# - "imports" : Detecte les imports inutilises## Structure :# class ExtendedReviewer(CodeReviewer):# def __init__(self):# super().__init__()# self.checks.append(("votre_check", "Description du check"))# Votre code iciprint("Decommentez et completez le code pour executer l'exercice")
Decommentez et completez le code pour executer l'exercice
Exercice 5 : Pipeline de classification de fichiers
Les pipelines sont puissants pour traiter des volumes de données. Objectif : Completez la fonction classify_file qui utilise Claude pour determiner le type et le rôle d’un fichier source Python. Cette fonction sera le premier maillon d’un pipeline d’analyse de projet.
# Exercice 4 : Classification automatique de fichiersdef classify_file(filepath):"""Determine le type d'un fichier source Python. Args: filepath: Chemin vers le fichier a analyser. Returns: Dictionnaire {"filepath": str, "type": str, "description": str}. Types possibles : "module", "script", "test", "config", "autre". """# TODO etudiant : lisez le fichier et appelez Claude pour le classifier# Etape 1 : Lisez le contenu du fichier avec Path(filepath).read_text()# Etape 2 : Composez un prompt demandant a Claude de classifier le fichier# Indice : Specifiez les categories possibles dans le prompt pour guider la reponse result =None# TODO etudiant : remplacez par l'implementationreturn result# Test avec un fichier du projet d'exempleclassification = classify_file("examples/sample_project/main.py")print(f"Classification : {classification}")
Classification : None
✓ Lecture ancrée — Classification de fichiers
La fonction de classification a pour objectif de catégoriser automatiquement les fichiers Python. Elle devra distinguer modules, scripts, tests et fichiers de configuration pour une meilleure organisation du projet.
✓ Lecture ancrée — Synthèse de l’automatisation
Ce notebook démontre comment automatiser la revue de code avec l’API Claude via des pipelines de prompts. Les principales fonctionnalités couvertes incluent : l’analyse statique de code, la génération de messages de commit conventionnels, la validation de messages, la création de hooks de pré-commit, et la revue complète de projets avec la classe CodeReviewer. L’approche par étapes permet une intégration progressive dans les workflows de développement.
Felicitations ! Vous avez complete la serie de notebooks Claude CLI.
Prochaines étapes suggeres
- Explorez les notebooks GenAI pour la generation d’images - Créez votre propre CLAUDE.md pour vos projets - Configurez des hooks de securite pour votre équipe
Comment fonctionne ce pipeline ?
La fonction
create_pipelineencapsule un schema de traitement classique en 3 phases :