From 61202b2a70e5a7668fa3d1ef0405bdef632e87d9 Mon Sep 17 00:00:00 2001 From: josh Date: Sun, 19 Apr 2026 11:05:35 -0400 Subject: [PATCH] feat: sort scheduled games by start time instead of hype Pre-game listings are more intuitive in chronological order than ranked by pregame importance. LIVE and FINAL keep sorting by Priority desc. Co-Authored-By: Claude Opus 4.7 --- app/games.py | 11 ++++- tests/test_games.py | 118 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/app/games.py b/app/games.py index 1d5ba0c..61c22a6 100644 --- a/app/games.py +++ b/app/games.py @@ -76,6 +76,7 @@ def parse_games(scoreboard_data): "total": total_priority, }, "Start Time": get_start_time(game), + "Start Time UTC": game.get("startTimeUTC", ""), "Home Record": format_record(game["homeTeam"]["record"]) if game["gameState"] in ["PRE", "FUT"] else "N/A", @@ -98,8 +99,14 @@ def parse_games(scoreboard_data): } ) - # Sort games based on priority - return sorted(extracted_info, key=lambda x: x["Priority"], reverse=True) + def _sort_key(g): + if g["Game State"] == "PRE": + # Earliest start first — ISO-8601 sorts correctly as a string + return (0, g["Start Time UTC"], 0) + # LIVE / FINAL — highest priority first + return (1, "", -g["Priority"]) + + return sorted(extracted_info, key=_sort_key) def get_comeback_bonus(game): diff --git a/tests/test_games.py b/tests/test_games.py index 097036a..21b152b 100644 --- a/tests/test_games.py +++ b/tests/test_games.py @@ -123,6 +123,124 @@ class TestParseGames: def test_returns_empty_list_for_empty_dict(self): assert parse_games({}) == [] + def test_pre_games_sorted_by_start_time_ascending(self, mocker): + mocker.patch( + "app.games.get_team_standings", + return_value={ + "league_sequence": 16, + "league_l10_sequence": 16, + "division_abbrev": "ATL", + "conference_abbrev": "E", + "games_played": 40, + "wildcard_sequence": 16, + }, + ) + late = make_game( + game_state="FUT", + home_name="Rangers", + away_name="Devils", + start_time_utc="2024-04-10T22:00:00Z", + ) + early = make_game( + game_state="FUT", + home_name="Bruins", + away_name="Canadiens", + start_time_utc="2024-04-10T19:00:00Z", + ) + next_day = make_game( + game_state="FUT", + home_name="Kings", + away_name="Ducks", + start_time_utc="2024-04-11T00:30:00Z", + ) + + result = parse_games({"games": [late, next_day, early]}) + pre_games = [g for g in result if g["Game State"] == "PRE"] + names = [g["Home Team"] for g in pre_games] + assert names == ["Bruins", "Rangers", "Kings"] + + def test_live_games_still_sorted_by_priority_descending(self, mocker): + mocker.patch( + "app.games.get_team_standings", + return_value={ + "league_sequence": 16, + "league_l10_sequence": 16, + "division_abbrev": "ATL", + "conference_abbrev": "E", + "games_played": 40, + "wildcard_sequence": 16, + }, + ) + # Late P3 tied — high priority + high = make_game( + game_state="LIVE", + home_name="Rangers", + away_name="Devils", + home_score=2, + away_score=2, + period=3, + seconds_remaining=60, + ) + # Early P1 blowout — low priority + low = make_game( + game_state="LIVE", + home_name="Bruins", + away_name="Canadiens", + home_score=5, + away_score=0, + period=1, + seconds_remaining=900, + ) + + result = parse_games({"games": [low, high]}) + live_games = [g for g in result if g["Game State"] == "LIVE"] + assert live_games[0]["Home Team"] == "Rangers" + assert live_games[1]["Home Team"] == "Bruins" + + def test_pre_games_ignore_priority_even_if_nonzero(self, mocker): + # Give one team standings that maximize importance, another that minimize it + def fake_standings(name): + if name == "Bruins": + return { + "league_sequence": 1, + "league_l10_sequence": 1, + "division_abbrev": "ATL", + "conference_abbrev": "E", + "games_played": 80, + "wildcard_sequence": 18, + } + return { + "league_sequence": 32, + "league_l10_sequence": 32, + "division_abbrev": "PAC", + "conference_abbrev": "W", + "games_played": 10, + "wildcard_sequence": 30, + } + + mocker.patch("app.games.get_team_standings", side_effect=fake_standings) + + # Bruins game starts later but will have higher importance + high_hype_late = make_game( + game_state="FUT", + home_name="Bruins", + away_name="Maple Leafs", + start_time_utc="2024-04-10T23:00:00Z", + ) + low_hype_early = make_game( + game_state="FUT", + home_name="Kings", + away_name="Ducks", + start_time_utc="2024-04-10T19:00:00Z", + ) + + result = parse_games({"games": [high_hype_late, low_hype_early]}) + pre_games = [g for g in result if g["Game State"] == "PRE"] + # Lower-hype-but-earlier game must still appear first + assert pre_games[0]["Home Team"] == "Kings" + assert pre_games[1]["Home Team"] == "Bruins" + assert pre_games[1]["Priority"] > pre_games[0]["Priority"] + class TestGetPowerPlayInfo: def test_returns_empty_when_no_situation(self):