Commit 052cd6852c

052cd6852c73f5fe4096e1391f9e90c426fb94c6

parent: 14d8039e4a

Verified · cmc

cmc <hello@cleberg.net> · 2026-05-04 22:12 UTC

fix: ruff format & remove unused home_title var

Layout: unified · split

build/lib/nba/box_score.py +32 −23
@@ -10,7 +10,21 @@ from nba_api.live.nba.endpoints.boxscore import BoxScore
10BOLD = "\033[1m" 10BOLD = "\033[1m"
11END = "\033[0m" 11END = "\033[0m"
12 12
13_HEADERS = ["Player", "Pos", "Min", "Pts", "Reb", "Ast", "Stl", "Blk", "TO", "FG", "3P", "FT", "+/-"] 13_HEADERS = [
14 "Player",
15 "Pos",
16 "Min",
17 "Pts",
18 "Reb",
19 "Ast",
20 "Stl",
21 "Blk",
22 "TO",
23 "FG",
24 "3P",
25 "FT",
26 "+/-",
27]
14 28
15 29
16def fetch_box_score(game_id: str) -> dict: 30def fetch_box_score(game_id: str) -> dict:
@@ -36,21 +50,23 @@ def _player_rows(players: list) -> list:
36 if p.get("status") == "INACTIVE": 50 if p.get("status") == "INACTIVE":
37 continue 51 continue
38 s = p.get("statistics", {}) 52 s = p.get("statistics", {})
39 rows.append([ 53 rows.append(
40 p.get("name", ""), 54 [
41 p.get("position", ""), 55 p.get("name", ""),
42 _parse_minutes(s.get("minutes", "")), 56 p.get("position", ""),
43 s.get("points", 0), 57 _parse_minutes(s.get("minutes", "")),
44 s.get("reboundsTotal", 0), 58 s.get("points", 0),
45 s.get("assists", 0), 59 s.get("reboundsTotal", 0),
46 s.get("steals", 0), 60 s.get("assists", 0),
47 s.get("blocks", 0), 61 s.get("steals", 0),
48 s.get("turnovers", 0), 62 s.get("blocks", 0),
49 f"{s.get('fieldGoalsMade', 0)}/{s.get('fieldGoalsAttempted', 0)}", 63 s.get("turnovers", 0),
50 f"{s.get('threePointersMade', 0)}/{s.get('threePointersAttempted', 0)}", 64 f"{s.get('fieldGoalsMade', 0)}/{s.get('fieldGoalsAttempted', 0)}",
51 f"{s.get('freeThrowsMade', 0)}/{s.get('freeThrowsAttempted', 0)}", 65 f"{s.get('threePointersMade', 0)}/{s.get('threePointersAttempted', 0)}",
52 s.get("plusMinusPoints", 0), 66 f"{s.get('freeThrowsMade', 0)}/{s.get('freeThrowsAttempted', 0)}",
53 ]) 67 s.get("plusMinusPoints", 0),
68 ]
69 )
54 return rows 70 return rows
55 71
56 72
@@ -60,13 +76,6 @@ def get_box_score_tables(data: dict) -> tuple:
60 home = game["homeTeam"] 76 home = game["homeTeam"]
61 away = game["awayTeam"] 77 away = game["awayTeam"]
62 78
63 home_title = (
64 f"{BOLD}{home['teamCity']} {home['teamName']} "
65 f"{home['score']} — {away['score']} "
66 f"{away['teamCity']} {away['teamName']}{END} "
67 f" [{game.get('gameStatusText', '')}]"
68 )
69
70 home_rows = _player_rows(home.get("players", [])) 79 home_rows = _player_rows(home.get("players", []))
71 away_rows = _player_rows(away.get("players", [])) 80 away_rows = _player_rows(away.get("players", []))
72 81
build/lib/nba/cli.py +4 −4
@@ -19,9 +19,7 @@ def nba() -> None:
19 parser.add_argument( 19 parser.add_argument(
20 "--standings", "-st", action="store_true", help="Display the standings" 20 "--standings", "-st", action="store_true", help="Display the standings"
21 ) 21 )
22 parser.add_argument( 22 parser.add_argument("--tui", action="store_true", help="Launch the interactive TUI")
23 "--tui", action="store_true", help="Launch the interactive TUI"
24 )
25 parser.add_argument( 23 parser.add_argument(
26 "--refresh", 24 "--refresh",
27 type=int, 25 type=int,
@@ -47,4 +45,6 @@ def nba() -> None:
47 elif args.standings: 45 elif args.standings:
48 standings.build_standings(ranks) 46 standings.build_standings(ranks)
49 else: 47 else:
50 print("Please specify --scores or --standings (or use --tui for interactive mode)") 48 print(
49 "Please specify --scores or --standings (or use --tui for interactive mode)"
50 )
build/lib/nba/leaders.py +13 −13
@@ -25,20 +25,23 @@ CATEGORIES = [
25 25
26# Extra columns to show alongside RANK, PLAYER, TEAM, GP for each category 26# Extra columns to show alongside RANK, PLAYER, TEAM, GP for each category
27_EXTRA_COLS = { 27_EXTRA_COLS = {
28 "PTS": ["PTS", "FGM", "FGA", "FG_PCT", "FTM", "FTA", "FT_PCT"], 28 "PTS": ["PTS", "FGM", "FGA", "FG_PCT", "FTM", "FTA", "FT_PCT"],
29 "REB": ["REB", "OREB", "DREB", "GP"], 29 "REB": ["REB", "OREB", "DREB", "GP"],
30 "AST": ["AST", "TOV", "AST_TOV", "GP"], 30 "AST": ["AST", "TOV", "AST_TOV", "GP"],
31 "STL": ["STL", "TOV", "GP"], 31 "STL": ["STL", "TOV", "GP"],
32 "BLK": ["BLK", "PF", "GP"], 32 "BLK": ["BLK", "PF", "GP"],
33 "EFF": ["EFF", "PTS", "REB", "AST", "GP"], 33 "EFF": ["EFF", "PTS", "REB", "AST", "GP"],
34 "FG_PCT": ["FG_PCT", "FGM", "FGA", "PTS"], 34 "FG_PCT": ["FG_PCT", "FGM", "FGA", "PTS"],
35 "FT_PCT": ["FT_PCT", "FTM", "FTA", "PTS"], 35 "FT_PCT": ["FT_PCT", "FTM", "FTA", "PTS"],
36 "FG3_PCT":["FG3_PCT", "FG3M", "FG3A", "PTS"], 36 "FG3_PCT": ["FG3_PCT", "FG3M", "FG3A", "PTS"],
37} 37}
38 38
39_DISPLAY_NAMES = { 39_DISPLAY_NAMES = {
40 "FG_PCT": "FG%", "FT_PCT": "FT%", "FG3_PCT": "3P%", 40 "FG_PCT": "FG%",
41 "FG3M": "3PM", "FG3A": "3PA", 41 "FT_PCT": "FT%",
42 "FG3_PCT": "3P%",
43 "FG3M": "3PM",
44 "FG3A": "3PA",
42 "AST_TOV": "AST/TO", 45 "AST_TOV": "AST/TO",
43} 46}
44 47
@@ -61,10 +64,7 @@ def get_leaders_table(data: dict, category: str = "PTS") -> str:
61 wanted = base + extra 64 wanted = base + extra
62 65
63 idx = {h: i for i, h in enumerate(headers)} 66 idx = {h: i for i, h in enumerate(headers)}
64 table_data = [ 67 table_data = [[row[idx[col]] for col in wanted if col in idx] for row in rows[:25]]
65 [row[idx[col]] for col in wanted if col in idx]
66 for row in rows[:25]
67 ]
68 display_headers = [_DISPLAY_NAMES.get(c, c) for c in wanted if c in idx] 68 display_headers = [_DISPLAY_NAMES.get(c, c) for c in wanted if c in idx]
69 69
70 cat_label = dict(CATEGORIES).get(category, category) 70 cat_label = dict(CATEGORIES).get(category, category)
build/lib/nba/playoff.py +26 −13
@@ -21,6 +21,7 @@ def fetch_playoff_picture() -> dict:
21 21
22def _clinch_status(row: list, idx: dict) -> str: 22def _clinch_status(row: list, idx: dict) -> str:
23 """Return a color-coded status string from clinch/elimination columns.""" 23 """Return a color-coded status string from clinch/elimination columns."""
24
24 def val(col): 25 def val(col):
25 return row[idx[col]] if col in idx else None 26 return row[idx[col]] if col in idx else None
26 27
@@ -54,19 +55,31 @@ def _build_conference_table(result_sets: list, name: str) -> str:
54 losses = get(row, "LOSSES") 55 losses = get(row, "LOSSES")
55 pct = get(row, "PCT") 56 pct = get(row, "PCT")
56 pct_str = f"{float(pct):.3f}" if pct not in ("", None) else "" 57 pct_str = f"{float(pct):.3f}" if pct not in ("", None) else ""
57 table_data.append([ 58 table_data.append(
58 get(row, "RANK"), 59 [
59 get(row, "TEAM"), 60 get(row, "RANK"),
60 f"{wins}-{losses}", 61 get(row, "TEAM"),
61 pct_str, 62 f"{wins}-{losses}",
62 get(row, "GB"), 63 pct_str,
63 get(row, "HOME"), 64 get(row, "GB"),
64 get(row, "AWAY"), 65 get(row, "HOME"),
65 get(row, "CONF"), 66 get(row, "AWAY"),
66 _clinch_status(row, idx), 67 get(row, "CONF"),
67 ]) 68 _clinch_status(row, idx),
68 69 ]
69 display_headers = ["#", "Team", "W-L", "PCT", "GB", "HOME", "AWAY", "CONF", "Status"] 70 )
71
72 display_headers = [
73 "#",
74 "Team",
75 "W-L",
76 "PCT",
77 "GB",
78 "HOME",
79 "AWAY",
80 "CONF",
81 "Status",
82 ]
70 conf_label = "Eastern" if "East" in name else "Western" 83 conf_label = "Eastern" if "East" in name else "Western"
71 title = f"{BOLD}{conf_label} Conference Playoff Picture:{END}" 84 title = f"{BOLD}{conf_label} Conference Playoff Picture:{END}"
72 return title + "\n" + tabulate(table_data, headers=display_headers, tablefmt="grid") 85 return title + "\n" + tabulate(table_data, headers=display_headers, tablefmt="grid")
build/lib/nba/standings.py +10 −5
@@ -27,7 +27,9 @@ def _build_conference_table(standings, conference: str) -> str:
27 streak = team[35] 27 streak = team[35]
28 28
29 strk_color = ( 29 strk_color = (
30 f"{RED}{streak}{END}" if int(streak) < 0 else f"{GREEN}{streak}{END}" 30 f"{RED}{streak}{END}"
31 if int(streak) < 0
32 else f"{GREEN}{streak}{END}"
31 ) 33 )
32 34
33 data.append( 35 data.append(
@@ -47,9 +49,8 @@ def _build_conference_table(standings, conference: str) -> str:
47 49
48 headers = ["Rank", "Team", "W-L", "PCT", "GB", "STRK", "L10", "HOME", "AWAY"] 50 headers = ["Rank", "Team", "W-L", "PCT", "GB", "STRK", "L10", "HOME", "AWAY"]
49 label = "Eastern" if conference == "East" else "Western" 51 label = "Eastern" if conference == "East" else "Western"
50 return ( 52 return f"{BOLD}{label} Conference Standings:{END}\n" + tabulate(
51 f"{BOLD}{label} Conference Standings:{END}\n" 53 data, headers=headers, tablefmt="grid"
52 + tabulate(data, headers=headers, tablefmt="grid")
53 ) 54 )
54 55
55 56
@@ -73,7 +74,11 @@ def get_standings_tables(standings) -> str:
73 Returns: 74 Returns:
74 str: Formatted standings string with ANSI color codes for both conferences. 75 str: Formatted standings string with ANSI color codes for both conferences.
75 """ 76 """
76 return get_east_standings_table(standings) + "\n\n" + get_west_standings_table(standings) 77 return (
78 get_east_standings_table(standings)
79 + "\n\n"
80 + get_west_standings_table(standings)
81 )
77 82
78 83
79def build_standings(standings) -> None: 84def build_standings(standings) -> None:
build/lib/nba/tui/app.py +15 −5
@@ -182,11 +182,15 @@ class NBAApp(App):
182 self.query_one(TabbedContent).active = "boxscore" 182 self.query_one(TabbedContent).active = "boxscore"
183 183
184 async def action_prev_category(self) -> None: 184 async def action_prev_category(self) -> None:
185 self._leaders_cat_idx = (self._leaders_cat_idx - 1) % len(leaders_mod.CATEGORIES) 185 self._leaders_cat_idx = (self._leaders_cat_idx - 1) % len(
186 leaders_mod.CATEGORIES
187 )
186 await self._refresh_leaders() 188 await self._refresh_leaders()
187 189
188 async def action_next_category(self) -> None: 190 async def action_next_category(self) -> None:
189 self._leaders_cat_idx = (self._leaders_cat_idx + 1) % len(leaders_mod.CATEGORIES) 191 self._leaders_cat_idx = (self._leaders_cat_idx + 1) % len(
192 leaders_mod.CATEGORIES
193 )
190 await self._refresh_leaders() 194 await self._refresh_leaders()
191 195
192 # ------------------------------------------------------------------ # 196 # ------------------------------------------------------------------ #
@@ -198,13 +202,17 @@ class NBAApp(App):
198 self.query_one("#leaders-content", Static).update(f"Loading {label} leaders...") 202 self.query_one("#leaders-content", Static).update(f"Loading {label} leaders...")
199 loop = asyncio.get_event_loop() 203 loop = asyncio.get_event_loop()
200 try: 204 try:
201 data = await loop.run_in_executor(None, lambda: leaders_mod.fetch_leaders(cat)) 205 data = await loop.run_in_executor(
206 None, lambda: leaders_mod.fetch_leaders(cat)
207 )
202 self._leaders_data = data 208 self._leaders_data = data
203 self.query_one("#leaders-content", Static).update( 209 self.query_one("#leaders-content", Static).update(
204 Text.from_ansi(leaders_mod.get_leaders_table(data, cat)) 210 Text.from_ansi(leaders_mod.get_leaders_table(data, cat))
205 ) 211 )
206 except Exception as exc: 212 except Exception as exc:
207 self.query_one("#leaders-content", Static).update(f"Error loading leaders: {exc}") 213 self.query_one("#leaders-content", Static).update(
214 f"Error loading leaders: {exc}"
215 )
208 216
209 async def _load_box_score(self, game_idx: int) -> None: 217 async def _load_box_score(self, game_idx: int) -> None:
210 if not self._games: 218 if not self._games:
@@ -233,5 +241,7 @@ class NBAApp(App):
233 self.query_one("#home-content", Static).update(Text.from_ansi(home_table)) 241 self.query_one("#home-content", Static).update(Text.from_ansi(home_table))
234 self.query_one("#away-content", Static).update(Text.from_ansi(away_table)) 242 self.query_one("#away-content", Static).update(Text.from_ansi(away_table))
235 except Exception as exc: 243 except Exception as exc:
236 self.query_one("#home-content", Static).update(f"Error loading box score: {exc}") 244 self.query_one("#home-content", Static).update(
245 f"Error loading box score: {exc}"
246 )
237 self.query_one("#away-content", Static).update("") 247 self.query_one("#away-content", Static).update("")
nba/box_score.py +32 −23
@@ -10,7 +10,21 @@ from nba_api.live.nba.endpoints.boxscore import BoxScore
10BOLD = "\033[1m" 10BOLD = "\033[1m"
11END = "\033[0m" 11END = "\033[0m"
12 12
13_HEADERS = ["Player", "Pos", "Min", "Pts", "Reb", "Ast", "Stl", "Blk", "TO", "FG", "3P", "FT", "+/-"] 13_HEADERS = [
14 "Player",
15 "Pos",
16 "Min",
17 "Pts",
18 "Reb",
19 "Ast",
20 "Stl",
21 "Blk",
22 "TO",
23 "FG",
24 "3P",
25 "FT",
26 "+/-",
27]
14 28
15 29
16def fetch_box_score(game_id: str) -> dict: 30def fetch_box_score(game_id: str) -> dict:
@@ -36,21 +50,23 @@ def _player_rows(players: list) -> list:
36 if p.get("status") == "INACTIVE": 50 if p.get("status") == "INACTIVE":
37 continue 51 continue
38 s = p.get("statistics", {}) 52 s = p.get("statistics", {})
39 rows.append([ 53 rows.append(
40 p.get("name", ""), 54 [
41 p.get("position", ""), 55 p.get("name", ""),
42 _parse_minutes(s.get("minutes", "")), 56 p.get("position", ""),
43 s.get("points", 0), 57 _parse_minutes(s.get("minutes", "")),
44 s.get("reboundsTotal", 0), 58 s.get("points", 0),
45 s.get("assists", 0), 59 s.get("reboundsTotal", 0),
46 s.get("steals", 0), 60 s.get("assists", 0),
47 s.get("blocks", 0), 61 s.get("steals", 0),
48 s.get("turnovers", 0), 62 s.get("blocks", 0),
49 f"{s.get('fieldGoalsMade', 0)}/{s.get('fieldGoalsAttempted', 0)}", 63 s.get("turnovers", 0),
50 f"{s.get('threePointersMade', 0)}/{s.get('threePointersAttempted', 0)}", 64 f"{s.get('fieldGoalsMade', 0)}/{s.get('fieldGoalsAttempted', 0)}",
51 f"{s.get('freeThrowsMade', 0)}/{s.get('freeThrowsAttempted', 0)}", 65 f"{s.get('threePointersMade', 0)}/{s.get('threePointersAttempted', 0)}",
52 s.get("plusMinusPoints", 0), 66 f"{s.get('freeThrowsMade', 0)}/{s.get('freeThrowsAttempted', 0)}",
53 ]) 67 s.get("plusMinusPoints", 0),
68 ]
69 )
54 return rows 70 return rows
55 71
56 72
@@ -60,13 +76,6 @@ def get_box_score_tables(data: dict) -> tuple:
60 home = game["homeTeam"] 76 home = game["homeTeam"]
61 away = game["awayTeam"] 77 away = game["awayTeam"]
62 78
63 home_title = (
64 f"{BOLD}{home['teamCity']} {home['teamName']} "
65 f"{home['score']} — {away['score']} "
66 f"{away['teamCity']} {away['teamName']}{END} "
67 f" [{game.get('gameStatusText', '')}]"
68 )
69
70 home_rows = _player_rows(home.get("players", [])) 79 home_rows = _player_rows(home.get("players", []))
71 away_rows = _player_rows(away.get("players", [])) 80 away_rows = _player_rows(away.get("players", []))
72 81
nba/cli.py +4 −4
@@ -19,9 +19,7 @@ def nba() -> None:
19 parser.add_argument( 19 parser.add_argument(
20 "--standings", "-st", action="store_true", help="Display the standings" 20 "--standings", "-st", action="store_true", help="Display the standings"
21 ) 21 )
22 parser.add_argument( 22 parser.add_argument("--tui", action="store_true", help="Launch the interactive TUI")
23 "--tui", action="store_true", help="Launch the interactive TUI"
24 )
25 parser.add_argument( 23 parser.add_argument(
26 "--refresh", 24 "--refresh",
27 type=int, 25 type=int,
@@ -47,4 +45,6 @@ def nba() -> None:
47 elif args.standings: 45 elif args.standings:
48 standings.build_standings(ranks) 46 standings.build_standings(ranks)
49 else: 47 else:
50 print("Please specify --scores or --standings (or use --tui for interactive mode)") 48 print(
49 "Please specify --scores or --standings (or use --tui for interactive mode)"
50 )
nba/leaders.py +13 −13
@@ -25,20 +25,23 @@ CATEGORIES = [
25 25
26# Extra columns to show alongside RANK, PLAYER, TEAM, GP for each category 26# Extra columns to show alongside RANK, PLAYER, TEAM, GP for each category
27_EXTRA_COLS = { 27_EXTRA_COLS = {
28 "PTS": ["PTS", "FGM", "FGA", "FG_PCT", "FTM", "FTA", "FT_PCT"], 28 "PTS": ["PTS", "FGM", "FGA", "FG_PCT", "FTM", "FTA", "FT_PCT"],
29 "REB": ["REB", "OREB", "DREB", "GP"], 29 "REB": ["REB", "OREB", "DREB", "GP"],
30 "AST": ["AST", "TOV", "AST_TOV", "GP"], 30 "AST": ["AST", "TOV", "AST_TOV", "GP"],
31 "STL": ["STL", "TOV", "GP"], 31 "STL": ["STL", "TOV", "GP"],
32 "BLK": ["BLK", "PF", "GP"], 32 "BLK": ["BLK", "PF", "GP"],
33 "EFF": ["EFF", "PTS", "REB", "AST", "GP"], 33 "EFF": ["EFF", "PTS", "REB", "AST", "GP"],
34 "FG_PCT": ["FG_PCT", "FGM", "FGA", "PTS"], 34 "FG_PCT": ["FG_PCT", "FGM", "FGA", "PTS"],
35 "FT_PCT": ["FT_PCT", "FTM", "FTA", "PTS"], 35 "FT_PCT": ["FT_PCT", "FTM", "FTA", "PTS"],
36 "FG3_PCT":["FG3_PCT", "FG3M", "FG3A", "PTS"], 36 "FG3_PCT": ["FG3_PCT", "FG3M", "FG3A", "PTS"],
37} 37}
38 38
39_DISPLAY_NAMES = { 39_DISPLAY_NAMES = {
40 "FG_PCT": "FG%", "FT_PCT": "FT%", "FG3_PCT": "3P%", 40 "FG_PCT": "FG%",
41 "FG3M": "3PM", "FG3A": "3PA", 41 "FT_PCT": "FT%",
42 "FG3_PCT": "3P%",
43 "FG3M": "3PM",
44 "FG3A": "3PA",
42 "AST_TOV": "AST/TO", 45 "AST_TOV": "AST/TO",
43} 46}
44 47
@@ -61,10 +64,7 @@ def get_leaders_table(data: dict, category: str = "PTS") -> str:
61 wanted = base + extra 64 wanted = base + extra
62 65
63 idx = {h: i for i, h in enumerate(headers)} 66 idx = {h: i for i, h in enumerate(headers)}
64 table_data = [ 67 table_data = [[row[idx[col]] for col in wanted if col in idx] for row in rows[:25]]
65 [row[idx[col]] for col in wanted if col in idx]
66 for row in rows[:25]
67 ]
68 display_headers = [_DISPLAY_NAMES.get(c, c) for c in wanted if c in idx] 68 display_headers = [_DISPLAY_NAMES.get(c, c) for c in wanted if c in idx]
69 69
70 cat_label = dict(CATEGORIES).get(category, category) 70 cat_label = dict(CATEGORIES).get(category, category)
nba/playoff.py +26 −13
@@ -21,6 +21,7 @@ def fetch_playoff_picture() -> dict:
21 21
22def _clinch_status(row: list, idx: dict) -> str: 22def _clinch_status(row: list, idx: dict) -> str:
23 """Return a color-coded status string from clinch/elimination columns.""" 23 """Return a color-coded status string from clinch/elimination columns."""
24
24 def val(col): 25 def val(col):
25 return row[idx[col]] if col in idx else None 26 return row[idx[col]] if col in idx else None
26 27
@@ -54,19 +55,31 @@ def _build_conference_table(result_sets: list, name: str) -> str:
54 losses = get(row, "LOSSES") 55 losses = get(row, "LOSSES")
55 pct = get(row, "PCT") 56 pct = get(row, "PCT")
56 pct_str = f"{float(pct):.3f}" if pct not in ("", None) else "" 57 pct_str = f"{float(pct):.3f}" if pct not in ("", None) else ""
57 table_data.append([ 58 table_data.append(
58 get(row, "RANK"), 59 [
59 get(row, "TEAM"), 60 get(row, "RANK"),
60 f"{wins}-{losses}", 61 get(row, "TEAM"),
61 pct_str, 62 f"{wins}-{losses}",
62 get(row, "GB"), 63 pct_str,
63 get(row, "HOME"), 64 get(row, "GB"),
64 get(row, "AWAY"), 65 get(row, "HOME"),
65 get(row, "CONF"), 66 get(row, "AWAY"),
66 _clinch_status(row, idx), 67 get(row, "CONF"),
67 ]) 68 _clinch_status(row, idx),
68 69 ]
69 display_headers = ["#", "Team", "W-L", "PCT", "GB", "HOME", "AWAY", "CONF", "Status"] 70 )
71
72 display_headers = [
73 "#",
74 "Team",
75 "W-L",
76 "PCT",
77 "GB",
78 "HOME",
79 "AWAY",
80 "CONF",
81 "Status",
82 ]
70 conf_label = "Eastern" if "East" in name else "Western" 83 conf_label = "Eastern" if "East" in name else "Western"
71 title = f"{BOLD}{conf_label} Conference Playoff Picture:{END}" 84 title = f"{BOLD}{conf_label} Conference Playoff Picture:{END}"
72 return title + "\n" + tabulate(table_data, headers=display_headers, tablefmt="grid") 85 return title + "\n" + tabulate(table_data, headers=display_headers, tablefmt="grid")
nba/standings.py +10 −5
@@ -27,7 +27,9 @@ def _build_conference_table(standings, conference: str) -> str:
27 streak = team[35] 27 streak = team[35]
28 28
29 strk_color = ( 29 strk_color = (
30 f"{RED}{streak}{END}" if int(streak) < 0 else f"{GREEN}{streak}{END}" 30 f"{RED}{streak}{END}"
31 if int(streak) < 0
32 else f"{GREEN}{streak}{END}"
31 ) 33 )
32 34
33 data.append( 35 data.append(
@@ -47,9 +49,8 @@ def _build_conference_table(standings, conference: str) -> str:
47 49
48 headers = ["Rank", "Team", "W-L", "PCT", "GB", "STRK", "L10", "HOME", "AWAY"] 50 headers = ["Rank", "Team", "W-L", "PCT", "GB", "STRK", "L10", "HOME", "AWAY"]
49 label = "Eastern" if conference == "East" else "Western" 51 label = "Eastern" if conference == "East" else "Western"
50 return ( 52 return f"{BOLD}{label} Conference Standings:{END}\n" + tabulate(
51 f"{BOLD}{label} Conference Standings:{END}\n" 53 data, headers=headers, tablefmt="grid"
52 + tabulate(data, headers=headers, tablefmt="grid")
53 ) 54 )
54 55
55 56
@@ -73,7 +74,11 @@ def get_standings_tables(standings) -> str:
73 Returns: 74 Returns:
74 str: Formatted standings string with ANSI color codes for both conferences. 75 str: Formatted standings string with ANSI color codes for both conferences.
75 """ 76 """
76 return get_east_standings_table(standings) + "\n\n" + get_west_standings_table(standings) 77 return (
78 get_east_standings_table(standings)
79 + "\n\n"
80 + get_west_standings_table(standings)
81 )
77 82
78 83
79def build_standings(standings) -> None: 84def build_standings(standings) -> None:
nba/tui/app.py +15 −5
@@ -182,11 +182,15 @@ class NBAApp(App):
182 self.query_one(TabbedContent).active = "boxscore" 182 self.query_one(TabbedContent).active = "boxscore"
183 183
184 async def action_prev_category(self) -> None: 184 async def action_prev_category(self) -> None:
185 self._leaders_cat_idx = (self._leaders_cat_idx - 1) % len(leaders_mod.CATEGORIES) 185 self._leaders_cat_idx = (self._leaders_cat_idx - 1) % len(
186 leaders_mod.CATEGORIES
187 )
186 await self._refresh_leaders() 188 await self._refresh_leaders()
187 189
188 async def action_next_category(self) -> None: 190 async def action_next_category(self) -> None:
189 self._leaders_cat_idx = (self._leaders_cat_idx + 1) % len(leaders_mod.CATEGORIES) 191 self._leaders_cat_idx = (self._leaders_cat_idx + 1) % len(
192 leaders_mod.CATEGORIES
193 )
190 await self._refresh_leaders() 194 await self._refresh_leaders()
191 195
192 # ------------------------------------------------------------------ # 196 # ------------------------------------------------------------------ #
@@ -198,13 +202,17 @@ class NBAApp(App):
198 self.query_one("#leaders-content", Static).update(f"Loading {label} leaders...") 202 self.query_one("#leaders-content", Static).update(f"Loading {label} leaders...")
199 loop = asyncio.get_event_loop() 203 loop = asyncio.get_event_loop()
200 try: 204 try:
201 data = await loop.run_in_executor(None, lambda: leaders_mod.fetch_leaders(cat)) 205 data = await loop.run_in_executor(
206 None, lambda: leaders_mod.fetch_leaders(cat)
207 )
202 self._leaders_data = data 208 self._leaders_data = data
203 self.query_one("#leaders-content", Static).update( 209 self.query_one("#leaders-content", Static).update(
204 Text.from_ansi(leaders_mod.get_leaders_table(data, cat)) 210 Text.from_ansi(leaders_mod.get_leaders_table(data, cat))
205 ) 211 )
206 except Exception as exc: 212 except Exception as exc:
207 self.query_one("#leaders-content", Static).update(f"Error loading leaders: {exc}") 213 self.query_one("#leaders-content", Static).update(
214 f"Error loading leaders: {exc}"
215 )
208 216
209 async def _load_box_score(self, game_idx: int) -> None: 217 async def _load_box_score(self, game_idx: int) -> None:
210 if not self._games: 218 if not self._games:
@@ -233,5 +241,7 @@ class NBAApp(App):
233 self.query_one("#home-content", Static).update(Text.from_ansi(home_table)) 241 self.query_one("#home-content", Static).update(Text.from_ansi(home_table))
234 self.query_one("#away-content", Static).update(Text.from_ansi(away_table)) 242 self.query_one("#away-content", Static).update(Text.from_ansi(away_table))
235 except Exception as exc: 243 except Exception as exc:
236 self.query_one("#home-content", Static).update(f"Error loading box score: {exc}") 244 self.query_one("#home-content", Static).update(
245 f"Error loading box score: {exc}"
246 )
237 self.query_one("#away-content", Static).update("") 247 self.query_one("#away-content", Static).update("")