hockey-blast-common-lib 0.1.62__py3-none-any.whl → 0.1.64__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. hockey_blast_common_lib/aggregate_all_stats.py +7 -4
  2. hockey_blast_common_lib/aggregate_goalie_stats.py +303 -113
  3. hockey_blast_common_lib/aggregate_h2h_stats.py +64 -33
  4. hockey_blast_common_lib/aggregate_human_stats.py +566 -281
  5. hockey_blast_common_lib/aggregate_referee_stats.py +287 -145
  6. hockey_blast_common_lib/aggregate_s2s_stats.py +85 -25
  7. hockey_blast_common_lib/aggregate_scorekeeper_stats.py +231 -119
  8. hockey_blast_common_lib/aggregate_skater_stats.py +595 -240
  9. hockey_blast_common_lib/assign_skater_skill.py +21 -11
  10. hockey_blast_common_lib/db_connection.py +59 -8
  11. hockey_blast_common_lib/embedding_utils.py +309 -0
  12. hockey_blast_common_lib/h2h_models.py +150 -56
  13. hockey_blast_common_lib/hockey_blast_sample_backup.sql.gz +0 -0
  14. hockey_blast_common_lib/models.py +305 -149
  15. hockey_blast_common_lib/options.py +30 -15
  16. hockey_blast_common_lib/progress_utils.py +21 -13
  17. hockey_blast_common_lib/skills_in_divisions.py +170 -33
  18. hockey_blast_common_lib/skills_propagation.py +164 -70
  19. hockey_blast_common_lib/stats_models.py +489 -245
  20. hockey_blast_common_lib/stats_utils.py +6 -3
  21. hockey_blast_common_lib/utils.py +89 -25
  22. hockey_blast_common_lib/wsgi.py +7 -5
  23. {hockey_blast_common_lib-0.1.62.dist-info → hockey_blast_common_lib-0.1.64.dist-info}/METADATA +1 -1
  24. hockey_blast_common_lib-0.1.64.dist-info/RECORD +29 -0
  25. hockey_blast_common_lib-0.1.62.dist-info/RECORD +0 -28
  26. {hockey_blast_common_lib-0.1.62.dist-info → hockey_blast_common_lib-0.1.64.dist-info}/WHEEL +0 -0
  27. {hockey_blast_common_lib-0.1.62.dist-info → hockey_blast_common_lib-0.1.64.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,16 @@
1
- import sys, os
1
+ import os
2
+ import sys
2
3
 
3
4
  # Add the package directory to the Python path
4
5
  sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
5
6
 
6
- from hockey_blast_common_lib.aggregate_human_stats import run_aggregate_human_stats
7
- from hockey_blast_common_lib.aggregate_skater_stats import run_aggregate_skater_stats
8
7
  from hockey_blast_common_lib.aggregate_goalie_stats import run_aggregate_goalie_stats
8
+ from hockey_blast_common_lib.aggregate_human_stats import run_aggregate_human_stats
9
9
  from hockey_blast_common_lib.aggregate_referee_stats import run_aggregate_referee_stats
10
- from hockey_blast_common_lib.aggregate_scorekeeper_stats import run_aggregate_scorekeeper_stats
10
+ from hockey_blast_common_lib.aggregate_scorekeeper_stats import (
11
+ run_aggregate_scorekeeper_stats,
12
+ )
13
+ from hockey_blast_common_lib.aggregate_skater_stats import run_aggregate_skater_stats
11
14
 
12
15
  if __name__ == "__main__":
13
16
  print("Running aggregate_skater_stats...", flush=True)
@@ -1,20 +1,44 @@
1
- import sys, os
1
+ import os
2
+ import sys
2
3
 
3
4
  # Add the package directory to the Python path
4
5
  sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
5
6
 
6
7
  from datetime import datetime, timedelta
8
+
7
9
  import sqlalchemy
10
+ from sqlalchemy.sql import func
8
11
 
9
- from hockey_blast_common_lib.models import Game, Organization, Division, Human, GoalieSaves
10
- from hockey_blast_common_lib.stats_models import OrgStatsGoalie, DivisionStatsGoalie, OrgStatsWeeklyGoalie, OrgStatsDailyGoalie, DivisionStatsWeeklyGoalie, DivisionStatsDailyGoalie, LevelStatsGoalie
11
12
  from hockey_blast_common_lib.db_connection import create_session
12
- from sqlalchemy.sql import func, case
13
- from hockey_blast_common_lib.options import MIN_GAMES_FOR_ORG_STATS, MIN_GAMES_FOR_DIVISION_STATS, MIN_GAMES_FOR_LEVEL_STATS
14
- from hockey_blast_common_lib.utils import get_non_human_ids, get_all_division_ids_for_org, get_start_datetime
15
- from hockey_blast_common_lib.utils import assign_ranks
16
- from hockey_blast_common_lib.stats_utils import ALL_ORGS_ID
13
+ from hockey_blast_common_lib.models import (
14
+ Division,
15
+ Game,
16
+ GoalieSaves,
17
+ Human,
18
+ Organization,
19
+ )
20
+ from hockey_blast_common_lib.options import (
21
+ MIN_GAMES_FOR_DIVISION_STATS,
22
+ MIN_GAMES_FOR_LEVEL_STATS,
23
+ MIN_GAMES_FOR_ORG_STATS,
24
+ )
17
25
  from hockey_blast_common_lib.progress_utils import create_progress_tracker
26
+ from hockey_blast_common_lib.stats_models import (
27
+ DivisionStatsDailyGoalie,
28
+ DivisionStatsGoalie,
29
+ DivisionStatsWeeklyGoalie,
30
+ LevelStatsGoalie,
31
+ OrgStatsDailyGoalie,
32
+ OrgStatsGoalie,
33
+ OrgStatsWeeklyGoalie,
34
+ )
35
+ from hockey_blast_common_lib.stats_utils import ALL_ORGS_ID
36
+ from hockey_blast_common_lib.utils import (
37
+ assign_ranks,
38
+ get_all_division_ids_for_org,
39
+ get_non_human_ids,
40
+ get_start_datetime,
41
+ )
18
42
 
19
43
  # Import status constants for game filtering
20
44
  FINAL_STATUS = "Final"
@@ -22,79 +46,113 @@ FINAL_SO_STATUS = "Final(SO)"
22
46
  FORFEIT_STATUS = "FORFEIT"
23
47
  NOEVENTS_STATUS = "NOEVENTS"
24
48
 
25
- def aggregate_goalie_stats(session, aggregation_type, aggregation_id, debug_human_id=None, aggregation_window=None):
49
+
50
+ def aggregate_goalie_stats(
51
+ session,
52
+ aggregation_type,
53
+ aggregation_id,
54
+ debug_human_id=None,
55
+ aggregation_window=None,
56
+ ):
26
57
  human_ids_to_filter = get_non_human_ids(session)
27
58
 
28
59
  # Get the name of the aggregation, for debug purposes
29
- if aggregation_type == 'org':
60
+ if aggregation_type == "org":
30
61
  if aggregation_id == ALL_ORGS_ID:
31
62
  aggregation_name = "All Orgs"
32
63
  filter_condition = sqlalchemy.true() # No filter for organization
33
64
  else:
34
- aggregation_name = session.query(Organization).filter(Organization.id == aggregation_id).first().organization_name
65
+ aggregation_name = (
66
+ session.query(Organization)
67
+ .filter(Organization.id == aggregation_id)
68
+ .first()
69
+ .organization_name
70
+ )
35
71
  filter_condition = Game.org_id == aggregation_id
36
- print(f"Aggregating goalie stats for {aggregation_name} with window {aggregation_window}...")
37
- if aggregation_window == 'Daily':
72
+ print(
73
+ f"Aggregating goalie stats for {aggregation_name} with window {aggregation_window}..."
74
+ )
75
+ if aggregation_window == "Daily":
38
76
  StatsModel = OrgStatsDailyGoalie
39
- elif aggregation_window == 'Weekly':
77
+ elif aggregation_window == "Weekly":
40
78
  StatsModel = OrgStatsWeeklyGoalie
41
79
  else:
42
80
  StatsModel = OrgStatsGoalie
43
81
  min_games = MIN_GAMES_FOR_ORG_STATS
44
- elif aggregation_type == 'division':
45
- if aggregation_window == 'Daily':
82
+ elif aggregation_type == "division":
83
+ if aggregation_window == "Daily":
46
84
  StatsModel = DivisionStatsDailyGoalie
47
- elif aggregation_window == 'Weekly':
85
+ elif aggregation_window == "Weekly":
48
86
  StatsModel = DivisionStatsWeeklyGoalie
49
87
  else:
50
88
  StatsModel = DivisionStatsGoalie
51
89
  min_games = MIN_GAMES_FOR_DIVISION_STATS
52
90
  filter_condition = Game.division_id == aggregation_id
53
- elif aggregation_type == 'level':
91
+ elif aggregation_type == "level":
54
92
  StatsModel = LevelStatsGoalie
55
93
  min_games = MIN_GAMES_FOR_LEVEL_STATS
56
94
  filter_condition = Division.level_id == aggregation_id
57
95
  # Add filter to only include games for the last 5 years
58
- five_years_ago = datetime.now() - timedelta(days=5*365)
59
- level_window_filter = func.cast(func.concat(Game.date, ' ', Game.time), sqlalchemy.types.TIMESTAMP) >= five_years_ago
96
+ five_years_ago = datetime.now() - timedelta(days=5 * 365)
97
+ level_window_filter = (
98
+ func.cast(
99
+ func.concat(Game.date, " ", Game.time), sqlalchemy.types.TIMESTAMP
100
+ )
101
+ >= five_years_ago
102
+ )
60
103
  filter_condition = filter_condition & level_window_filter
61
104
  else:
62
105
  raise ValueError("Invalid aggregation type")
63
106
 
64
107
  # Delete existing items from the stats table
65
- session.query(StatsModel).filter(StatsModel.aggregation_id == aggregation_id).delete()
108
+ session.query(StatsModel).filter(
109
+ StatsModel.aggregation_id == aggregation_id
110
+ ).delete()
66
111
  session.commit()
67
112
 
68
113
  # Apply aggregation window filter
69
114
  if aggregation_window:
70
- last_game_datetime_str = session.query(func.max(func.concat(Game.date, ' ', Game.time))).filter(filter_condition, Game.status.like('Final%')).scalar()
115
+ last_game_datetime_str = (
116
+ session.query(func.max(func.concat(Game.date, " ", Game.time)))
117
+ .filter(filter_condition, Game.status.like("Final%"))
118
+ .scalar()
119
+ )
71
120
  start_datetime = get_start_datetime(last_game_datetime_str, aggregation_window)
72
121
  if start_datetime:
73
- game_window_filter = func.cast(func.concat(Game.date, ' ', Game.time), sqlalchemy.types.TIMESTAMP).between(start_datetime, last_game_datetime_str)
122
+ game_window_filter = func.cast(
123
+ func.concat(Game.date, " ", Game.time), sqlalchemy.types.TIMESTAMP
124
+ ).between(start_datetime, last_game_datetime_str)
74
125
  filter_condition = filter_condition & game_window_filter
75
126
  else:
76
- #print(f"Warning: No valid start datetime for aggregation window '{aggregation_window}' for {aggregation_name}. No games will be included.")
127
+ # print(f"Warning: No valid start datetime for aggregation window '{aggregation_window}' for {aggregation_name}. No games will be included.")
77
128
  return
78
129
 
79
-
80
130
  # Aggregate games played, goals allowed, and shots faced for each goalie using GoalieSaves table
81
- # games_participated: Count FINAL, FINAL_SO, FORFEIT, NOEVENTS
82
- # games_with_stats: Count only FINAL, FINAL_SO (for per-game averages)
83
- query = session.query(
84
- GoalieSaves.goalie_id.label('human_id'),
85
- func.count(GoalieSaves.game_id).label('games_played'), # DEPRECATED - will be replaced by games_participated
86
- func.sum(case(
87
- (Game.status.in_([FINAL_STATUS, FINAL_SO_STATUS, FORFEIT_STATUS, NOEVENTS_STATUS]), 1),
88
- else_=0
89
- )).label('games_participated'),
90
- func.sum(case(
91
- (Game.status.in_([FINAL_STATUS, FINAL_SO_STATUS]), 1),
92
- else_=0
93
- )).label('games_with_stats'),
94
- func.sum(GoalieSaves.goals_allowed).label('goals_allowed'),
95
- func.sum(GoalieSaves.shots_against).label('shots_faced'),
96
- func.array_agg(GoalieSaves.game_id).label('game_ids')
97
- ).join(Game, GoalieSaves.game_id == Game.id).join(Division, Game.division_id == Division.id).filter(filter_condition)
131
+ # Filter games by status upfront for performance (avoid CASE statements)
132
+ # Only count games with these statuses: FINAL, FINAL_SO, FORFEIT, NOEVENTS
133
+ query = (
134
+ session.query(
135
+ GoalieSaves.goalie_id.label("human_id"),
136
+ func.count(GoalieSaves.game_id).label("games_played"),
137
+ func.count(GoalieSaves.game_id).label(
138
+ "games_participated"
139
+ ), # Same as games_played after filtering
140
+ func.count(GoalieSaves.game_id).label(
141
+ "games_with_stats"
142
+ ), # Same as games_played after filtering
143
+ func.sum(GoalieSaves.goals_allowed).label("goals_allowed"),
144
+ func.sum(GoalieSaves.shots_against).label("shots_faced"),
145
+ func.array_agg(GoalieSaves.game_id).label("game_ids"),
146
+ )
147
+ .join(Game, GoalieSaves.game_id == Game.id)
148
+ .filter(
149
+ Game.status.in_(
150
+ [FINAL_STATUS, FINAL_SO_STATUS, FORFEIT_STATUS, NOEVENTS_STATUS]
151
+ )
152
+ )
153
+ .join(Division, Game.division_id == Division.id)
154
+ .filter(filter_condition)
155
+ )
98
156
 
99
157
  # Filter for specific human_id if provided
100
158
  if debug_human_id:
@@ -110,63 +168,89 @@ def aggregate_goalie_stats(session, aggregation_type, aggregation_id, debug_huma
110
168
  key = (aggregation_id, stat.human_id)
111
169
  if key not in stats_dict:
112
170
  stats_dict[key] = {
113
- 'games_played': 0, # DEPRECATED - for backward compatibility
114
- 'games_participated': 0, # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
115
- 'games_with_stats': 0, # Games with full stats: FINAL, FINAL_SO only
116
- 'goals_allowed': 0,
117
- 'shots_faced': 0,
118
- 'goals_allowed_per_game': 0.0,
119
- 'save_percentage': 0.0,
120
- 'game_ids': [],
121
- 'first_game_id': None,
122
- 'last_game_id': None
171
+ "games_played": 0, # DEPRECATED - for backward compatibility
172
+ "games_participated": 0, # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
173
+ "games_with_stats": 0, # Games with full stats: FINAL, FINAL_SO only
174
+ "goals_allowed": 0,
175
+ "shots_faced": 0,
176
+ "goals_allowed_per_game": 0.0,
177
+ "save_percentage": 0.0,
178
+ "game_ids": [],
179
+ "first_game_id": None,
180
+ "last_game_id": None,
123
181
  }
124
- stats_dict[key]['games_played'] += stat.games_played
125
- stats_dict[key]['games_participated'] += stat.games_participated
126
- stats_dict[key]['games_with_stats'] += stat.games_with_stats
127
- stats_dict[key]['goals_allowed'] += stat.goals_allowed if stat.goals_allowed is not None else 0
128
- stats_dict[key]['shots_faced'] += stat.shots_faced if stat.shots_faced is not None else 0
129
- stats_dict[key]['game_ids'].extend(stat.game_ids)
182
+ stats_dict[key]["games_played"] += stat.games_played
183
+ stats_dict[key]["games_participated"] += stat.games_participated
184
+ stats_dict[key]["games_with_stats"] += stat.games_with_stats
185
+ stats_dict[key]["goals_allowed"] += (
186
+ stat.goals_allowed if stat.goals_allowed is not None else 0
187
+ )
188
+ stats_dict[key]["shots_faced"] += (
189
+ stat.shots_faced if stat.shots_faced is not None else 0
190
+ )
191
+ stats_dict[key]["game_ids"].extend(stat.game_ids)
130
192
 
131
193
  # Filter out entries with games_played less than min_games
132
- stats_dict = {key: value for key, value in stats_dict.items() if value['games_played'] >= min_games}
194
+ stats_dict = {
195
+ key: value
196
+ for key, value in stats_dict.items()
197
+ if value["games_played"] >= min_games
198
+ }
133
199
 
134
200
  # Calculate per game stats (using games_with_stats as denominator for accuracy)
135
201
  for key, stat in stats_dict.items():
136
- if stat['games_with_stats'] > 0:
137
- stat['goals_allowed_per_game'] = stat['goals_allowed'] / stat['games_with_stats']
138
- stat['save_percentage'] = (stat['shots_faced'] - stat['goals_allowed']) / stat['shots_faced'] if stat['shots_faced'] > 0 else 0.0
202
+ if stat["games_with_stats"] > 0:
203
+ stat["goals_allowed_per_game"] = (
204
+ stat["goals_allowed"] / stat["games_with_stats"]
205
+ )
206
+ stat["save_percentage"] = (
207
+ (stat["shots_faced"] - stat["goals_allowed"]) / stat["shots_faced"]
208
+ if stat["shots_faced"] > 0
209
+ else 0.0
210
+ )
139
211
 
140
212
  # Ensure all keys have valid human_id values
141
213
  stats_dict = {key: value for key, value in stats_dict.items() if key[1] is not None}
142
214
 
143
215
  # Populate first_game_id and last_game_id
144
216
  for key, stat in stats_dict.items():
145
- all_game_ids = stat['game_ids']
217
+ all_game_ids = stat["game_ids"]
146
218
  if all_game_ids:
147
- first_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date, Game.time).first()
148
- last_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date.desc(), Game.time.desc()).first()
149
- stat['first_game_id'] = first_game.id if first_game else None
150
- stat['last_game_id'] = last_game.id if last_game else None
219
+ first_game = (
220
+ session.query(Game)
221
+ .filter(Game.id.in_(all_game_ids))
222
+ .order_by(Game.date, Game.time)
223
+ .first()
224
+ )
225
+ last_game = (
226
+ session.query(Game)
227
+ .filter(Game.id.in_(all_game_ids))
228
+ .order_by(Game.date.desc(), Game.time.desc())
229
+ .first()
230
+ )
231
+ stat["first_game_id"] = first_game.id if first_game else None
232
+ stat["last_game_id"] = last_game.id if last_game else None
151
233
 
152
234
  # Calculate total_in_rank
153
235
  total_in_rank = len(stats_dict)
154
236
 
155
237
  # Assign ranks within each level
156
- assign_ranks(stats_dict, 'games_played')
157
- assign_ranks(stats_dict, 'games_participated') # Rank by total participation
158
- assign_ranks(stats_dict, 'games_with_stats') # Rank by games with full stats
159
- assign_ranks(stats_dict, 'goals_allowed', reverse_rank=True)
160
- assign_ranks(stats_dict, 'shots_faced')
161
- assign_ranks(stats_dict, 'goals_allowed_per_game', reverse_rank=True)
162
- assign_ranks(stats_dict, 'save_percentage')
238
+ assign_ranks(stats_dict, "games_played")
239
+ assign_ranks(stats_dict, "games_participated") # Rank by total participation
240
+ assign_ranks(stats_dict, "games_with_stats") # Rank by games with full stats
241
+ assign_ranks(stats_dict, "goals_allowed", reverse_rank=True)
242
+ assign_ranks(stats_dict, "shots_faced")
243
+ assign_ranks(stats_dict, "goals_allowed_per_game", reverse_rank=True)
244
+ assign_ranks(stats_dict, "save_percentage")
163
245
 
164
246
  # Debug output for specific human
165
247
  if debug_human_id:
166
248
  if any(key[1] == debug_human_id for key in stats_dict):
167
249
  human = session.query(Human).filter(Human.id == debug_human_id).first()
168
250
  human_name = f"{human.first_name} {human.last_name}" if human else "Unknown"
169
- print(f"For Human {debug_human_id} ({human_name}) for {aggregation_type} {aggregation_id} ({aggregation_name}) , total_in_rank {total_in_rank} and window {aggregation_window}:")
251
+ print(
252
+ f"For Human {debug_human_id} ({human_name}) for {aggregation_type} {aggregation_id} ({aggregation_name}) , total_in_rank {total_in_rank} and window {aggregation_window}:"
253
+ )
170
254
  for key, stat in stats_dict.items():
171
255
  if key[1] == debug_human_id:
172
256
  for k, v in stat.items():
@@ -176,28 +260,42 @@ def aggregate_goalie_stats(session, aggregation_type, aggregation_id, debug_huma
176
260
  batch_size = 1000
177
261
  for i, (key, stat) in enumerate(stats_dict.items(), 1):
178
262
  aggregation_id, human_id = key
179
- goals_allowed_per_game = stat['goals_allowed'] / stat['games_played'] if stat['games_played'] > 0 else 0.0
180
- save_percentage = (stat['shots_faced'] - stat['goals_allowed']) / stat['shots_faced'] if stat['shots_faced'] > 0 else 0.0
263
+ goals_allowed_per_game = (
264
+ stat["goals_allowed"] / stat["games_played"]
265
+ if stat["games_played"] > 0
266
+ else 0.0
267
+ )
268
+ save_percentage = (
269
+ (stat["shots_faced"] - stat["goals_allowed"]) / stat["shots_faced"]
270
+ if stat["shots_faced"] > 0
271
+ else 0.0
272
+ )
181
273
  goalie_stat = StatsModel(
182
274
  aggregation_id=aggregation_id,
183
275
  human_id=human_id,
184
- games_played=stat['games_played'], # DEPRECATED - for backward compatibility
185
- games_participated=stat['games_participated'], # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
186
- games_participated_rank=stat['games_participated_rank'],
187
- games_with_stats=stat['games_with_stats'], # Games with full stats: FINAL, FINAL_SO only
188
- games_with_stats_rank=stat['games_with_stats_rank'],
189
- goals_allowed=stat['goals_allowed'],
190
- shots_faced=stat['shots_faced'],
276
+ games_played=stat[
277
+ "games_played"
278
+ ], # DEPRECATED - for backward compatibility
279
+ games_participated=stat[
280
+ "games_participated"
281
+ ], # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
282
+ games_participated_rank=stat["games_participated_rank"],
283
+ games_with_stats=stat[
284
+ "games_with_stats"
285
+ ], # Games with full stats: FINAL, FINAL_SO only
286
+ games_with_stats_rank=stat["games_with_stats_rank"],
287
+ goals_allowed=stat["goals_allowed"],
288
+ shots_faced=stat["shots_faced"],
191
289
  goals_allowed_per_game=goals_allowed_per_game,
192
290
  save_percentage=save_percentage,
193
- games_played_rank=stat['games_played_rank'],
194
- goals_allowed_rank=stat['goals_allowed_rank'],
195
- shots_faced_rank=stat['shots_faced_rank'],
196
- goals_allowed_per_game_rank=stat['goals_allowed_per_game_rank'],
197
- save_percentage_rank=stat['save_percentage_rank'],
291
+ games_played_rank=stat["games_played_rank"],
292
+ goals_allowed_rank=stat["goals_allowed_rank"],
293
+ shots_faced_rank=stat["shots_faced_rank"],
294
+ goals_allowed_per_game_rank=stat["goals_allowed_per_game_rank"],
295
+ save_percentage_rank=stat["save_percentage_rank"],
198
296
  total_in_rank=total_in_rank,
199
- first_game_id=stat['first_game_id'],
200
- last_game_id=stat['last_game_id']
297
+ first_game_id=stat["first_game_id"],
298
+ last_game_id=stat["last_game_id"],
201
299
  )
202
300
  session.add(goalie_stat)
203
301
  # Commit in batches
@@ -205,6 +303,7 @@ def aggregate_goalie_stats(session, aggregation_type, aggregation_id, debug_huma
205
303
  session.commit()
206
304
  session.commit()
207
305
 
306
+
208
307
  def run_aggregate_goalie_stats():
209
308
  session = create_session("boss")
210
309
  human_id_to_debug = None
@@ -215,51 +314,142 @@ def run_aggregate_goalie_stats():
215
314
 
216
315
  for org_id in org_ids:
217
316
  division_ids = get_all_division_ids_for_org(session, org_id)
218
- org_name = session.query(Organization.organization_name).filter(Organization.id == org_id).scalar() or f"org_id {org_id}"
219
-
317
+ org_name = (
318
+ session.query(Organization.organization_name)
319
+ .filter(Organization.id == org_id)
320
+ .scalar()
321
+ or f"org_id {org_id}"
322
+ )
323
+
220
324
  if human_id_to_debug is None and division_ids:
221
325
  # Process divisions with progress tracking
222
- progress = create_progress_tracker(len(division_ids), f"Processing {len(division_ids)} divisions for {org_name}")
326
+ progress = create_progress_tracker(
327
+ len(division_ids),
328
+ f"Processing {len(division_ids)} divisions for {org_name}",
329
+ )
223
330
  for i, division_id in enumerate(division_ids):
224
- aggregate_goalie_stats(session, aggregation_type='division', aggregation_id=division_id, debug_human_id=human_id_to_debug)
225
- aggregate_goalie_stats(session, aggregation_type='division', aggregation_id=division_id, debug_human_id=human_id_to_debug, aggregation_window='Weekly')
226
- aggregate_goalie_stats(session, aggregation_type='division', aggregation_id=division_id, debug_human_id=human_id_to_debug, aggregation_window='Daily')
331
+ aggregate_goalie_stats(
332
+ session,
333
+ aggregation_type="division",
334
+ aggregation_id=division_id,
335
+ debug_human_id=human_id_to_debug,
336
+ )
337
+ aggregate_goalie_stats(
338
+ session,
339
+ aggregation_type="division",
340
+ aggregation_id=division_id,
341
+ debug_human_id=human_id_to_debug,
342
+ aggregation_window="Weekly",
343
+ )
344
+ aggregate_goalie_stats(
345
+ session,
346
+ aggregation_type="division",
347
+ aggregation_id=division_id,
348
+ debug_human_id=human_id_to_debug,
349
+ aggregation_window="Daily",
350
+ )
227
351
  progress.update(i + 1)
228
352
  else:
229
353
  # Debug mode or no divisions - process without progress tracking
230
354
  for division_id in division_ids:
231
- aggregate_goalie_stats(session, aggregation_type='division', aggregation_id=division_id, debug_human_id=human_id_to_debug)
232
- aggregate_goalie_stats(session, aggregation_type='division', aggregation_id=division_id, debug_human_id=human_id_to_debug, aggregation_window='Weekly')
233
- aggregate_goalie_stats(session, aggregation_type='division', aggregation_id=division_id, debug_human_id=human_id_to_debug, aggregation_window='Daily')
355
+ aggregate_goalie_stats(
356
+ session,
357
+ aggregation_type="division",
358
+ aggregation_id=division_id,
359
+ debug_human_id=human_id_to_debug,
360
+ )
361
+ aggregate_goalie_stats(
362
+ session,
363
+ aggregation_type="division",
364
+ aggregation_id=division_id,
365
+ debug_human_id=human_id_to_debug,
366
+ aggregation_window="Weekly",
367
+ )
368
+ aggregate_goalie_stats(
369
+ session,
370
+ aggregation_type="division",
371
+ aggregation_id=division_id,
372
+ debug_human_id=human_id_to_debug,
373
+ aggregation_window="Daily",
374
+ )
234
375
 
235
376
  # Process org-level stats with progress tracking
236
377
  if human_id_to_debug is None:
237
- org_progress = create_progress_tracker(3, f"Processing org-level stats for {org_name}")
238
- aggregate_goalie_stats(session, aggregation_type='org', aggregation_id=org_id, debug_human_id=human_id_to_debug)
378
+ org_progress = create_progress_tracker(
379
+ 3, f"Processing org-level stats for {org_name}"
380
+ )
381
+ aggregate_goalie_stats(
382
+ session,
383
+ aggregation_type="org",
384
+ aggregation_id=org_id,
385
+ debug_human_id=human_id_to_debug,
386
+ )
239
387
  org_progress.update(1)
240
- aggregate_goalie_stats(session, aggregation_type='org', aggregation_id=org_id, debug_human_id=human_id_to_debug, aggregation_window='Weekly')
388
+ aggregate_goalie_stats(
389
+ session,
390
+ aggregation_type="org",
391
+ aggregation_id=org_id,
392
+ debug_human_id=human_id_to_debug,
393
+ aggregation_window="Weekly",
394
+ )
241
395
  org_progress.update(2)
242
- aggregate_goalie_stats(session, aggregation_type='org', aggregation_id=org_id, debug_human_id=human_id_to_debug, aggregation_window='Daily')
396
+ aggregate_goalie_stats(
397
+ session,
398
+ aggregation_type="org",
399
+ aggregation_id=org_id,
400
+ debug_human_id=human_id_to_debug,
401
+ aggregation_window="Daily",
402
+ )
243
403
  org_progress.update(3)
244
404
  else:
245
- aggregate_goalie_stats(session, aggregation_type='org', aggregation_id=org_id, debug_human_id=human_id_to_debug)
246
- aggregate_goalie_stats(session, aggregation_type='org', aggregation_id=org_id, debug_human_id=human_id_to_debug, aggregation_window='Weekly')
247
- aggregate_goalie_stats(session, aggregation_type='org', aggregation_id=org_id, debug_human_id=human_id_to_debug, aggregation_window='Daily')
248
-
405
+ aggregate_goalie_stats(
406
+ session,
407
+ aggregation_type="org",
408
+ aggregation_id=org_id,
409
+ debug_human_id=human_id_to_debug,
410
+ )
411
+ aggregate_goalie_stats(
412
+ session,
413
+ aggregation_type="org",
414
+ aggregation_id=org_id,
415
+ debug_human_id=human_id_to_debug,
416
+ aggregation_window="Weekly",
417
+ )
418
+ aggregate_goalie_stats(
419
+ session,
420
+ aggregation_type="org",
421
+ aggregation_id=org_id,
422
+ debug_human_id=human_id_to_debug,
423
+ aggregation_window="Daily",
424
+ )
425
+
249
426
  # Aggregate by level
250
427
  level_ids = session.query(Division.level_id).distinct().all()
251
428
  level_ids = [level_id[0] for level_id in level_ids if level_id[0] is not None]
252
-
429
+
253
430
  if human_id_to_debug is None and level_ids:
254
431
  # Process levels with progress tracking
255
- level_progress = create_progress_tracker(len(level_ids), f"Processing {len(level_ids)} skill levels")
432
+ level_progress = create_progress_tracker(
433
+ len(level_ids), f"Processing {len(level_ids)} skill levels"
434
+ )
256
435
  for i, level_id in enumerate(level_ids):
257
- aggregate_goalie_stats(session, aggregation_type='level', aggregation_id=level_id, debug_human_id=human_id_to_debug)
436
+ aggregate_goalie_stats(
437
+ session,
438
+ aggregation_type="level",
439
+ aggregation_id=level_id,
440
+ debug_human_id=human_id_to_debug,
441
+ )
258
442
  level_progress.update(i + 1)
259
443
  else:
260
444
  # Debug mode or no levels - process without progress tracking
261
445
  for level_id in level_ids:
262
- aggregate_goalie_stats(session, aggregation_type='level', aggregation_id=level_id, debug_human_id=human_id_to_debug)
446
+ aggregate_goalie_stats(
447
+ session,
448
+ aggregation_type="level",
449
+ aggregation_id=level_id,
450
+ debug_human_id=human_id_to_debug,
451
+ )
452
+
263
453
 
264
454
  if __name__ == "__main__":
265
- run_aggregate_goalie_stats()
455
+ run_aggregate_goalie_stats()