# 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()