python
examples
examples.py🐍python
"""
CLI Applications - Examples
Learn to build professional command-line tools with Python.
"""
import argparse
import sys
from pathlib import Path
from typing import Callable
from dataclasses import dataclass, field
# =============================================================================
# ARGPARSE BASICS - Built-in argument parsing
# =============================================================================
def argparse_basic_example():
"""Basic argparse usage."""
parser = argparse.ArgumentParser(
description="A simple file processor",
epilog="Example: python cli.py input.txt -o output.txt"
)
# Positional argument (required)
parser.add_argument(
'input_file',
type=str,
help='Input file to process'
)
# Optional arguments with flags
parser.add_argument(
'-o', '--output',
type=str,
default='output.txt',
help='Output file (default: output.txt)'
)
parser.add_argument(
'-v', '--verbose',
action='store_true',
help='Enable verbose output'
)
parser.add_argument(
'-n', '--count',
type=int,
default=1,
help='Number of times to process'
)
# Parse arguments (use [] for testing, remove for real CLI)
args = parser.parse_args(['test.txt', '-v', '-n', '3'])
print(f"Input: {args.input_file}")
print(f"Output: {args.output}")
print(f"Verbose: {args.verbose}")
print(f"Count: {args.count}")
def argparse_subcommands_example():
"""Argparse with subcommands (like git)."""
parser = argparse.ArgumentParser(
prog='myapp',
description='Application with subcommands'
)
subparsers = parser.add_subparsers(dest='command', help='Available commands')
# 'init' subcommand
init_parser = subparsers.add_parser('init', help='Initialize a project')
init_parser.add_argument('name', help='Project name')
init_parser.add_argument('--template', default='basic', help='Template to use')
# 'build' subcommand
build_parser = subparsers.add_parser('build', help='Build the project')
build_parser.add_argument('--release', action='store_true', help='Build for release')
build_parser.add_argument('--target', default='all', help='Build target')
# 'run' subcommand
run_parser = subparsers.add_parser('run', help='Run the project')
run_parser.add_argument('--port', type=int, default=8000, help='Port to run on')
# Test parsing
args = parser.parse_args(['init', 'myproject', '--template', 'web'])
print(f"Command: {args.command}")
print(f"Name: {args.name}")
print(f"Template: {args.template}")
def argparse_choices_example():
"""Argparse with choices and validation."""
parser = argparse.ArgumentParser(description='Process with choices')
parser.add_argument(
'--format',
choices=['json', 'xml', 'csv'],
default='json',
help='Output format'
)
parser.add_argument(
'--log-level',
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
default='INFO',
help='Logging level'
)
parser.add_argument(
'--workers',
type=int,
choices=range(1, 17),
default=4,
metavar='N',
help='Number of workers (1-16)'
)
args = parser.parse_args(['--format', 'csv', '--log-level', 'DEBUG'])
print(f"Format: {args.format}")
print(f"Log level: {args.log_level}")
# =============================================================================
# CLICK - Decorator-based CLI framework
# =============================================================================
# Note: Click needs to be installed: pip install click
CLICK_EXAMPLE = '''
import click
@click.group()
@click.version_option(version='1.0.0')
def cli():
"""My awesome CLI application."""
pass
@cli.command()
@click.argument('name')
@click.option('--greeting', '-g', default='Hello', help='Greeting to use')
@click.option('--count', '-c', default=1, help='Number of greetings')
def greet(name, greeting, count):
"""Greet someone."""
for _ in range(count):
click.echo(f'{greeting}, {name}!')
@cli.command()
@click.argument('input_file', type=click.Path(exists=True))
@click.option('--output', '-o', type=click.Path(), help='Output file')
@click.option('--verbose', '-v', is_flag=True, help='Verbose output')
def process(input_file, output, verbose):
"""Process a file."""
if verbose:
click.echo(f'Processing {input_file}...')
# Process file...
click.echo(click.style('Done!', fg='green'))
@cli.command()
@click.option('--name', prompt='Your name', help='Your name')
@click.option('--password', prompt=True, hide_input=True, help='Password')
def login(name, password):
"""Login to the system."""
click.echo(f'Logging in as {name}...')
if __name__ == '__main__':
cli()
'''
# =============================================================================
# TYPER - Modern CLI with type hints
# =============================================================================
# Note: Typer needs to be installed: pip install typer
TYPER_EXAMPLE = '''
import typer
from typing import Optional
from enum import Enum
app = typer.Typer(help="My awesome CLI application")
class Format(str, Enum):
json = "json"
yaml = "yaml"
toml = "toml"
@app.command()
def greet(
name: str = typer.Argument(..., help="Name to greet"),
greeting: str = typer.Option("Hello", "--greeting", "-g", help="Greeting"),
count: int = typer.Option(1, "--count", "-c", help="Number of greetings"),
):
"""Greet someone with a custom message."""
for _ in range(count):
typer.echo(f"{greeting}, {name}!")
@app.command()
def process(
input_file: Path = typer.Argument(..., exists=True, help="Input file"),
output: Optional[Path] = typer.Option(None, "--output", "-o"),
format: Format = typer.Option(Format.json, "--format", "-f"),
verbose: bool = typer.Option(False, "--verbose", "-v"),
):
"""Process a file."""
if verbose:
typer.echo(f"Processing {input_file} as {format.value}...")
# Process...
typer.echo(typer.style("Done!", fg=typer.colors.GREEN))
@app.command()
def init(
name: str = typer.Argument(...),
force: bool = typer.Option(False, "--force", "-f", help="Overwrite existing"),
):
"""Initialize a new project."""
if force:
typer.confirm("This will overwrite existing files. Continue?", abort=True)
typer.echo(f"Creating project {name}...")
if __name__ == "__main__":
app()
'''
# =============================================================================
# RICH - Beautiful terminal output
# =============================================================================
# Note: Rich needs to be installed: pip install rich
RICH_EXAMPLE = '''
from rich.console import Console
from rich.table import Table
from rich.progress import Progress, track
from rich.panel import Panel
from rich.markdown import Markdown
from rich import print as rprint
import time
console = Console()
# Styled text
console.print("[bold red]Error:[/bold red] Something went wrong")
console.print("[green]Success![/green] Operation completed")
console.print("[blue underline]https://example.com[/blue underline]")
# Tables
table = Table(title="Users")
table.add_column("ID", style="cyan")
table.add_column("Name", style="magenta")
table.add_column("Email", style="green")
table.add_row("1", "Alice", "alice@example.com")
table.add_row("2", "Bob", "bob@example.com")
table.add_row("3", "Charlie", "charlie@example.com")
console.print(table)
# Progress bars
with Progress() as progress:
task = progress.add_task("[green]Processing...", total=100)
while not progress.finished:
progress.update(task, advance=1)
time.sleep(0.01)
# Simple progress with track
for item in track(range(100), description="Processing..."):
time.sleep(0.01)
# Panels
panel = Panel("This is important information", title="Notice", border_style="blue")
console.print(panel)
# Markdown
md = Markdown("""
# Title
This is **bold** and this is *italic*.
- Item 1
- Item 2
- Item 3
""")
console.print(md)
# Status spinner
with console.status("[bold green]Working...") as status:
time.sleep(2)
status.update("[bold blue]Almost done...")
time.sleep(1)
'''
# =============================================================================
# BUILDING A SIMPLE CLI WITHOUT EXTERNAL LIBS
# =============================================================================
@dataclass
class Command:
"""A CLI command definition."""
name: str
description: str
handler: Callable
arguments: list = field(default_factory=list)
class SimpleCLI:
"""A simple CLI framework without external dependencies."""
def __init__(self, name: str, description: str = ""):
self.name = name
self.description = description
self.commands: dict[str, Command] = {}
def command(self, name: str, description: str = ""):
"""Decorator to register a command."""
def decorator(func: Callable):
self.commands[name] = Command(name, description, func)
return func
return decorator
def print_help(self):
"""Print help message."""
print(f"\n{self.name}")
if self.description:
print(f" {self.description}")
print("\nCommands:")
for name, cmd in self.commands.items():
print(f" {name:15} {cmd.description}")
print("\nUse '{} <command> --help' for more information.\n".format(self.name))
def run(self, args: list[str] | None = None):
"""Run the CLI with given arguments."""
if args is None:
args = sys.argv[1:]
if not args or args[0] in ['-h', '--help', 'help']:
self.print_help()
return
command_name = args[0]
if command_name not in self.commands:
print(f"Error: Unknown command '{command_name}'")
self.print_help()
return
command = self.commands[command_name]
command.handler(*args[1:])
# Example usage of SimpleCLI
cli = SimpleCLI("mycli", "A simple demonstration CLI")
@cli.command("hello", "Say hello to someone")
def hello_command(name: str = "World"):
"""Say hello."""
print(f"Hello, {name}!")
@cli.command("add", "Add two numbers")
def add_command(a: str, b: str):
"""Add two numbers."""
try:
result = float(a) + float(b)
print(f"{a} + {b} = {result}")
except ValueError:
print("Error: Please provide valid numbers")
@cli.command("list", "List files in directory")
def list_command(path: str = "."):
"""List files."""
p = Path(path)
if p.exists() and p.is_dir():
for item in p.iterdir():
prefix = "📁" if item.is_dir() else "📄"
print(f" {prefix} {item.name}")
else:
print(f"Error: '{path}' is not a valid directory")
# =============================================================================
# CONFIGURATION FILE HANDLING
# =============================================================================
import json
def load_config_json(path: str) -> dict:
"""Load JSON configuration file."""
with open(path) as f:
return json.load(f)
def load_config_env(prefix: str = "") -> dict:
"""Load configuration from environment variables."""
import os
config = {}
for key, value in os.environ.items():
if prefix and not key.startswith(prefix):
continue
clean_key = key[len(prefix):] if prefix else key
config[clean_key.lower()] = value
return config
# YAML config example (requires pyyaml)
YAML_CONFIG_EXAMPLE = '''
import yaml
def load_config_yaml(path: str) -> dict:
"""Load YAML configuration file."""
with open(path) as f:
return yaml.safe_load(f)
# Example YAML config:
"""
app:
name: MyApp
debug: true
database:
host: localhost
port: 5432
name: myapp
features:
- authentication
- logging
- caching
"""
'''
# TOML config example (Python 3.11+ has tomllib built-in)
TOML_CONFIG_EXAMPLE = '''
import tomllib # Python 3.11+
def load_config_toml(path: str) -> dict:
"""Load TOML configuration file."""
with open(path, "rb") as f:
return tomllib.load(f)
# Example TOML config:
"""
[app]
name = "MyApp"
debug = true
[database]
host = "localhost"
port = 5432
name = "myapp"
[features]
enabled = ["authentication", "logging", "caching"]
"""
'''
# =============================================================================
# TERMINAL COLORS WITHOUT EXTERNAL LIBS
# =============================================================================
class Colors:
"""ANSI color codes for terminal output."""
# Text colors
BLACK = '\033[30m'
RED = '\033[31m'
GREEN = '\033[32m'
YELLOW = '\033[33m'
BLUE = '\033[34m'
MAGENTA = '\033[35m'
CYAN = '\033[36m'
WHITE = '\033[37m'
# Background colors
BG_BLACK = '\033[40m'
BG_RED = '\033[41m'
BG_GREEN = '\033[42m'
BG_YELLOW = '\033[43m'
BG_BLUE = '\033[44m'
# Styles
BOLD = '\033[1m'
DIM = '\033[2m'
ITALIC = '\033[3m'
UNDERLINE = '\033[4m'
# Reset
RESET = '\033[0m'
def colored(text: str, color: str, bold: bool = False) -> str:
"""Apply color to text."""
style = Colors.BOLD if bold else ""
return f"{style}{color}{text}{Colors.RESET}"
def print_success(message: str):
"""Print success message in green."""
print(colored(f"✓ {message}", Colors.GREEN))
def print_error(message: str):
"""Print error message in red."""
print(colored(f"✗ {message}", Colors.RED, bold=True))
def print_warning(message: str):
"""Print warning message in yellow."""
print(colored(f"⚠ {message}", Colors.YELLOW))
def print_info(message: str):
"""Print info message in blue."""
print(colored(f"ℹ {message}", Colors.BLUE))
# =============================================================================
# SIMPLE PROGRESS BAR
# =============================================================================
import time
def progress_bar(
iterable,
total: int | None = None,
prefix: str = "",
length: int = 40,
fill: str = "█"
):
"""
Simple progress bar without external dependencies.
Usage:
for item in progress_bar(items, prefix="Processing"):
process(item)
"""
total = total or len(iterable)
def print_progress(iteration):
percent = iteration / total
filled = int(length * percent)
bar = fill * filled + '-' * (length - filled)
print(f'\r{prefix} |{bar}| {percent:.1%}', end='', flush=True)
for i, item in enumerate(iterable, 1):
yield item
print_progress(i)
print() # New line at the end
# =============================================================================
# INTERACTIVE PROMPTS
# =============================================================================
def prompt(message: str, default: str = "") -> str:
"""Prompt user for input with optional default."""
if default:
result = input(f"{message} [{default}]: ").strip()
return result if result else default
return input(f"{message}: ").strip()
def confirm(message: str, default: bool = False) -> bool:
"""Ask for yes/no confirmation."""
suffix = " [Y/n]" if default else " [y/N]"
response = input(f"{message}{suffix}: ").strip().lower()
if not response:
return default
return response in ('y', 'yes', 'true', '1')
def choose(message: str, choices: list[str], default: int = 0) -> str:
"""Let user choose from a list of options."""
print(message)
for i, choice in enumerate(choices, 1):
marker = ">" if i - 1 == default else " "
print(f" {marker} {i}. {choice}")
while True:
try:
response = input(f"Choose [1-{len(choices)}]: ").strip()
if not response:
return choices[default]
index = int(response) - 1
if 0 <= index < len(choices):
return choices[index]
except ValueError:
pass
print("Invalid choice. Try again.")
# =============================================================================
# DEMONSTRATIONS
# =============================================================================
if __name__ == "__main__":
print("=" * 60)
print("ARGPARSE BASIC EXAMPLE")
print("=" * 60)
argparse_basic_example()
print("\n" + "=" * 60)
print("ARGPARSE SUBCOMMANDS")
print("=" * 60)
argparse_subcommands_example()
print("\n" + "=" * 60)
print("COLORED OUTPUT")
print("=" * 60)
print_success("Operation completed successfully!")
print_error("Something went wrong!")
print_warning("This might cause issues")
print_info("Just FYI...")
print("\n" + "=" * 60)
print("PROGRESS BAR")
print("=" * 60)
items = list(range(50))
for item in progress_bar(items, prefix="Processing"):
time.sleep(0.02)
print("\n" + "=" * 60)
print("SIMPLE CLI DEMO")
print("=" * 60)
cli.run(['hello', 'Python'])
cli.run(['add', '10', '20'])
cli.run(['list', '.'])