Claude CLI - Automatisation Avancee

Navigation : Index | << Précédent

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)

1. Configuration

import sys
import subprocess
import json
import os
from pathlib import Path

sys.path.insert(0, 'helpers')
from claude_cli import run_claude, verify_installation, print_response

EXAMPLES_DIR = Path('examples/sample_project')
print(f"Claude CLI pret: {verify_installation()}")
Claude CLI pret: True

✓ Lecture ancrée — Vérification de l’installation

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 claude installé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 :

Input → [Claude: Analyse] → [Claude: Correction] → [Claude: Review] → Output

Avantages des pipelines

  • 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 = stdout
        
        return {"success": True, "results": results, "final_output": current_data}
    
    return execute

print("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 → Ameliorations
code_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 :

  1. Analyse : Claude identifie les caractéristiques du code (structure, patterns, anti-patterns)
  2. Synthese : Un second appel resume les points essentiels (filtrage du bruit)
  3. 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 automatique

FILE=$1                                          # Premier argument = fichier
REVIEW=$(claude -p "Revue de code pour: $(cat $FILE)")  # Exécution Claude
echo "$REVIEW" > "${FILE}.review.md"             # Sauvegarde résultat

Exemple PowerShell (Windows)

# Analyse de tous les fichiers Python du repertoire courant
Get-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 automatique
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"
'''

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 equivalente
def auto_review(filepath):
    """Effectue une revue de code automatique."""
    path = Path(filepath)
    
    if not 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 potentiels
2. Problemes de style (PEP 8)
3. Ameliorations possibles
4. Securite

Format: 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 courte

Description detaillee si necessaire.

Types: feat, fix, docs, style, refactor, test, chore

Diff:
{diff_content}""",
        model="haiku"
    )
    return stdout if code == 0 else f"Erreur: {stderr}"

# Exemple de diff
example_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 :

{
  "hooks": {
    "PreToolUse": {
      "Write": "python validate_write.py",
      "Bash": "python confirm_bash.py"
    },
    "PostToolUse": {
      "Bash": "python log_bash.py"
    }
  }
}

Protocole de communication

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 validation
def validate_write_hook(filepath, content):
    """Hook qui valide le contenu avant ecriture."""
    issues = []
    
    # Verifications de securite
    if '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 style
    if filepath.endswith('.py'):
        if 'import *' in content:
            issues.append("Import wildcard detecte (mauvaise pratique)")
    
    return {
        "approved": len(issues) == 0,
        "issues": issues
    }

# Test
test_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']}")
Approuve: False
Problemes: ['Possible cle API detectee', 'Import wildcard detecte (mauvaise pratique)']

✓ Lecture ancrée — Hook de pré-commit

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 :

  1. from utils import * : Import wildcard - rend impossible de savoir quelles fonctions sont utilisees, peut causer des conflits de noms
  2. 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 commit
import re

def 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'implementation
    return result

# Tests
messages = [
    "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}")
  feat(api): add user authentication endpoint -> None
  BUGFIX: correction crash -> None
  add feature -> None
  docs(readme): update installation instructions -> None

✓ 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.

flowchart TD
    CR["CodeReviewer"]
    CR --> RF["review_file(path)"]
    RF --> B["check: bugs"]
    RF --> S["check: style"]
    RF --> Sec["check: security"]
    RF --> Pe["check: performance"]
    CR --> RP["review_project(dir)"]
    CR --> GR["generate_report() -> rapport Markdown"]
class CodeReviewer:
    """Revue de code automatisee avec Claude."""
    
    def __init__(self, model="sonnet", timeout=180):
        self.model = model
        self.timeout = timeout
        self.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)
        if not path.exists():
            return {"error": "Fichier non trouve"}
        
        content = path.read_text()
        results = {"file": str(path), "checks": {}}
        
        for check_name, check_desc in self.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 == 0 else f"Erreur: {stderr}"
        
        return results
    
    def 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 :

  1. Lecture du fichier source via Path.read_text()
  2. Pour chaque check : appel run_claude avec la description du check et le contenu
  3. Agregation des résultats dans un dictionnaire {"file": ..., "checks": {...}}
  4. 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 disponibles
project_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 changelog
def 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'implementation
    return changelog

# Test avec un diff exemple
sample_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 ici

print("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 fichiers
def 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'implementation
    return result

# Test avec un fichier du projet d'exemple
classification = 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.

8. Resume Final

Competences acquises dans cette serie

Notebook Competences
01-Bases claude -p, modèles, formats de sortie
02-Sessions -c, sessions, conversations multi-tours
03-References @fichier, plages de lignes, CLAUDE.md
04-Agents Explore, Plan, subagents, parallelisation
05-Automatisation Pipelines, scripts shell, hooks, revue automatisee

Points cles de ce notebook

  • Les pipelines permettent de chainer des opérations Claude de maniere modulaire
  • L’integration shell (Bash/PowerShell) permet d’automatiser au niveau système
  • Les slash commands accelerent les tâches courantes en mode interactif
  • Les hooks offrent un contrôle fin sur les actions de Claude

Documentation et ressources

Ressources communautaires


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

Retour au sommet