hockey-blast-common-lib 0.1.63__py3-none-any.whl → 0.1.65__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 +301 -107
  3. hockey_blast_common_lib/aggregate_h2h_stats.py +64 -33
  4. hockey_blast_common_lib/aggregate_human_stats.py +565 -280
  5. hockey_blast_common_lib/aggregate_referee_stats.py +286 -135
  6. hockey_blast_common_lib/aggregate_s2s_stats.py +85 -25
  7. hockey_blast_common_lib/aggregate_scorekeeper_stats.py +228 -113
  8. hockey_blast_common_lib/aggregate_skater_stats.py +561 -238
  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 -150
  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 +91 -25
  22. hockey_blast_common_lib/wsgi.py +7 -5
  23. {hockey_blast_common_lib-0.1.63.dist-info → hockey_blast_common_lib-0.1.65.dist-info}/METADATA +1 -1
  24. hockey_blast_common_lib-0.1.65.dist-info/RECORD +29 -0
  25. hockey_blast_common_lib-0.1.63.dist-info/RECORD +0 -28
  26. {hockey_blast_common_lib-0.1.63.dist-info → hockey_blast_common_lib-0.1.65.dist-info}/WHEEL +0 -0
  27. {hockey_blast_common_lib-0.1.63.dist-info → hockey_blast_common_lib-0.1.65.dist-info}/top_level.txt +0 -0
@@ -1,22 +1,46 @@
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 datetime import datetime, timedelta
7
+
7
8
  import sqlalchemy
9
+ from sqlalchemy import and_, case, func
10
+ from sqlalchemy.sql import case, func
8
11
 
9
- from hockey_blast_common_lib.models import Game, Goal, Penalty, GameRoster, Organization, Division, Human, Level
10
- from hockey_blast_common_lib.stats_models import OrgStatsSkater, DivisionStatsSkater, OrgStatsWeeklySkater, OrgStatsDailySkater, DivisionStatsWeeklySkater, DivisionStatsDailySkater, LevelStatsSkater
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 parse_args, MIN_GAMES_FOR_ORG_STATS, MIN_GAMES_FOR_DIVISION_STATS, MIN_GAMES_FOR_LEVEL_STATS
14
- from hockey_blast_common_lib.utils import get_org_id_from_alias, get_non_human_ids, get_division_ids_for_last_season_in_all_leagues, get_all_division_ids_for_org
15
- from hockey_blast_common_lib.utils import get_start_datetime
16
- from sqlalchemy import func, case, and_
17
- from collections import defaultdict
18
- from hockey_blast_common_lib.stats_utils import ALL_ORGS_ID
13
+ from hockey_blast_common_lib.models import (
14
+ Division,
15
+ Game,
16
+ GameRoster,
17
+ Goal,
18
+ Human,
19
+ Level,
20
+ Organization,
21
+ Penalty,
22
+ )
23
+ from hockey_blast_common_lib.options import (
24
+ MIN_GAMES_FOR_DIVISION_STATS,
25
+ MIN_GAMES_FOR_LEVEL_STATS,
26
+ MIN_GAMES_FOR_ORG_STATS,
27
+ )
19
28
  from hockey_blast_common_lib.progress_utils import create_progress_tracker
29
+ from hockey_blast_common_lib.stats_models import (
30
+ DivisionStatsDailySkater,
31
+ DivisionStatsSkater,
32
+ DivisionStatsWeeklySkater,
33
+ LevelStatsSkater,
34
+ OrgStatsDailySkater,
35
+ OrgStatsSkater,
36
+ OrgStatsWeeklySkater,
37
+ )
38
+ from hockey_blast_common_lib.stats_utils import ALL_ORGS_ID
39
+ from hockey_blast_common_lib.utils import (
40
+ get_all_division_ids_for_org,
41
+ get_non_human_ids,
42
+ get_start_datetime,
43
+ )
20
44
 
21
45
  # Import status constants for game filtering
22
46
  FINAL_STATUS = "Final"
@@ -24,6 +48,7 @@ FINAL_SO_STATUS = "Final(SO)"
24
48
  FORFEIT_STATUS = "FORFEIT"
25
49
  NOEVENTS_STATUS = "NOEVENTS"
26
50
 
51
+
27
52
  def calculate_current_point_streak(session, human_id, filter_condition):
28
53
  """
29
54
  Calculate the current point streak for a player.
@@ -33,29 +58,37 @@ def calculate_current_point_streak(session, human_id, filter_condition):
33
58
  Optimized to use CASE statements for conditional aggregation in a single query.
34
59
  """
35
60
  # Get all games with their point totals in ONE query using CASE for conditional counting
36
- game_points = session.query(
37
- Game.id,
38
- Game.date,
39
- Game.time,
40
- func.sum(case((Goal.goal_scorer_id == human_id, 1), else_=0)).label('goals'),
41
- func.sum(case(
42
- ((Goal.assist_1_id == human_id) | (Goal.assist_2_id == human_id), 1),
43
- else_=0
44
- )).label('assists')
45
- ).join(
46
- GameRoster, Game.id == GameRoster.game_id
47
- ).outerjoin(
48
- Goal, Game.id == Goal.game_id
49
- ).filter(
50
- GameRoster.human_id == human_id,
51
- ~GameRoster.role.ilike('g'), # Exclude goalie games
52
- filter_condition,
53
- (Game.status.like('Final%')) | (Game.status == 'NOEVENTS') # Include Final and NOEVENTS games
54
- ).group_by(
55
- Game.id, Game.date, Game.time
56
- ).order_by(
57
- Game.date.desc(), Game.time.desc()
58
- ).all()
61
+ game_points = (
62
+ session.query(
63
+ Game.id,
64
+ Game.date,
65
+ Game.time,
66
+ func.sum(case((Goal.goal_scorer_id == human_id, 1), else_=0)).label(
67
+ "goals"
68
+ ),
69
+ func.sum(
70
+ case(
71
+ (
72
+ (Goal.assist_1_id == human_id) | (Goal.assist_2_id == human_id),
73
+ 1,
74
+ ),
75
+ else_=0,
76
+ )
77
+ ).label("assists"),
78
+ )
79
+ .join(GameRoster, Game.id == GameRoster.game_id)
80
+ .outerjoin(Goal, Game.id == Goal.game_id)
81
+ .filter(
82
+ GameRoster.human_id == human_id,
83
+ ~GameRoster.role.ilike("g"), # Exclude goalie games
84
+ filter_condition,
85
+ (Game.status.like("Final%"))
86
+ | (Game.status == "NOEVENTS"), # Include Final and NOEVENTS games
87
+ )
88
+ .group_by(Game.id, Game.date, Game.time)
89
+ .order_by(Game.date.desc(), Game.time.desc())
90
+ .all()
91
+ )
59
92
 
60
93
  if not game_points:
61
94
  return 0, 0.0
@@ -75,52 +108,74 @@ def calculate_current_point_streak(session, human_id, filter_condition):
75
108
  break
76
109
 
77
110
  # Calculate average points during streak
78
- avg_points_during_streak = total_points_in_streak / current_streak if current_streak > 0 else 0.0
111
+ avg_points_during_streak = (
112
+ total_points_in_streak / current_streak if current_streak > 0 else 0.0
113
+ )
79
114
 
80
115
  return current_streak, avg_points_during_streak
81
116
 
82
- def aggregate_skater_stats(session, aggregation_type, aggregation_id, debug_human_id=None, aggregation_window=None):
117
+
118
+ def aggregate_skater_stats(
119
+ session,
120
+ aggregation_type,
121
+ aggregation_id,
122
+ debug_human_id=None,
123
+ aggregation_window=None,
124
+ ):
83
125
  human_ids_to_filter = get_non_human_ids(session)
84
126
 
85
127
  # Get the name of the aggregation, for debug purposes
86
- if aggregation_type == 'org':
128
+ if aggregation_type == "org":
87
129
  if aggregation_id == ALL_ORGS_ID:
88
130
  aggregation_name = "All Orgs"
89
131
  filter_condition = sqlalchemy.true() # No filter for organization
90
132
  else:
91
- aggregation_name = session.query(Organization).filter(Organization.id == aggregation_id).first().organization_name
133
+ aggregation_name = (
134
+ session.query(Organization)
135
+ .filter(Organization.id == aggregation_id)
136
+ .first()
137
+ .organization_name
138
+ )
92
139
  filter_condition = Game.org_id == aggregation_id
93
- print(f"Aggregating skater stats for {aggregation_name} with window {aggregation_window}...")
140
+ print(
141
+ f"Aggregating skater stats for {aggregation_name} with window {aggregation_window}..."
142
+ )
94
143
 
95
- elif aggregation_type == 'division':
96
- aggregation_name = session.query(Division).filter(Division.id == aggregation_id).first().level
97
- elif aggregation_type == 'level':
98
- aggregation_name = session.query(Level).filter(Level.id == aggregation_id).first().level_name
144
+ elif aggregation_type == "division":
145
+ aggregation_name = (
146
+ session.query(Division).filter(Division.id == aggregation_id).first().level
147
+ )
148
+ elif aggregation_type == "level":
149
+ aggregation_name = (
150
+ session.query(Level).filter(Level.id == aggregation_id).first().level_name
151
+ )
99
152
  else:
100
153
  aggregation_name = "Unknown"
101
154
 
102
- if aggregation_type == 'org':
103
- if aggregation_window == 'Daily':
155
+ if aggregation_type == "org":
156
+ if aggregation_window == "Daily":
104
157
  StatsModel = OrgStatsDailySkater
105
- elif aggregation_window == 'Weekly':
158
+ elif aggregation_window == "Weekly":
106
159
  StatsModel = OrgStatsWeeklySkater
107
160
  else:
108
161
  StatsModel = OrgStatsSkater
109
162
  min_games = MIN_GAMES_FOR_ORG_STATS
110
- elif aggregation_type == 'division':
111
- if aggregation_window == 'Daily':
163
+ elif aggregation_type == "division":
164
+ if aggregation_window == "Daily":
112
165
  StatsModel = DivisionStatsDailySkater
113
- elif aggregation_window == 'Weekly':
166
+ elif aggregation_window == "Weekly":
114
167
  StatsModel = DivisionStatsWeeklySkater
115
168
  else:
116
169
  StatsModel = DivisionStatsSkater
117
170
  min_games = MIN_GAMES_FOR_DIVISION_STATS
118
171
  filter_condition = Game.division_id == aggregation_id
119
- elif aggregation_type == 'level':
172
+ elif aggregation_type == "level":
120
173
  StatsModel = LevelStatsSkater
121
174
  min_games = MIN_GAMES_FOR_LEVEL_STATS
122
175
  # Get division IDs for this level to avoid cartesian product
123
- division_ids = session.query(Division.id).filter(Division.level_id == aggregation_id).all()
176
+ division_ids = (
177
+ session.query(Division.id).filter(Division.level_id == aggregation_id).all()
178
+ )
124
179
  division_ids = [div_id[0] for div_id in division_ids]
125
180
  if not division_ids:
126
181
  return # No divisions for this level
@@ -133,20 +188,31 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, debug_huma
133
188
  raise ValueError("Invalid aggregation type")
134
189
 
135
190
  # Delete existing items from the stats table
136
- session.query(StatsModel).filter(StatsModel.aggregation_id == aggregation_id).delete()
191
+ session.query(StatsModel).filter(
192
+ StatsModel.aggregation_id == aggregation_id
193
+ ).delete()
137
194
  session.commit()
138
195
 
139
196
  # Apply aggregation window filter
140
197
  if aggregation_window:
141
- last_game_datetime_str = session.query(func.max(func.concat(Game.date, ' ', Game.time))).filter(filter_condition, (Game.status.like('Final%')) | (Game.status == 'NOEVENTS')).scalar()
198
+ last_game_datetime_str = (
199
+ session.query(func.max(func.concat(Game.date, " ", Game.time)))
200
+ .filter(
201
+ filter_condition,
202
+ (Game.status.like("Final%")) | (Game.status == "NOEVENTS"),
203
+ )
204
+ .scalar()
205
+ )
142
206
  start_datetime = get_start_datetime(last_game_datetime_str, aggregation_window)
143
207
  if start_datetime:
144
- game_window_filter = func.cast(func.concat(Game.date, ' ', Game.time), sqlalchemy.types.TIMESTAMP).between(start_datetime, last_game_datetime_str)
208
+ game_window_filter = func.cast(
209
+ func.concat(Game.date, " ", Game.time), sqlalchemy.types.TIMESTAMP
210
+ ).between(start_datetime, last_game_datetime_str)
145
211
  filter_condition = filter_condition & game_window_filter
146
212
  else:
147
- #print(f"Warning: No valid start datetime for aggregation window '{aggregation_window}' for {aggregation_name}. No games will be included.")
213
+ # print(f"Warning: No valid start datetime for aggregation window '{aggregation_window}' for {aggregation_name}. No games will be included.")
148
214
  return
149
-
215
+
150
216
  # Filter for specific human_id if provided
151
217
  human_filter = []
152
218
  # if debug_human_id:
@@ -155,69 +221,153 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, debug_huma
155
221
  # Aggregate games played for each human in each division, excluding goalies
156
222
  # Filter games by status upfront for performance (avoid CASE statements on 200K+ rows)
157
223
  # Only count games with these statuses: FINAL, FINAL_SO, FORFEIT, NOEVENTS
158
- games_played_query = session.query(
159
- GameRoster.human_id,
160
- func.count(Game.id).label('games_played'),
161
- func.count(Game.id).label('games_participated'), # Same as games_played after filtering
162
- func.count(Game.id).label('games_with_stats'), # Same as games_played after filtering
163
- func.array_agg(Game.id).label('game_ids')
164
- ).join(Game, Game.id == GameRoster.game_id).filter(
165
- Game.status.in_([FINAL_STATUS, FINAL_SO_STATUS, FORFEIT_STATUS, NOEVENTS_STATUS])
224
+ games_played_query = (
225
+ session.query(
226
+ GameRoster.human_id,
227
+ func.count(Game.id).label("games_played"),
228
+ func.count(Game.id).label(
229
+ "games_participated"
230
+ ), # Same as games_played after filtering
231
+ func.count(Game.id).label(
232
+ "games_with_stats"
233
+ ), # Same as games_played after filtering
234
+ func.array_agg(Game.id).label("game_ids"),
235
+ )
236
+ .join(Game, Game.id == GameRoster.game_id)
237
+ .filter(
238
+ Game.status.in_(
239
+ [FINAL_STATUS, FINAL_SO_STATUS, FORFEIT_STATUS, NOEVENTS_STATUS]
240
+ )
241
+ )
166
242
  )
167
243
 
168
244
  # Only join Division if not level aggregation (since we filter on Game.division_id directly for levels)
169
- if aggregation_type != 'level':
170
- games_played_query = games_played_query.join(Division, Game.division_id == Division.id)
245
+ if aggregation_type != "level":
246
+ games_played_query = games_played_query.join(
247
+ Division, Game.division_id == Division.id
248
+ )
171
249
 
172
- games_played_stats = games_played_query.filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(GameRoster.human_id).all()
250
+ games_played_stats = (
251
+ games_played_query.filter(
252
+ filter_condition, ~GameRoster.role.ilike("g"), *human_filter
253
+ )
254
+ .group_by(GameRoster.human_id)
255
+ .all()
256
+ )
173
257
 
174
258
  # Aggregate goals for each human in each division, excluding goalies
175
- goals_query = session.query(
176
- Goal.goal_scorer_id.label('human_id'),
177
- func.count(Goal.id).label('goals'),
178
- func.array_agg(Goal.game_id).label('goal_game_ids')
179
- ).join(Game, Game.id == Goal.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Goal.goal_scorer_id == GameRoster.human_id))
180
-
181
- if aggregation_type != 'level':
259
+ goals_query = (
260
+ session.query(
261
+ Goal.goal_scorer_id.label("human_id"),
262
+ func.count(Goal.id).label("goals"),
263
+ func.array_agg(Goal.game_id).label("goal_game_ids"),
264
+ )
265
+ .join(Game, Game.id == Goal.game_id)
266
+ .join(
267
+ GameRoster,
268
+ and_(
269
+ Game.id == GameRoster.game_id,
270
+ Goal.goal_scorer_id == GameRoster.human_id,
271
+ ),
272
+ )
273
+ )
274
+
275
+ if aggregation_type != "level":
182
276
  goals_query = goals_query.join(Division, Game.division_id == Division.id)
183
-
184
- goals_stats = goals_query.filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Goal.goal_scorer_id).all()
277
+
278
+ goals_stats = (
279
+ goals_query.filter(filter_condition, ~GameRoster.role.ilike("g"), *human_filter)
280
+ .group_by(Goal.goal_scorer_id)
281
+ .all()
282
+ )
185
283
 
186
284
  # Aggregate assists for each human in each division, excluding goalies
187
- assists_query = session.query(
188
- Goal.assist_1_id.label('human_id'),
189
- func.count(Goal.id).label('assists'),
190
- func.array_agg(Goal.game_id).label('assist_game_ids')
191
- ).join(Game, Game.id == Goal.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Goal.assist_1_id == GameRoster.human_id))
192
-
193
- if aggregation_type != 'level':
285
+ assists_query = (
286
+ session.query(
287
+ Goal.assist_1_id.label("human_id"),
288
+ func.count(Goal.id).label("assists"),
289
+ func.array_agg(Goal.game_id).label("assist_game_ids"),
290
+ )
291
+ .join(Game, Game.id == Goal.game_id)
292
+ .join(
293
+ GameRoster,
294
+ and_(
295
+ Game.id == GameRoster.game_id, Goal.assist_1_id == GameRoster.human_id
296
+ ),
297
+ )
298
+ )
299
+
300
+ if aggregation_type != "level":
194
301
  assists_query = assists_query.join(Division, Game.division_id == Division.id)
195
-
196
- assists_stats = assists_query.filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Goal.assist_1_id).all()
197
-
198
- assists_query_2 = session.query(
199
- Goal.assist_2_id.label('human_id'),
200
- func.count(Goal.id).label('assists'),
201
- func.array_agg(Goal.game_id).label('assist_2_game_ids')
202
- ).join(Game, Game.id == Goal.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Goal.assist_2_id == GameRoster.human_id))
203
-
204
- if aggregation_type != 'level':
205
- assists_query_2 = assists_query_2.join(Division, Game.division_id == Division.id)
206
-
207
- assists_stats_2 = assists_query_2.filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Goal.assist_2_id).all()
302
+
303
+ assists_stats = (
304
+ assists_query.filter(
305
+ filter_condition, ~GameRoster.role.ilike("g"), *human_filter
306
+ )
307
+ .group_by(Goal.assist_1_id)
308
+ .all()
309
+ )
310
+
311
+ assists_query_2 = (
312
+ session.query(
313
+ Goal.assist_2_id.label("human_id"),
314
+ func.count(Goal.id).label("assists"),
315
+ func.array_agg(Goal.game_id).label("assist_2_game_ids"),
316
+ )
317
+ .join(Game, Game.id == Goal.game_id)
318
+ .join(
319
+ GameRoster,
320
+ and_(
321
+ Game.id == GameRoster.game_id, Goal.assist_2_id == GameRoster.human_id
322
+ ),
323
+ )
324
+ )
325
+
326
+ if aggregation_type != "level":
327
+ assists_query_2 = assists_query_2.join(
328
+ Division, Game.division_id == Division.id
329
+ )
330
+
331
+ assists_stats_2 = (
332
+ assists_query_2.filter(
333
+ filter_condition, ~GameRoster.role.ilike("g"), *human_filter
334
+ )
335
+ .group_by(Goal.assist_2_id)
336
+ .all()
337
+ )
208
338
 
209
339
  # Aggregate penalties for each human in each division, excluding goalies
210
- penalties_query = session.query(
211
- Penalty.penalized_player_id.label('human_id'),
212
- func.count(Penalty.id).label('penalties'),
213
- func.sum(case((Penalty.penalty_minutes == 'GM', 1), else_=0)).label('gm_penalties'), # New aggregation for GM penalties
214
- func.array_agg(Penalty.game_id).label('penalty_game_ids')
215
- ).join(Game, Game.id == Penalty.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Penalty.penalized_player_id == GameRoster.human_id))
216
-
217
- if aggregation_type != 'level':
218
- penalties_query = penalties_query.join(Division, Game.division_id == Division.id)
219
-
220
- penalties_stats = penalties_query.filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Penalty.penalized_player_id).all()
340
+ penalties_query = (
341
+ session.query(
342
+ Penalty.penalized_player_id.label("human_id"),
343
+ func.count(Penalty.id).label("penalties"),
344
+ func.sum(case((Penalty.penalty_minutes == "GM", 1), else_=0)).label(
345
+ "gm_penalties"
346
+ ), # New aggregation for GM penalties
347
+ func.array_agg(Penalty.game_id).label("penalty_game_ids"),
348
+ )
349
+ .join(Game, Game.id == Penalty.game_id)
350
+ .join(
351
+ GameRoster,
352
+ and_(
353
+ Game.id == GameRoster.game_id,
354
+ Penalty.penalized_player_id == GameRoster.human_id,
355
+ ),
356
+ )
357
+ )
358
+
359
+ if aggregation_type != "level":
360
+ penalties_query = penalties_query.join(
361
+ Division, Game.division_id == Division.id
362
+ )
363
+
364
+ penalties_stats = (
365
+ penalties_query.filter(
366
+ filter_condition, ~GameRoster.role.ilike("g"), *human_filter
367
+ )
368
+ .group_by(Penalty.penalized_player_id)
369
+ .all()
370
+ )
221
371
 
222
372
  # Combine the results
223
373
  stats_dict = {}
@@ -227,65 +377,71 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, debug_huma
227
377
  key = (aggregation_id, stat.human_id)
228
378
  if key not in stats_dict:
229
379
  stats_dict[key] = {
230
- 'games_played': 0, # DEPRECATED - for backward compatibility
231
- 'games_participated': 0, # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
232
- 'games_with_stats': 0, # Games with full stats: FINAL, FINAL_SO only
233
- 'goals': 0,
234
- 'assists': 0,
235
- 'penalties': 0,
236
- 'gm_penalties': 0, # Initialize GM penalties
237
- 'points': 0, # Initialize points
238
- 'goals_per_game': 0.0,
239
- 'points_per_game': 0.0,
240
- 'assists_per_game': 0.0,
241
- 'penalties_per_game': 0.0,
242
- 'gm_penalties_per_game': 0.0, # Initialize GM penalties per game
243
- 'current_point_streak': 0, # Initialize current point streak
244
- 'current_point_streak_avg_points': 0.0, # Initialize current point streak average points
245
- 'game_ids': [],
246
- 'first_game_id': None,
247
- 'last_game_id': None
380
+ "games_played": 0, # DEPRECATED - for backward compatibility
381
+ "games_participated": 0, # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
382
+ "games_with_stats": 0, # Games with full stats: FINAL, FINAL_SO only
383
+ "goals": 0,
384
+ "assists": 0,
385
+ "penalties": 0,
386
+ "gm_penalties": 0, # Initialize GM penalties
387
+ "points": 0, # Initialize points
388
+ "goals_per_game": 0.0,
389
+ "points_per_game": 0.0,
390
+ "assists_per_game": 0.0,
391
+ "penalties_per_game": 0.0,
392
+ "gm_penalties_per_game": 0.0, # Initialize GM penalties per game
393
+ "current_point_streak": 0, # Initialize current point streak
394
+ "current_point_streak_avg_points": 0.0, # Initialize current point streak average points
395
+ "game_ids": [],
396
+ "first_game_id": None,
397
+ "last_game_id": None,
248
398
  }
249
- stats_dict[key]['games_played'] += stat.games_played
250
- stats_dict[key]['games_participated'] += stat.games_participated
251
- stats_dict[key]['games_with_stats'] += stat.games_with_stats
252
- stats_dict[key]['game_ids'].extend(stat.game_ids)
399
+ stats_dict[key]["games_played"] += stat.games_played
400
+ stats_dict[key]["games_participated"] += stat.games_participated
401
+ stats_dict[key]["games_with_stats"] += stat.games_with_stats
402
+ stats_dict[key]["game_ids"].extend(stat.game_ids)
253
403
 
254
404
  # Filter out entries with games_played less than min_games
255
- stats_dict = {key: value for key, value in stats_dict.items() if value['games_played'] >= min_games}
405
+ stats_dict = {
406
+ key: value
407
+ for key, value in stats_dict.items()
408
+ if value["games_played"] >= min_games
409
+ }
256
410
 
257
411
  for stat in goals_stats:
258
412
  key = (aggregation_id, stat.human_id)
259
413
  if key in stats_dict:
260
- stats_dict[key]['goals'] += stat.goals
261
- stats_dict[key]['points'] += stat.goals # Update points
414
+ stats_dict[key]["goals"] += stat.goals
415
+ stats_dict[key]["points"] += stat.goals # Update points
262
416
 
263
417
  for stat in assists_stats:
264
418
  key = (aggregation_id, stat.human_id)
265
419
  if key in stats_dict:
266
- stats_dict[key]['assists'] += stat.assists
267
- stats_dict[key]['points'] += stat.assists # Update points
420
+ stats_dict[key]["assists"] += stat.assists
421
+ stats_dict[key]["points"] += stat.assists # Update points
268
422
 
269
423
  for stat in assists_stats_2:
270
424
  key = (aggregation_id, stat.human_id)
271
425
  if key in stats_dict:
272
- stats_dict[key]['assists'] += stat.assists
273
- stats_dict[key]['points'] += stat.assists # Update points
426
+ stats_dict[key]["assists"] += stat.assists
427
+ stats_dict[key]["points"] += stat.assists # Update points
274
428
 
275
429
  for stat in penalties_stats:
276
430
  key = (aggregation_id, stat.human_id)
277
431
  if key in stats_dict:
278
- stats_dict[key]['penalties'] += stat.penalties
279
- stats_dict[key]['gm_penalties'] += stat.gm_penalties # Update GM penalties
432
+ stats_dict[key]["penalties"] += stat.penalties
433
+ stats_dict[key]["gm_penalties"] += stat.gm_penalties # Update GM penalties
280
434
 
281
435
  # Calculate per game stats (using games_with_stats as denominator for accuracy)
282
436
  for key, stat in stats_dict.items():
283
- if stat['games_with_stats'] > 0:
284
- stat['goals_per_game'] = stat['goals'] / stat['games_with_stats']
285
- stat['points_per_game'] = stat['points'] / stat['games_with_stats']
286
- stat['assists_per_game'] = stat['assists'] / stat['games_with_stats']
287
- stat['penalties_per_game'] = stat['penalties'] / stat['games_with_stats']
288
- stat['gm_penalties_per_game'] = stat['gm_penalties'] / stat['games_with_stats'] # Calculate GM penalties per game
437
+ if stat["games_with_stats"] > 0:
438
+ stat["goals_per_game"] = stat["goals"] / stat["games_with_stats"]
439
+ stat["points_per_game"] = stat["points"] / stat["games_with_stats"]
440
+ stat["assists_per_game"] = stat["assists"] / stat["games_with_stats"]
441
+ stat["penalties_per_game"] = stat["penalties"] / stat["games_with_stats"]
442
+ stat["gm_penalties_per_game"] = (
443
+ stat["gm_penalties"] / stat["games_with_stats"]
444
+ ) # Calculate GM penalties per game
289
445
 
290
446
  # Ensure all keys have valid human_id values
291
447
  stats_dict = {key: value for key, value in stats_dict.items() if key[1] is not None}
@@ -293,79 +449,126 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, debug_huma
293
449
  # Populate first_game_id and last_game_id
294
450
  # Only show progress for "All Orgs" with no window (all-time stats) - the slowest case
295
451
  total_players = len(stats_dict)
296
- if aggregation_type == 'org' and aggregation_id == ALL_ORGS_ID and aggregation_window is None and total_players > 1000:
297
- progress = create_progress_tracker(total_players, f"Processing {total_players} players for {aggregation_name}")
452
+ if (
453
+ aggregation_type == "org"
454
+ and aggregation_id == ALL_ORGS_ID
455
+ and aggregation_window is None
456
+ and total_players > 1000
457
+ ):
458
+ progress = create_progress_tracker(
459
+ total_players, f"Processing {total_players} players for {aggregation_name}"
460
+ )
298
461
  for idx, (key, stat) in enumerate(stats_dict.items()):
299
- all_game_ids = stat['game_ids']
462
+ all_game_ids = stat["game_ids"]
300
463
  if all_game_ids:
301
- first_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date, Game.time).first()
302
- last_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date.desc(), Game.time.desc()).first()
303
- stat['first_game_id'] = first_game.id if first_game else None
304
- stat['last_game_id'] = last_game.id if last_game else None
305
- if (idx + 1) % 100 == 0 or (idx + 1) == total_players: # Update every 100 players
464
+ first_game = (
465
+ session.query(Game)
466
+ .filter(Game.id.in_(all_game_ids))
467
+ .order_by(Game.date, Game.time)
468
+ .first()
469
+ )
470
+ last_game = (
471
+ session.query(Game)
472
+ .filter(Game.id.in_(all_game_ids))
473
+ .order_by(Game.date.desc(), Game.time.desc())
474
+ .first()
475
+ )
476
+ stat["first_game_id"] = first_game.id if first_game else None
477
+ stat["last_game_id"] = last_game.id if last_game else None
478
+ if (idx + 1) % 100 == 0 or (
479
+ idx + 1
480
+ ) == total_players: # Update every 100 players
306
481
  progress.update(idx + 1)
307
482
  else:
308
483
  # No progress tracking for all other cases
309
484
  for key, stat in stats_dict.items():
310
- all_game_ids = stat['game_ids']
485
+ all_game_ids = stat["game_ids"]
311
486
  if all_game_ids:
312
- first_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date, Game.time).first()
313
- last_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date.desc(), Game.time.desc()).first()
314
- stat['first_game_id'] = first_game.id if first_game else None
315
- stat['last_game_id'] = last_game.id if last_game else None
487
+ first_game = (
488
+ session.query(Game)
489
+ .filter(Game.id.in_(all_game_ids))
490
+ .order_by(Game.date, Game.time)
491
+ .first()
492
+ )
493
+ last_game = (
494
+ session.query(Game)
495
+ .filter(Game.id.in_(all_game_ids))
496
+ .order_by(Game.date.desc(), Game.time.desc())
497
+ .first()
498
+ )
499
+ stat["first_game_id"] = first_game.id if first_game else None
500
+ stat["last_game_id"] = last_game.id if last_game else None
316
501
 
317
502
  # Calculate current point streak (only for all-time stats)
318
503
  if aggregation_window is None:
319
504
  total_players = len(stats_dict)
320
505
  # Show progress for All Orgs - this is the slowest part
321
- if aggregation_type == 'org' and aggregation_id == ALL_ORGS_ID and total_players > 1000:
322
- progress = create_progress_tracker(total_players, f"Calculating point streaks for {total_players} players")
506
+ if (
507
+ aggregation_type == "org"
508
+ and aggregation_id == ALL_ORGS_ID
509
+ and total_players > 1000
510
+ ):
511
+ progress = create_progress_tracker(
512
+ total_players, f"Calculating point streaks for {total_players} players"
513
+ )
323
514
  for idx, (key, stat) in enumerate(stats_dict.items()):
324
515
  agg_id, human_id = key
325
- streak_length, avg_points = calculate_current_point_streak(session, human_id, filter_condition)
326
- stat['current_point_streak'] = streak_length
327
- stat['current_point_streak_avg_points'] = avg_points
516
+ streak_length, avg_points = calculate_current_point_streak(
517
+ session, human_id, filter_condition
518
+ )
519
+ stat["current_point_streak"] = streak_length
520
+ stat["current_point_streak_avg_points"] = avg_points
328
521
  if (idx + 1) % 100 == 0 or (idx + 1) == total_players:
329
522
  progress.update(idx + 1)
330
523
  else:
331
524
  for key, stat in stats_dict.items():
332
525
  agg_id, human_id = key
333
- streak_length, avg_points = calculate_current_point_streak(session, human_id, filter_condition)
334
- stat['current_point_streak'] = streak_length
335
- stat['current_point_streak_avg_points'] = avg_points
526
+ streak_length, avg_points = calculate_current_point_streak(
527
+ session, human_id, filter_condition
528
+ )
529
+ stat["current_point_streak"] = streak_length
530
+ stat["current_point_streak_avg_points"] = avg_points
336
531
 
337
532
  # Calculate total_in_rank
338
533
  total_in_rank = len(stats_dict)
339
534
 
340
535
  # Assign ranks within each level
341
536
  def assign_ranks(stats_dict, field):
342
- sorted_stats = sorted(stats_dict.items(), key=lambda x: x[1][field], reverse=True)
537
+ sorted_stats = sorted(
538
+ stats_dict.items(), key=lambda x: x[1][field], reverse=True
539
+ )
343
540
  for rank, (key, stat) in enumerate(sorted_stats, start=1):
344
- stats_dict[key][f'{field}_rank'] = rank
345
-
346
- assign_ranks(stats_dict, 'games_played')
347
- assign_ranks(stats_dict, 'games_participated') # Rank by total participation
348
- assign_ranks(stats_dict, 'games_with_stats') # Rank by games with full stats
349
- assign_ranks(stats_dict, 'goals')
350
- assign_ranks(stats_dict, 'assists')
351
- assign_ranks(stats_dict, 'points')
352
- assign_ranks(stats_dict, 'penalties')
353
- assign_ranks(stats_dict, 'gm_penalties') # Assign ranks for GM penalties
354
- assign_ranks(stats_dict, 'goals_per_game')
355
- assign_ranks(stats_dict, 'points_per_game')
356
- assign_ranks(stats_dict, 'assists_per_game')
357
- assign_ranks(stats_dict, 'penalties_per_game')
358
- assign_ranks(stats_dict, 'gm_penalties_per_game') # Assign ranks for GM penalties per game
359
- if aggregation_window is None: # Only assign current_point_streak ranks for all-time stats
360
- assign_ranks(stats_dict, 'current_point_streak')
361
- assign_ranks(stats_dict, 'current_point_streak_avg_points')
541
+ stats_dict[key][f"{field}_rank"] = rank
542
+
543
+ assign_ranks(stats_dict, "games_played")
544
+ assign_ranks(stats_dict, "games_participated") # Rank by total participation
545
+ assign_ranks(stats_dict, "games_with_stats") # Rank by games with full stats
546
+ assign_ranks(stats_dict, "goals")
547
+ assign_ranks(stats_dict, "assists")
548
+ assign_ranks(stats_dict, "points")
549
+ assign_ranks(stats_dict, "penalties")
550
+ assign_ranks(stats_dict, "gm_penalties") # Assign ranks for GM penalties
551
+ assign_ranks(stats_dict, "goals_per_game")
552
+ assign_ranks(stats_dict, "points_per_game")
553
+ assign_ranks(stats_dict, "assists_per_game")
554
+ assign_ranks(stats_dict, "penalties_per_game")
555
+ assign_ranks(
556
+ stats_dict, "gm_penalties_per_game"
557
+ ) # Assign ranks for GM penalties per game
558
+ if (
559
+ aggregation_window is None
560
+ ): # Only assign current_point_streak ranks for all-time stats
561
+ assign_ranks(stats_dict, "current_point_streak")
562
+ assign_ranks(stats_dict, "current_point_streak_avg_points")
362
563
 
363
564
  # Debug output for specific human
364
565
  if debug_human_id:
365
566
  if any(key[1] == debug_human_id for key in stats_dict):
366
567
  human = session.query(Human).filter(Human.id == debug_human_id).first()
367
568
  human_name = f"{human.first_name} {human.last_name}" if human else "Unknown"
368
- 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}:")
569
+ print(
570
+ 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}:"
571
+ )
369
572
  for key, stat in stats_dict.items():
370
573
  if key[1] == debug_human_id:
371
574
  for k, v in stat.items():
@@ -376,47 +579,75 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, debug_huma
376
579
  batch_size = 1000
377
580
  for i, (key, stat) in enumerate(stats_dict.items(), 1):
378
581
  aggregation_id, human_id = key
379
- goals_per_game = stat['goals'] / stat['games_played'] if stat['games_played'] > 0 else 0.0
380
- points_per_game = (stat['goals'] + stat['assists']) / stat['games_played'] if stat['games_played'] > 0 else 0.0
381
- assists_per_game = stat['assists'] / stat['games_played'] if stat['games_played'] > 0 else 0.0
382
- penalties_per_game = stat['penalties'] / stat['games_played'] if stat['games_played'] > 0 else 0.0
383
- gm_penalties_per_game = stat['gm_penalties'] / stat['games_played'] if stat['games_played'] > 0 else 0.0 # Calculate GM penalties per game
582
+ goals_per_game = (
583
+ stat["goals"] / stat["games_played"] if stat["games_played"] > 0 else 0.0
584
+ )
585
+ points_per_game = (
586
+ (stat["goals"] + stat["assists"]) / stat["games_played"]
587
+ if stat["games_played"] > 0
588
+ else 0.0
589
+ )
590
+ assists_per_game = (
591
+ stat["assists"] / stat["games_played"] if stat["games_played"] > 0 else 0.0
592
+ )
593
+ penalties_per_game = (
594
+ stat["penalties"] / stat["games_played"]
595
+ if stat["games_played"] > 0
596
+ else 0.0
597
+ )
598
+ gm_penalties_per_game = (
599
+ stat["gm_penalties"] / stat["games_played"]
600
+ if stat["games_played"] > 0
601
+ else 0.0
602
+ ) # Calculate GM penalties per game
384
603
  skater_stat = StatsModel(
385
604
  aggregation_id=aggregation_id,
386
605
  human_id=human_id,
387
- games_played=stat['games_played'], # DEPRECATED - for backward compatibility
388
- games_participated=stat['games_participated'], # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
389
- games_participated_rank=stat['games_participated_rank'],
390
- games_with_stats=stat['games_with_stats'], # Games with full stats: FINAL, FINAL_SO only
391
- games_with_stats_rank=stat['games_with_stats_rank'],
392
- goals=stat['goals'],
393
- assists=stat['assists'],
394
- points=stat['goals'] + stat['assists'],
395
- penalties=stat['penalties'],
396
- gm_penalties=stat['gm_penalties'], # Include GM penalties
606
+ games_played=stat[
607
+ "games_played"
608
+ ], # DEPRECATED - for backward compatibility
609
+ games_participated=stat[
610
+ "games_participated"
611
+ ], # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
612
+ games_participated_rank=stat["games_participated_rank"],
613
+ games_with_stats=stat[
614
+ "games_with_stats"
615
+ ], # Games with full stats: FINAL, FINAL_SO only
616
+ games_with_stats_rank=stat["games_with_stats_rank"],
617
+ goals=stat["goals"],
618
+ assists=stat["assists"],
619
+ points=stat["goals"] + stat["assists"],
620
+ penalties=stat["penalties"],
621
+ gm_penalties=stat["gm_penalties"], # Include GM penalties
397
622
  goals_per_game=goals_per_game,
398
623
  points_per_game=points_per_game,
399
624
  assists_per_game=assists_per_game,
400
625
  penalties_per_game=penalties_per_game,
401
626
  gm_penalties_per_game=gm_penalties_per_game, # Include GM penalties per game
402
- games_played_rank=stat['games_played_rank'],
403
- goals_rank=stat['goals_rank'],
404
- assists_rank=stat['assists_rank'],
405
- points_rank=stat['points_rank'],
406
- penalties_rank=stat['penalties_rank'],
407
- gm_penalties_rank=stat['gm_penalties_rank'], # Include GM penalties rank
408
- goals_per_game_rank=stat['goals_per_game_rank'],
409
- points_per_game_rank=stat['points_per_game_rank'],
410
- assists_per_game_rank=stat['assists_per_game_rank'],
411
- penalties_per_game_rank=stat['penalties_per_game_rank'],
412
- gm_penalties_per_game_rank=stat['gm_penalties_per_game_rank'], # Include GM penalties per game rank
627
+ games_played_rank=stat["games_played_rank"],
628
+ goals_rank=stat["goals_rank"],
629
+ assists_rank=stat["assists_rank"],
630
+ points_rank=stat["points_rank"],
631
+ penalties_rank=stat["penalties_rank"],
632
+ gm_penalties_rank=stat["gm_penalties_rank"], # Include GM penalties rank
633
+ goals_per_game_rank=stat["goals_per_game_rank"],
634
+ points_per_game_rank=stat["points_per_game_rank"],
635
+ assists_per_game_rank=stat["assists_per_game_rank"],
636
+ penalties_per_game_rank=stat["penalties_per_game_rank"],
637
+ gm_penalties_per_game_rank=stat[
638
+ "gm_penalties_per_game_rank"
639
+ ], # Include GM penalties per game rank
413
640
  total_in_rank=total_in_rank,
414
- current_point_streak=stat.get('current_point_streak', 0),
415
- current_point_streak_rank=stat.get('current_point_streak_rank', 0),
416
- current_point_streak_avg_points=stat.get('current_point_streak_avg_points', 0.0),
417
- current_point_streak_avg_points_rank=stat.get('current_point_streak_avg_points_rank', 0),
418
- first_game_id=stat['first_game_id'],
419
- last_game_id=stat['last_game_id']
641
+ current_point_streak=stat.get("current_point_streak", 0),
642
+ current_point_streak_rank=stat.get("current_point_streak_rank", 0),
643
+ current_point_streak_avg_points=stat.get(
644
+ "current_point_streak_avg_points", 0.0
645
+ ),
646
+ current_point_streak_avg_points_rank=stat.get(
647
+ "current_point_streak_avg_points_rank", 0
648
+ ),
649
+ first_game_id=stat["first_game_id"],
650
+ last_game_id=stat["last_game_id"],
420
651
  )
421
652
  session.add(skater_stat)
422
653
  # Commit in batches
@@ -424,6 +655,7 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, debug_huma
424
655
  session.commit()
425
656
  session.commit()
426
657
 
658
+
427
659
  def run_aggregate_skater_stats():
428
660
  session = create_session("boss")
429
661
  human_id_to_debug = None
@@ -434,51 +666,142 @@ def run_aggregate_skater_stats():
434
666
 
435
667
  for org_id in org_ids:
436
668
  division_ids = get_all_division_ids_for_org(session, org_id)
437
- org_name = session.query(Organization.organization_name).filter(Organization.id == org_id).scalar() or f"org_id {org_id}"
438
-
669
+ org_name = (
670
+ session.query(Organization.organization_name)
671
+ .filter(Organization.id == org_id)
672
+ .scalar()
673
+ or f"org_id {org_id}"
674
+ )
675
+
439
676
  if human_id_to_debug is None and division_ids:
440
677
  # Process divisions with progress tracking
441
- progress = create_progress_tracker(len(division_ids), f"Processing {len(division_ids)} divisions for {org_name}")
678
+ progress = create_progress_tracker(
679
+ len(division_ids),
680
+ f"Processing {len(division_ids)} divisions for {org_name}",
681
+ )
442
682
  for i, division_id in enumerate(division_ids):
443
- aggregate_skater_stats(session, aggregation_type='division', aggregation_id=division_id, debug_human_id=human_id_to_debug)
444
- aggregate_skater_stats(session, aggregation_type='division', aggregation_id=division_id, debug_human_id=human_id_to_debug, aggregation_window='Weekly')
445
- aggregate_skater_stats(session, aggregation_type='division', aggregation_id=division_id, debug_human_id=human_id_to_debug, aggregation_window='Daily')
683
+ aggregate_skater_stats(
684
+ session,
685
+ aggregation_type="division",
686
+ aggregation_id=division_id,
687
+ debug_human_id=human_id_to_debug,
688
+ )
689
+ aggregate_skater_stats(
690
+ session,
691
+ aggregation_type="division",
692
+ aggregation_id=division_id,
693
+ debug_human_id=human_id_to_debug,
694
+ aggregation_window="Weekly",
695
+ )
696
+ aggregate_skater_stats(
697
+ session,
698
+ aggregation_type="division",
699
+ aggregation_id=division_id,
700
+ debug_human_id=human_id_to_debug,
701
+ aggregation_window="Daily",
702
+ )
446
703
  progress.update(i + 1)
447
704
  else:
448
705
  # Debug mode or no divisions - process without progress tracking
449
706
  for division_id in division_ids:
450
- aggregate_skater_stats(session, aggregation_type='division', aggregation_id=division_id, debug_human_id=human_id_to_debug)
451
- aggregate_skater_stats(session, aggregation_type='division', aggregation_id=division_id, debug_human_id=human_id_to_debug, aggregation_window='Weekly')
452
- aggregate_skater_stats(session, aggregation_type='division', aggregation_id=division_id, debug_human_id=human_id_to_debug, aggregation_window='Daily')
707
+ aggregate_skater_stats(
708
+ session,
709
+ aggregation_type="division",
710
+ aggregation_id=division_id,
711
+ debug_human_id=human_id_to_debug,
712
+ )
713
+ aggregate_skater_stats(
714
+ session,
715
+ aggregation_type="division",
716
+ aggregation_id=division_id,
717
+ debug_human_id=human_id_to_debug,
718
+ aggregation_window="Weekly",
719
+ )
720
+ aggregate_skater_stats(
721
+ session,
722
+ aggregation_type="division",
723
+ aggregation_id=division_id,
724
+ debug_human_id=human_id_to_debug,
725
+ aggregation_window="Daily",
726
+ )
453
727
 
454
728
  # Process org-level stats with progress tracking
455
729
  if human_id_to_debug is None:
456
- org_progress = create_progress_tracker(3, f"Processing org-level stats for {org_name}")
457
- aggregate_skater_stats(session, aggregation_type='org', aggregation_id=org_id, debug_human_id=human_id_to_debug)
730
+ org_progress = create_progress_tracker(
731
+ 3, f"Processing org-level stats for {org_name}"
732
+ )
733
+ aggregate_skater_stats(
734
+ session,
735
+ aggregation_type="org",
736
+ aggregation_id=org_id,
737
+ debug_human_id=human_id_to_debug,
738
+ )
458
739
  org_progress.update(1)
459
- aggregate_skater_stats(session, aggregation_type='org', aggregation_id=org_id, debug_human_id=human_id_to_debug, aggregation_window='Weekly')
740
+ aggregate_skater_stats(
741
+ session,
742
+ aggregation_type="org",
743
+ aggregation_id=org_id,
744
+ debug_human_id=human_id_to_debug,
745
+ aggregation_window="Weekly",
746
+ )
460
747
  org_progress.update(2)
461
- aggregate_skater_stats(session, aggregation_type='org', aggregation_id=org_id, debug_human_id=human_id_to_debug, aggregation_window='Daily')
748
+ aggregate_skater_stats(
749
+ session,
750
+ aggregation_type="org",
751
+ aggregation_id=org_id,
752
+ debug_human_id=human_id_to_debug,
753
+ aggregation_window="Daily",
754
+ )
462
755
  org_progress.update(3)
463
756
  else:
464
- aggregate_skater_stats(session, aggregation_type='org', aggregation_id=org_id, debug_human_id=human_id_to_debug)
465
- aggregate_skater_stats(session, aggregation_type='org', aggregation_id=org_id, debug_human_id=human_id_to_debug, aggregation_window='Weekly')
466
- aggregate_skater_stats(session, aggregation_type='org', aggregation_id=org_id, debug_human_id=human_id_to_debug, aggregation_window='Daily')
467
-
757
+ aggregate_skater_stats(
758
+ session,
759
+ aggregation_type="org",
760
+ aggregation_id=org_id,
761
+ debug_human_id=human_id_to_debug,
762
+ )
763
+ aggregate_skater_stats(
764
+ session,
765
+ aggregation_type="org",
766
+ aggregation_id=org_id,
767
+ debug_human_id=human_id_to_debug,
768
+ aggregation_window="Weekly",
769
+ )
770
+ aggregate_skater_stats(
771
+ session,
772
+ aggregation_type="org",
773
+ aggregation_id=org_id,
774
+ debug_human_id=human_id_to_debug,
775
+ aggregation_window="Daily",
776
+ )
777
+
468
778
  # Aggregate by level
469
779
  level_ids = session.query(Division.level_id).distinct().all()
470
780
  level_ids = [level_id[0] for level_id in level_ids if level_id[0] is not None]
471
-
781
+
472
782
  if human_id_to_debug is None and level_ids:
473
783
  # Process levels with progress tracking
474
- level_progress = create_progress_tracker(len(level_ids), f"Processing {len(level_ids)} skill levels")
784
+ level_progress = create_progress_tracker(
785
+ len(level_ids), f"Processing {len(level_ids)} skill levels"
786
+ )
475
787
  for i, level_id in enumerate(level_ids):
476
- aggregate_skater_stats(session, aggregation_type='level', aggregation_id=level_id, debug_human_id=human_id_to_debug)
788
+ aggregate_skater_stats(
789
+ session,
790
+ aggregation_type="level",
791
+ aggregation_id=level_id,
792
+ debug_human_id=human_id_to_debug,
793
+ )
477
794
  level_progress.update(i + 1)
478
795
  else:
479
796
  # Debug mode or no levels - process without progress tracking
480
797
  for level_id in level_ids:
481
- aggregate_skater_stats(session, aggregation_type='level', aggregation_id=level_id, debug_human_id=human_id_to_debug)
798
+ aggregate_skater_stats(
799
+ session,
800
+ aggregation_type="level",
801
+ aggregation_id=level_id,
802
+ debug_human_id=human_id_to_debug,
803
+ )
804
+
482
805
 
483
806
  if __name__ == "__main__":
484
807
  run_aggregate_skater_stats()