Modern Python Engineering
Chapitre 14
14 - CLI Python
> **Duree :** 3 semaines > **Objectif :** Maitriser la creation d'interfaces en ligne de commande en Python.
Cours 14 : CLI Python
1. Click
1.1 Commandes de base
import click
@click.command()
@click.argument("name")
@click.option("--greeting", default="Hello", help="Greeting message")
@click.option("--count", default=1, type=int, help="Number of times")
@click.option("--verbose", is_flag=True, help="Enable verbose output")
def hello(name, greeting, count, verbose):
"""Say hello to NAME."""
for _ in range(count):
click.echo(f"{greeting}, {name}!")
if verbose:
click.echo(f"Count: {count}")
if __name__ == "__main__":
hello()
Utilisation :
python hello.py World --greeting Hi --count 3 --verbose
1.2 Groupes de commandes
@click.group()
def cli():
pass
@cli.command()
@click.argument("project_name")
def init(project_name):
click.echo(f"Initializing {project_name}...")
@cli.command()
def build():
click.echo("Building...")
@cli.command()
def deploy():
click.echo("Deploying...")
if __name__ == "__main__":
cli()
1.3 Contexte et callbacks
@click.group()
@click.option("--debug/--no-debug", default=False)
@click.pass_context
def cli(ctx, debug):
ctx.ensure_object(dict)
ctx.obj["DEBUG"] = debug
@cli.command()
@click.pass_context
def sync(ctx):
click.echo(f"Debug mode: {ctx.obj['DEBUG']}")
2. Typer
2.1 Typer avec type hints
from typer import Typer
import typer
app = Typer()
@app.command()
def hello(
name: str,
greeting: str = typer.Option("Hello", help="Greeting message"),
count: int = typer.Option(1, help="Number of times"),
verbose: bool = typer.Option(False, "--verbose", "-v"),
):
for _ in range(count):
print(f"{greeting}, {name}!")
@app.command()
def goodbye(name: str, formal: bool = False):
if formal:
print(f"Goodbye Ms. {name}.")
else:
print(f"Bye {name}!")
if __name__ == "__main__":
app()
2.2 Auto-documentation
python app.py --help
python app.py hello --help
2.3 Shell completion
eval "$(python app.py --install-completion)"
3. Rich
3.1 Console et styles
from rich.console import Console
console = Console()
console.print("[bold green]Success![/bold green]")
console.rule("[blue]Section[/blue]")
3.2 Tables
from rich.table import Table
table = Table(title="Users")
table.add_column("ID", style="cyan")
table.add_column("Name", style="magenta")
table.add_row("1", "Alice")
table.add_row("2", "Bob")
console.print(table)
3.3 Progress bars
from rich.progress import Progress
import time
with Progress() as progress:
task = progress.add_task("[cyan]Processing...", total=100)
for i in range(100):
time.sleep(0.02)
progress.update(task, advance=1)
4. Textual
from textual.app import App, ComposeResult
from textual.widgets import Header, Footer, Button, Input, Static
class MyApp(App):
CSS = '''
Screen { align: center middle; }
'''
def compose(self) -> ComposeResult:
yield Header()
yield Input(placeholder="Enter your name...", id="name-input")
yield Button("Submit", id="submit-btn")
yield Static(id="hello")
yield Footer()
def on_button_pressed(self, event):
name = self.query_one("#name-input", Input).value
self.query_one("#hello", Static).update(f"Hello, {name}!")
if __name__ == "__main__":
MyApp().run()
5. argparse
import argparse
parser = argparse.ArgumentParser(description="CLI tool")
parser.add_argument("input", help="Input file")
parser.add_argument("-o", "--output", default="output.json")
parser.add_argument("-v", "--verbose", action="store_true")
args = parser.parse_args()
print(f"Processing {args.input}")
6. CLI Testing
from click.testing import CliRunner
from my_cli import hello
def test_hello():
runner = CliRunner()
result = runner.invoke(hello, ["--greeting", "Hi", "World"])
assert result.exit_code == 0
assert "Hi, World!" in result.output
7. Distribution
pipx install my-cli
8. Diagramme
Diagramme en cours de génération...