Dans ce tutoriel, vous allez apprendre à créer une interface en ligne de commande (CLI) en Python.
Trois bibliothèques sont au programme :
argparse, qui fait partie de la bibliothèque standardclick, qui s’utilise avec des décorateurstyper, qui s’appuie sur les annotations de type (type hints)
Les exemples ont été testés avec Python 3.13, click 8.5.0 et typer 0.27.3.
Pourquoi créer une CLI ?
Une CLI permet de paramétrer un script sans toucher au code : on lui passe des arguments au lancement, comme à n’importe quelle commande du système. Le même script devient un outil réutilisable, que l’on peut appeler à la main, depuis un script bash ou dans un pipeline CI/CD.
argparse (bibliothèque standard)
argparse est inclus dans Python, aucune installation nécessaire.
Exemple basique
import argparse
parser = argparse.ArgumentParser(description="Un outil CLI simple")
parser.add_argument("nom", help="Votre nom")
parser.add_argument("-a", "--age", type=int, help="Votre âge")
args = parser.parse_args()
print(f"Bonjour {args.nom}!")
if args.age:
print(f"Vous avez {args.age} ans.")
Utilisation :
python script.py Pierre --age 25
# Bonjour Pierre!
# Vous avez 25 ans.
Arguments positionnels et optionnels
import argparse
parser = argparse.ArgumentParser(description="Gestionnaire de fichiers")
# Argument positionnel (obligatoire)
parser.add_argument("fichier", help="Chemin du fichier")
# Arguments optionnels
parser.add_argument("-o", "--output", help="Fichier de sortie")
parser.add_argument("-v", "--verbose", action="store_true", help="Mode verbeux")
parser.add_argument("-n", "--nombre", type=int, default=10, help="Nombre de lignes (défaut: 10)")
args = parser.parse_args()
print(f"Fichier: {args.fichier}")
print(f"Output: {args.output}")
print(f"Verbose: {args.verbose}")
print(f"Nombre: {args.nombre}")
Un argument positionnel est obligatoire et repéré par sa position, un argument optionnel commence par - ou --. Avec action="store_true", l’argument devient un simple drapeau, qui vaut True s’il est présent. argparse génère aussi l’aide à partir de ces déclarations :
python script.py --help
Ce qui donne, avec Python 3.13 :
usage: script.py [-h] [-o OUTPUT] [-v] [-n NOMBRE] fichier
Gestionnaire de fichiers
positional arguments:
fichier Chemin du fichier
options:
-h, --help show this help message and exit
-o, --output OUTPUT Fichier de sortie
-v, --verbose Mode verbeux
-n, --nombre NOMBRE Nombre de lignes (défaut: 10)
Depuis Python 3.14, cette aide s’affiche en couleur.
Sous-commandes avec argparse
import argparse
parser = argparse.ArgumentParser(description="Gestionnaire de tâches")
subparsers = parser.add_subparsers(dest="commande", help="Commandes disponibles")
# Sous-commande "add"
parser_add = subparsers.add_parser("add", help="Ajouter une tâche")
parser_add.add_argument("tache", help="Description de la tâche")
parser_add.add_argument("-p", "--priorite", type=int, default=1, help="Priorité (1-5)")
# Sous-commande "list"
parser_list = subparsers.add_parser("list", help="Lister les tâches")
parser_list.add_argument("-a", "--all", action="store_true", help="Afficher toutes les tâches")
# Sous-commande "delete"
parser_delete = subparsers.add_parser("delete", help="Supprimer une tâche")
parser_delete.add_argument("id", type=int, help="ID de la tâche")
args = parser.parse_args()
if args.commande == "add":
print(f"Ajout de la tâche: {args.tache} (priorité: {args.priorite})")
elif args.commande == "list":
print(f"Liste des tâches (all={args.all})")
elif args.commande == "delete":
print(f"Suppression de la tâche #{args.id}")
else:
parser.print_help()
Utilisation :
python tasks.py add "Finir le rapport" -p 3
python tasks.py list --all
python tasks.py delete 5
Click
click est une bibliothèque qui simplifie la création de CLI avec des décorateurs.
Installation
pip install click
Exemple basique
import click
@click.command()
@click.argument("nom")
@click.option("-a", "--age", type=int, help="Votre âge")
def bonjour(nom, age):
"""Un outil CLI simple."""
click.echo(f"Bonjour {nom}!")
if age:
click.echo(f"Vous avez {age} ans.")
if __name__ == "__main__":
bonjour()
Options avancées avec Click
import click
@click.command()
@click.argument("fichier", type=click.Path(exists=True))
@click.option("-o", "--output", type=click.Path(), help="Fichier de sortie")
@click.option("-v", "--verbose", is_flag=True, help="Mode verbeux")
@click.option("-f", "--format", type=click.Choice(["json", "csv", "xml"]), default="json")
@click.option("-n", "--nombre", type=int, default=10, show_default=True)
def traiter(fichier, output, verbose, format, nombre):
"""Traite un fichier et génère une sortie."""
if verbose:
click.echo(f"Traitement de {fichier}...")
click.echo(f"Format: {format}, Lignes: {nombre}")
if output:
click.echo(f"Écriture vers {output}")
if __name__ == "__main__":
traiter()
Groupes de commandes avec Click
import click
@click.group()
def cli():
"""Gestionnaire de tâches."""
pass
@cli.command()
@click.argument("tache")
@click.option("-p", "--priorite", type=int, default=1, help="Priorité (1-5)")
def add(tache, priorite):
"""Ajouter une nouvelle tâche."""
click.echo(f"Ajout: {tache} (priorité: {priorite})")
@cli.command()
@click.option("-a", "--all", "show_all", is_flag=True, help="Afficher toutes les tâches")
def list(show_all):
"""Lister les tâches."""
click.echo(f"Liste des tâches (all={show_all})")
@cli.command()
@click.argument("task_id", type=int)
@click.confirmation_option(prompt="Êtes-vous sûr de vouloir supprimer?")
def delete(task_id):
"""Supprimer une tâche."""
click.echo(f"Suppression de la tâche #{task_id}")
if __name__ == "__main__":
cli()
Couleurs et style avec Click
import click
@click.command()
def status():
"""Affiche le statut avec des couleurs."""
click.secho("Succès!", fg="green", bold=True)
click.secho("Attention!", fg="yellow")
click.secho("Erreur!", fg="red", bold=True)
# Barre de progression
with click.progressbar(range(100), label="Traitement") as items:
for item in items:
# Simuler un traitement
import time
time.sleep(0.01)
if __name__ == "__main__":
status()
Typer
typer utilise les annotations de type de Python pour générer automatiquement une CLI.
Installation
pip install typer
Exemple basique
import typer
from typing import Optional
def main(nom: str, age: Optional[int] = None):
"""Un outil CLI simple."""
print(f"Bonjour {nom}!")
if age:
print(f"Vous avez {age} ans.")
if __name__ == "__main__":
typer.run(main)
C’est tout ! Typer déduit les types des annotations et génère l’aide tout seul. Son installation ajoute aussi la bibliothèque Rich, qui met en forme l’aide et les messages d’erreur dans des encadrés.
Options avancées avec Typer
import typer
from typing import Optional
from pathlib import Path
from enum import Enum
class Format(str, Enum):
json = "json"
csv = "csv"
xml = "xml"
def traiter(
fichier: Path = typer.Argument(..., help="Chemin du fichier"),
output: Optional[Path] = typer.Option(None, "--output", "-o", help="Fichier de sortie"),
verbose: bool = typer.Option(False, "--verbose", "-v", help="Mode verbeux"),
format: Format = typer.Option(Format.json, "--format", "-f", help="Format de sortie"),
nombre: int = typer.Option(10, "--nombre", "-n", help="Nombre de lignes"),
):
"""Traite un fichier et génère une sortie."""
if verbose:
typer.echo(f"Traitement de {fichier}...")
typer.echo(f"Format: {format.value}, Lignes: {nombre}")
if output:
typer.echo(f"Écriture vers {output}")
if __name__ == "__main__":
typer.run(traiter)
Application avec sous-commandes
import typer
from typing import Optional
app = typer.Typer(help="Gestionnaire de tâches")
@app.command()
def add(
tache: str = typer.Argument(..., help="Description de la tâche"),
priorite: int = typer.Option(1, "--priorite", "-p", min=1, max=5, help="Priorité"),
):
"""Ajouter une nouvelle tâche."""
typer.echo(f"Ajout: {tache} (priorité: {priorite})")
@app.command()
def list(
all: bool = typer.Option(False, "--all", "-a", help="Afficher toutes les tâches"),
):
"""Lister les tâches."""
typer.echo(f"Liste des tâches (all={all})")
@app.command()
def delete(
task_id: int = typer.Argument(..., help="ID de la tâche"),
force: bool = typer.Option(False, "--force", "-f", help="Supprimer sans confirmation"),
):
"""Supprimer une tâche."""
if not force:
confirm = typer.confirm("Êtes-vous sûr?")
if not confirm:
raise typer.Abort()
typer.echo(f"Suppression de la tâche #{task_id}")
if __name__ == "__main__":
app()
Couleurs et style avec Typer
import typer
def main():
typer.secho("Succès!", fg=typer.colors.GREEN, bold=True)
typer.secho("Attention!", fg=typer.colors.YELLOW)
typer.secho("Erreur!", fg=typer.colors.RED, bold=True)
# Demander une entrée
nom = typer.prompt("Quel est votre nom?")
typer.echo(f"Bonjour {nom}!")
# Confirmation
if typer.confirm("Voulez-vous continuer?"):
typer.echo("Continuation...")
if __name__ == "__main__":
typer.run(main)
Rendre votre CLI installable
Pour distribuer votre CLI, créez un fichier pyproject.toml :
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "mon-outil"
version = "1.0.0"
description = "Mon outil CLI"
dependencies = [
"typer>=0.9.0",
]
[project.scripts]
mon-outil = "mon_package.cli:app"
Ici, le code de la CLI (l’objet app de Typer) se trouve dans mon_package/cli.py, à côté du pyproject.toml. Installez ensuite le projet avec :
pip install -e .
La commande mon-outil est alors disponible dans l’environnement où le paquet est installé (le venv actif, s’il y en a un).
Comparaison des bibliothèques
| Fonctionnalité | argparse | click | typer |
|---|---|---|---|
| Installation | Inclus | pip | pip |
| Syntaxe | Impérative | Décorateurs | Annotations de type |
| Courbe d’apprentissage | Moyenne | Facile | Très facile |
| Sous-commandes | Oui | Oui | Oui |
| Couleurs/style | Non (aide en couleur depuis Python 3.14) | Oui | Oui |
| Autocomplétion | Non | Intégrée | Intégrée |
| Validation | Basique | Avancée | Avancée |
Pour choisir : argparse suffit pour un script simple qui ne doit pas avoir de dépendance externe, click convient aux CLI complexes qui demandent beaucoup de personnalisation, et typer donne le code le plus court si vous utilisez déjà les annotations de type.
Voir aussi
- Python : Comment utiliser les décorateurs
- Python : Comment faire une api web avec FastAPI
- Documentation argparse : https://docs.python.org/3/library/argparse.html
- Documentation click : https://click.palletsprojects.com
- Documentation typer : https://typer.tiangolo.com