Exercices Projets guidés CLI basique avec Click
🎉

Bravo!

Débutant 🧠 Fondamentaux 10 XP 0 personnes ont réussi

CLI basique avec Click

Tu demarres un projet ambitieux : construire ton propre Mini Claude Code. Un assistant IA en ligne de commande qui peut lire tes fichiers, ecrire du code, l'executer et corriger ses erreurs. Le genre d'outil que tu utilises peut-etre deja au quotidien, et que tu vas comprendre de l'interieur en le reconstruisant brique par brique.

Premiere etape : creer le squelette du CLI. Avant de parler a un LLM, avant de lire des fichiers, il faut que ton programme sache recevoir une commande de l'utilisateur et y reagir. C'est la fondation de tout.

En Python, le standard pour creer des CLI professionnels s'appelle Click. C'est la librairie utilisee par Flask, Celery, et des centaines d'outils de production. Elle remplace avantageusement argparse (trop verbeux) et sys.argv (trop primitif).

Pour l'installer :

pip install click rich

Click fonctionne avec des decorateurs. Tu decores une fonction avec @click.command() et elle devient une commande CLI. Pour ajouter un argument :

import click

@click.command()
@click.argument("nom")
def saluer(nom):
click.echo(f"Bonjour {nom} !")

# En terminal : python mon_script.py Alice
# Affiche : Bonjour Alice !

Tu peux aussi ajouter des options (avec --) et des valeurs par defaut :

@click.command()
@click.option("--model", default="gpt-4o-mini", help="Le modele a utiliser")
def chat(model):
click.echo(f"Modele : {model}")

Pour ce premier exercice, on ne va pas encore utiliser Click directement dans le sandbox (il faut un terminal pour ca). A la place, tu vas ecrire la fonction qui sera au coeur de ton CLI : une fonction traiter_commande(texte) qui prend le texte saisi par l'utilisateur et renvoie un dictionnaire avec la commande parsee.

La fonction doit gerer trois cas :

Si le texte commence par / c'est une commande speciale. Extrais le nom de la commande (sans le /) et les arguments eventuels.
Si le texte est vide ou ne contient que des espaces, renvoie une erreur.
Sinon, c'est un prompt pour le LLM.

Le dictionnaire retourne doit avoir cette forme :

{"type": "prompt", "contenu": "explique-moi les decorateurs"}
{"type": "commande", "nom": "quit", "args": []}
{"type": "commande", "nom": "files", "args": ["src/"]}
{"type": "erreur", "message": "Commande vide"}

Exemple :

traiter_commande("explique-moi les decorateurs")
renvoie {"type": "prompt", "contenu": "explique-moi les decorateurs"}

traiter_commande("/quit")
renvoie {"type": "commande", "nom": "quit", "args": []}

traiter_commande("/files src/ tests/")
renvoie {"type": "commande", "nom": "files", "args": ["src/", "tests/"]}

traiter_commande(" ")
renvoie {"type": "erreur", "message": "Commande vide"}

Tests (4/5)

Prompt simple
r = traiter_commande("explique-moi les decorateurs")
assert r["type"] == "prompt", f"Un texte normal doit etre de type 'prompt', pas '{r['type']}'"
assert r["contenu"] == "explique-moi les decorateurs"
Commande sans arguments
r = traiter_commande("/quit")
assert r["type"] == "commande"
assert r["nom"] == "quit"
assert r["args"] == [], f"Pas d'arguments attendus, obtenu {r['args']}"
Commande avec arguments
r = traiter_commande("/files src/ tests/")
assert r["type"] == "commande"
assert r["nom"] == "files"
assert r["args"] == ["src/", "tests/"], f"Attendu ['src/', 'tests/'], obtenu {r['args']}"
Texte vide ou espaces
r1 = traiter_commande("")
assert r1["type"] == "erreur", "Un texte vide doit retourner une erreur"

r2 = traiter_commande("   ")
assert r2["type"] == "erreur", "Un texte avec que des espaces doit retourner une erreur"

+ 0 tests cachés

Indices (3 disponibles)

solution.py