Coverage for cli.py: 0.00%
133 statements
« prev ^ index » next coverage.py v7.10.6, created at 2026-04-15 13:02 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2026-04-15 13:02 +0000
1#!/usr/bin/env python3
2"""
3CLI tool for managing the sports league.
4Quick way to add games and manage data via the backend API.
5"""
7import sys
8from datetime import datetime
10import httpx
11import typer
12from rich.console import Console
13from rich.prompt import Confirm, IntPrompt, Prompt
14from rich.table import Table
16app = typer.Typer()
17console = Console()
19# API base URL - adjust if your backend runs on a different port
20API_BASE_URL = "http://localhost:8000"
23def get_teams():
24 """Fetch all teams from the API."""
25 try:
26 response = httpx.get(f"{API_BASE_URL}/api/teams")
27 response.raise_for_status()
28 return response.json()
29 except httpx.RequestError as e:
30 console.print(f"[red]Error connecting to API: {e}[/red]")
31 sys.exit(1)
32 except httpx.HTTPStatusError as e:
33 console.print(f"[red]API error: {e}[/red]")
34 sys.exit(1)
37@app.command()
38def add_game(
39 date: str | None = typer.Option(None, "--date", "-d", help="Game date (YYYY-MM-DD)"),
40 home_team: str | None = typer.Option(None, "--home", "-h", help="Home team name"),
41 away_team: str | None = typer.Option(None, "--away", "-a", help="Away team name"),
42 home_score: int | None = typer.Option(None, "--home-score", "-hs", help="Home team score"),
43 away_score: int | None = typer.Option(None, "--away-score", "-as", help="Away team score"),
44):
45 """Add a new game to the league."""
46 console.print("[bold cyan]Add New Game[/bold cyan]\n")
48 # Get list of teams for validation and display
49 teams = get_teams()
50 team_names = [team["name"] for team in teams]
52 # Interactive mode if not all parameters provided
53 if not all([date, home_team, away_team, home_score is not None, away_score is not None]):
54 # Show available teams
55 table = Table(title="Available Teams")
56 table.add_column("Team Name", style="cyan")
57 table.add_column("City", style="green")
59 for team in sorted(teams, key=lambda x: x["name"]):
60 table.add_row(team["name"], team["city"])
62 console.print(table)
63 console.print()
65 # Get game details interactively
66 if not date:
67 default_date = datetime.now().strftime("%Y-%m-%d")
68 date = Prompt.ask("Game date (YYYY-MM-DD)", default=default_date)
70 if not home_team:
71 home_team = Prompt.ask("Home team", choices=team_names)
73 if not away_team:
74 # Filter out home team from choices
75 away_choices = [t for t in team_names if t != home_team]
76 away_team = Prompt.ask("Away team", choices=away_choices)
78 if home_score is None:
79 home_score = IntPrompt.ask("Home team score")
81 if away_score is None:
82 away_score = IntPrompt.ask("Away team score")
84 # Validate teams
85 if home_team not in team_names:
86 console.print(f"[red]Error: '{home_team}' is not a valid team[/red]")
87 return
89 if away_team not in team_names:
90 console.print(f"[red]Error: '{away_team}' is not a valid team[/red]")
91 return
93 if home_team == away_team:
94 console.print("[red]Error: Home and away teams cannot be the same[/red]")
95 return
97 # Validate date format
98 try:
99 datetime.strptime(date, "%Y-%m-%d")
100 except ValueError:
101 console.print("[red]Error: Invalid date format. Use YYYY-MM-DD[/red]")
102 return
104 # Display game summary
105 console.print("\n[bold]Game Summary:[/bold]")
106 console.print(f"Date: [cyan]{date}[/cyan]")
107 console.print(f"Home: [green]{home_team}[/green] - Score: [yellow]{home_score}[/yellow]")
108 console.print(f"Away: [blue]{away_team}[/blue] - Score: [yellow]{away_score}[/yellow]")
110 # Confirm before submitting
111 if not Confirm.ask("\nAdd this game?"):
112 console.print("[yellow]Game not added.[/yellow]")
113 return
115 # Submit to API
116 game_data = {
117 "game_date": date,
118 "home_team": home_team,
119 "away_team": away_team,
120 "home_score": home_score,
121 "away_score": away_score,
122 }
124 try:
125 response = httpx.post(f"{API_BASE_URL}/api/games", json=game_data)
126 response.raise_for_status()
127 console.print("[green]✓ Game added successfully![/green]")
128 except httpx.HTTPStatusError as e:
129 console.print(f"[red]Error adding game: {e.response.text}[/red]")
130 except httpx.RequestError as e:
131 console.print(f"[red]Error connecting to API: {e}[/red]")
134@app.command()
135def list_teams():
136 """List all teams in the league."""
137 teams = get_teams()
139 table = Table(title="League Teams")
140 table.add_column("Team Name", style="cyan")
141 table.add_column("City", style="green")
143 for team in sorted(teams, key=lambda x: x["name"]):
144 table.add_row(team["name"], team["city"])
146 console.print(table)
147 console.print(f"\n[dim]Total teams: {len(teams)}[/dim]")
150@app.command()
151def recent_games(limit: int = typer.Option(10, "--limit", "-l", help="Number of games to show")):
152 """Show recent games."""
153 try:
154 response = httpx.get(f"{API_BASE_URL}/api/games")
155 response.raise_for_status()
156 games = response.json()
158 # Sort by date and get recent games
159 games.sort(key=lambda x: x["game_date"], reverse=True)
160 recent = games[:limit]
162 table = Table(title=f"Recent {limit} Games")
163 table.add_column("Date", style="cyan")
164 table.add_column("Home Team", style="green")
165 table.add_column("Score", style="yellow", justify="center")
166 table.add_column("Away Team", style="blue")
168 for game in recent:
169 score = f"{game['home_score']} - {game['away_score']}"
170 table.add_row(game["game_date"], game["home_team"], score, game["away_team"])
172 console.print(table)
174 except httpx.RequestError as e:
175 console.print(f"[red]Error connecting to API: {e}[/red]")
176 except httpx.HTTPStatusError as e:
177 console.print(f"[red]API error: {e}[/red]")
180@app.command()
181def table():
182 """Show the current league table."""
183 try:
184 response = httpx.get(f"{API_BASE_URL}/api/table")
185 response.raise_for_status()
186 standings = response.json()
188 table = Table(title="League Table")
189 table.add_column("Pos", style="dim", width=4)
190 table.add_column("Team", style="cyan")
191 table.add_column("P", justify="right", width=4)
192 table.add_column("W", justify="right", width=4)
193 table.add_column("D", justify="right", width=4)
194 table.add_column("L", justify="right", width=4)
195 table.add_column("GF", justify="right", width=4)
196 table.add_column("GA", justify="right", width=4)
197 table.add_column("GD", justify="right", width=4)
198 table.add_column("Pts", style="bold yellow", justify="right", width=4)
200 for i, team in enumerate(standings, 1):
201 table.add_row(
202 str(i),
203 team["team"],
204 str(team["played"]),
205 str(team["wins"]),
206 str(team["draws"]),
207 str(team["losses"]),
208 str(team["goals_for"]),
209 str(team["goals_against"]),
210 str(team["goal_difference"]),
211 str(team["points"]),
212 )
214 console.print(table)
216 except httpx.RequestError as e:
217 console.print(f"[red]Error connecting to API: {e}[/red]")
218 except httpx.HTTPStatusError as e:
219 console.print(f"[red]API error: {e}[/red]")
222def main():
223 """Main entry point for the CLI."""
224 app()
227if __name__ == "__main__":
228 main()