python的typer写cli脚本如此简单

# typer_demo.py
import typer
from pathlib import Path
from typing import Optional
from typing_extensions import Annotated

app = typer.Typer(rich_markup_mode="rich")
config_app = typer.Typer()
file_app = typer.Typer()
app.add_typer(config_app, name="config", help="Configuration management")
app.add_typer(file_app, name="file", help="File operations")

# Shared verbose option
def verbose_callback(value: bool):
    if value:
        typer.echo("Verbose mode enabled")

# 新增 quiet_callback 函数
def quiet_callback(value: bool):
    if value:
        typer.echo("Quiet mode enabled")

# 添加 -quiet 参数
@app.callback()
def main(
    verbose: Annotated[
        bool,
        typer.Option("--verbose", "-v", callback=verbose_callback, help="Enable verbose mode")
    ] = False,
    quiet: Annotated[
        bool,
        typer.Option("--quiet", "-q", callback=quiet_callback, help="Enable quiet mode")
    ] = False
):
    pass

@config_app.command("show")
def show_config(
    key: Annotated[
        Optional[str],
        typer.Argument(show_default=False, help="Configuration key to show")
    ] = None
):
    """Display configuration values"""
    # Implementation would load actual config
    mock_config = {"user": "admin", "age": 30}
    if key:
        typer.echo(f"{key}: {mock_config.get(key, 'Not found')}")
    else:
        for k, v in mock_config.items():
            typer.echo(f"{k}: {v}")

@config_app.command("set")
def set_config(
    key: Annotated[str, typer.Argument(help="Configuration key to set")],
    value: Annotated[str, typer.Argument(help="Value to set")],
    age: Annotated[
        Optional[int],
        typer.Option(min=0, max=150, help="Age validation example")
    ] = None
):
    """Set configuration values"""
    # Implementation would save config
    if age is not None:
        typer.echo(f"Setting age to {age} with validation")
    typer.secho(f"Set {key} = {value}", fg="green")

@file_app.command("upload")
def upload_file(
    path: Annotated[
        Path,
        typer.Argument(exists=True, file_okay=True, dir_okay=False,
                      readable=True, resolve_path=True,
                      help="File path to upload")
    ],
    chunk_size: Annotated[
        int,
        typer.Option("--chunk", "-c", help="Chunk size in bytes",
                    rich_help_panel="Advanced Options")
    ] = 1024,
    retries: Annotated[
        int,
        typer.Option("--retries", "-r", help="Number of retries",
                    rich_help_panel="Advanced Options")
    ] = 3
):
    """Upload a file to remote server"""
    progress = typer.progressbar(length=100, label="Uploading")
    for _ in progress:
        # Simulate upload progress
        pass
    typer.secho(f"Uploaded {path} successfully!", bold=True)

@file_app.command("download")
def download_file(
    url: Annotated[str, typer.Argument(help="File URL to download")],
    output: Annotated[
        Path,
        typer.Option("--output", "-o", help="Output path",
                    envvar="OUTPUT_DIR")
    ] = Path("downloads")
):
    """Download a file from URL"""
    if not output.exists():
        output.mkdir(parents=True)
    typer.echo(f"Downloading {url} to {output}")

if __name__ == "__main__":
    app()

 

posted @ 2025-03-31 21:49  iTech  阅读(47)  评论(0)    收藏  举报