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,21 +1,38 @@
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
 
7
- from datetime import datetime, timedelta
8
+
8
9
  import sqlalchemy
9
- from hockey_blast_common_lib.models import Game, Penalty, Organization, Division
10
- from hockey_blast_common_lib.stats_models import OrgStatsReferee, DivisionStatsReferee, OrgStatsWeeklyReferee, OrgStatsDailyReferee, DivisionStatsWeeklyReferee, DivisionStatsDailyReferee, LevelStatsReferee
10
+ from sqlalchemy.sql import case, func
11
+
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 assign_ranks
16
- from hockey_blast_common_lib.utils import get_start_datetime
17
- from hockey_blast_common_lib.stats_utils import ALL_ORGS_ID
13
+ from hockey_blast_common_lib.models import Division, Game, Organization, Penalty
14
+ from hockey_blast_common_lib.options import (
15
+ MIN_GAMES_FOR_DIVISION_STATS,
16
+ MIN_GAMES_FOR_LEVEL_STATS,
17
+ MIN_GAMES_FOR_ORG_STATS,
18
+ )
18
19
  from hockey_blast_common_lib.progress_utils import create_progress_tracker
20
+ from hockey_blast_common_lib.stats_models import (
21
+ DivisionStatsDailyReferee,
22
+ DivisionStatsReferee,
23
+ DivisionStatsWeeklyReferee,
24
+ LevelStatsReferee,
25
+ OrgStatsDailyReferee,
26
+ OrgStatsReferee,
27
+ OrgStatsWeeklyReferee,
28
+ )
29
+ from hockey_blast_common_lib.stats_utils import ALL_ORGS_ID
30
+ from hockey_blast_common_lib.utils import (
31
+ assign_ranks,
32
+ get_all_division_ids_for_org,
33
+ get_non_human_ids,
34
+ get_start_datetime,
35
+ )
19
36
 
20
37
  # Import status constants for game filtering
21
38
  FINAL_STATUS = "Final"
@@ -23,34 +40,44 @@ FINAL_SO_STATUS = "Final(SO)"
23
40
  FORFEIT_STATUS = "FORFEIT"
24
41
  NOEVENTS_STATUS = "NOEVENTS"
25
42
 
26
- def aggregate_referee_stats(session, aggregation_type, aggregation_id, aggregation_window=None):
43
+
44
+ def aggregate_referee_stats(
45
+ session, aggregation_type, aggregation_id, aggregation_window=None
46
+ ):
27
47
  human_ids_to_filter = get_non_human_ids(session)
28
48
 
29
- if aggregation_type == 'org':
49
+ if aggregation_type == "org":
30
50
  if aggregation_id == ALL_ORGS_ID:
31
51
  aggregation_name = "All Orgs"
32
52
  filter_condition = sqlalchemy.true() # No filter for organization
33
53
  else:
34
- aggregation_name = session.query(Organization).filter(Organization.id == aggregation_id).first().organization_name
54
+ aggregation_name = (
55
+ session.query(Organization)
56
+ .filter(Organization.id == aggregation_id)
57
+ .first()
58
+ .organization_name
59
+ )
35
60
  filter_condition = Game.org_id == aggregation_id
36
- print(f"Aggregating referee stats for {aggregation_name} with window {aggregation_window}...")
37
- if aggregation_window == 'Daily':
61
+ print(
62
+ f"Aggregating referee stats for {aggregation_name} with window {aggregation_window}..."
63
+ )
64
+ if aggregation_window == "Daily":
38
65
  StatsModel = OrgStatsDailyReferee
39
- elif aggregation_window == 'Weekly':
66
+ elif aggregation_window == "Weekly":
40
67
  StatsModel = OrgStatsWeeklyReferee
41
68
  else:
42
69
  StatsModel = OrgStatsReferee
43
70
  min_games = MIN_GAMES_FOR_ORG_STATS
44
- elif aggregation_type == 'division':
45
- if aggregation_window == 'Daily':
71
+ elif aggregation_type == "division":
72
+ if aggregation_window == "Daily":
46
73
  StatsModel = DivisionStatsDailyReferee
47
- elif aggregation_window == 'Weekly':
74
+ elif aggregation_window == "Weekly":
48
75
  StatsModel = DivisionStatsWeeklyReferee
49
76
  else:
50
77
  StatsModel = DivisionStatsReferee
51
78
  min_games = MIN_GAMES_FOR_DIVISION_STATS
52
79
  filter_condition = Game.division_id == aggregation_id
53
- elif aggregation_type == 'level':
80
+ elif aggregation_type == "level":
54
81
  StatsModel = LevelStatsReferee
55
82
  min_games = MIN_GAMES_FOR_LEVEL_STATS
56
83
  filter_condition = Division.level_id == aggregation_id
@@ -62,60 +89,87 @@ def aggregate_referee_stats(session, aggregation_type, aggregation_id, aggregati
62
89
  raise ValueError("Invalid aggregation type")
63
90
 
64
91
  # Delete existing items from the stats table
65
- session.query(StatsModel).filter(StatsModel.aggregation_id == aggregation_id).delete()
92
+ session.query(StatsModel).filter(
93
+ StatsModel.aggregation_id == aggregation_id
94
+ ).delete()
66
95
  session.commit()
67
96
 
68
97
  # Apply aggregation window filter
69
98
  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()
99
+ last_game_datetime_str = (
100
+ session.query(func.max(func.concat(Game.date, " ", Game.time)))
101
+ .filter(filter_condition, Game.status.like("Final%"))
102
+ .scalar()
103
+ )
71
104
  start_datetime = get_start_datetime(last_game_datetime_str, aggregation_window)
72
105
  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)
106
+ game_window_filter = func.cast(
107
+ func.concat(Game.date, " ", Game.time), sqlalchemy.types.TIMESTAMP
108
+ ).between(start_datetime, last_game_datetime_str)
74
109
  filter_condition = filter_condition & game_window_filter
75
110
  else:
76
- #print(f"Warning: No valid start datetime for aggregation window '{aggregation_window}' for {aggregation_name}. No games will be included.")
111
+ # print(f"Warning: No valid start datetime for aggregation window '{aggregation_window}' for {aggregation_name}. No games will be included.")
77
112
  return
78
113
 
79
114
  filter_condition = filter_condition & (Division.id == Game.division_id)
80
115
  # Aggregate games reffed for each referee
81
116
  # games_participated: Count FINAL, FINAL_SO, FORFEIT, NOEVENTS
82
117
  # games_with_stats: Count only FINAL, FINAL_SO (for per-game averages)
83
- games_reffed_stats = session.query(
84
- Game.referee_1_id.label('human_id'),
85
- func.count(Game.id).label('games_reffed'), # 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.array_agg(Game.id).label('game_ids')
95
- ).filter(filter_condition).group_by(Game.referee_1_id).all()
96
-
97
- games_reffed_stats_2 = session.query(
98
- Game.referee_2_id.label('human_id'),
99
- func.count(Game.id).label('games_reffed'), # DEPRECATED - will be replaced by games_participated
100
- func.sum(case(
101
- (Game.status.in_([FINAL_STATUS, FINAL_SO_STATUS, FORFEIT_STATUS, NOEVENTS_STATUS]), 1),
102
- else_=0
103
- )).label('games_participated'),
104
- func.sum(case(
105
- (Game.status.in_([FINAL_STATUS, FINAL_SO_STATUS]), 1),
106
- else_=0
107
- )).label('games_with_stats'),
108
- func.array_agg(Game.id).label('game_ids')
109
- ).filter(filter_condition).group_by(Game.referee_2_id).all()
118
+ # Filter by game status upfront for performance
119
+ status_filter = Game.status.in_(
120
+ [FINAL_STATUS, FINAL_SO_STATUS, FORFEIT_STATUS, NOEVENTS_STATUS]
121
+ )
122
+
123
+ games_reffed_stats = (
124
+ session.query(
125
+ Game.referee_1_id.label("human_id"),
126
+ func.count(Game.id).label("games_reffed"),
127
+ func.count(Game.id).label(
128
+ "games_participated"
129
+ ), # Same as games_reffed after filtering
130
+ func.count(Game.id).label(
131
+ "games_with_stats"
132
+ ), # Same as games_reffed after filtering
133
+ func.array_agg(Game.id).label("game_ids"),
134
+ )
135
+ .filter(filter_condition, status_filter)
136
+ .group_by(Game.referee_1_id)
137
+ .all()
138
+ )
139
+
140
+ games_reffed_stats_2 = (
141
+ session.query(
142
+ Game.referee_2_id.label("human_id"),
143
+ func.count(Game.id).label("games_reffed"),
144
+ func.count(Game.id).label(
145
+ "games_participated"
146
+ ), # Same as games_reffed after filtering
147
+ func.count(Game.id).label(
148
+ "games_with_stats"
149
+ ), # Same as games_reffed after filtering
150
+ func.array_agg(Game.id).label("game_ids"),
151
+ )
152
+ .filter(filter_condition, status_filter)
153
+ .group_by(Game.referee_2_id)
154
+ .all()
155
+ )
110
156
 
111
157
  # Aggregate penalties given for each referee
112
- penalties_given_stats = session.query(
113
- Game.id.label('game_id'),
114
- Game.referee_1_id,
115
- Game.referee_2_id,
116
- func.count(Penalty.id).label('penalties_given'),
117
- func.sum(case((func.lower(Penalty.penalty_minutes) == 'gm', 1), else_=0)).label('gm_given')
118
- ).join(Game, Game.id == Penalty.game_id).filter(filter_condition).group_by(Game.id, Game.referee_1_id, Game.referee_2_id).all()
158
+ penalties_given_stats = (
159
+ session.query(
160
+ Game.id.label("game_id"),
161
+ Game.referee_1_id,
162
+ Game.referee_2_id,
163
+ func.count(Penalty.id).label("penalties_given"),
164
+ func.sum(
165
+ case((func.lower(Penalty.penalty_minutes) == "gm", 1), else_=0)
166
+ ).label("gm_given"),
167
+ )
168
+ .join(Game, Game.id == Penalty.game_id)
169
+ .filter(filter_condition)
170
+ .group_by(Game.id, Game.referee_1_id, Game.referee_2_id)
171
+ .all()
172
+ )
119
173
 
120
174
  # Combine the results
121
175
  stats_dict = {}
@@ -125,21 +179,21 @@ def aggregate_referee_stats(session, aggregation_type, aggregation_id, aggregati
125
179
  key = (aggregation_id, stat.human_id)
126
180
  if key not in stats_dict:
127
181
  stats_dict[key] = {
128
- 'games_reffed': 0, # DEPRECATED - for backward compatibility
129
- 'games_participated': 0, # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
130
- 'games_with_stats': 0, # Games with full stats: FINAL, FINAL_SO only
131
- 'penalties_given': 0,
132
- 'gm_given': 0,
133
- 'penalties_per_game': 0.0,
134
- 'gm_per_game': 0.0,
135
- 'game_ids': [],
136
- 'first_game_id': None,
137
- 'last_game_id': None
182
+ "games_reffed": 0, # DEPRECATED - for backward compatibility
183
+ "games_participated": 0, # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
184
+ "games_with_stats": 0, # Games with full stats: FINAL, FINAL_SO only
185
+ "penalties_given": 0,
186
+ "gm_given": 0,
187
+ "penalties_per_game": 0.0,
188
+ "gm_per_game": 0.0,
189
+ "game_ids": [],
190
+ "first_game_id": None,
191
+ "last_game_id": None,
138
192
  }
139
- stats_dict[key]['games_reffed'] += stat.games_reffed
140
- stats_dict[key]['games_participated'] += stat.games_participated
141
- stats_dict[key]['games_with_stats'] += stat.games_with_stats
142
- stats_dict[key]['game_ids'].extend(stat.game_ids)
193
+ stats_dict[key]["games_reffed"] += stat.games_reffed
194
+ stats_dict[key]["games_participated"] += stat.games_participated
195
+ stats_dict[key]["games_with_stats"] += stat.games_with_stats
196
+ stats_dict[key]["game_ids"].extend(stat.game_ids)
143
197
 
144
198
  for stat in games_reffed_stats_2:
145
199
  if stat.human_id in human_ids_to_filter:
@@ -147,69 +201,85 @@ def aggregate_referee_stats(session, aggregation_type, aggregation_id, aggregati
147
201
  key = (aggregation_id, stat.human_id)
148
202
  if key not in stats_dict:
149
203
  stats_dict[key] = {
150
- 'games_reffed': 0, # DEPRECATED - for backward compatibility
151
- 'games_participated': 0, # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
152
- 'games_with_stats': 0, # Games with full stats: FINAL, FINAL_SO only
153
- 'penalties_given': 0,
154
- 'gm_given': 0,
155
- 'penalties_per_game': 0.0,
156
- 'gm_per_game': 0.0,
157
- 'game_ids': [],
158
- 'first_game_id': None,
159
- 'last_game_id': None
204
+ "games_reffed": 0, # DEPRECATED - for backward compatibility
205
+ "games_participated": 0, # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
206
+ "games_with_stats": 0, # Games with full stats: FINAL, FINAL_SO only
207
+ "penalties_given": 0,
208
+ "gm_given": 0,
209
+ "penalties_per_game": 0.0,
210
+ "gm_per_game": 0.0,
211
+ "game_ids": [],
212
+ "first_game_id": None,
213
+ "last_game_id": None,
160
214
  }
161
- stats_dict[key]['games_reffed'] += stat.games_reffed
162
- stats_dict[key]['games_participated'] += stat.games_participated
163
- stats_dict[key]['games_with_stats'] += stat.games_with_stats
164
- stats_dict[key]['game_ids'].extend(stat.game_ids)
215
+ stats_dict[key]["games_reffed"] += stat.games_reffed
216
+ stats_dict[key]["games_participated"] += stat.games_participated
217
+ stats_dict[key]["games_with_stats"] += stat.games_with_stats
218
+ stats_dict[key]["game_ids"].extend(stat.game_ids)
165
219
 
166
220
  # Filter out entries with games_reffed less than min_games
167
- stats_dict = {key: value for key, value in stats_dict.items() if value['games_reffed'] >= min_games}
221
+ stats_dict = {
222
+ key: value
223
+ for key, value in stats_dict.items()
224
+ if value["games_reffed"] >= min_games
225
+ }
168
226
 
169
227
  for stat in penalties_given_stats:
170
228
  if stat.referee_1_id and stat.referee_1_id not in human_ids_to_filter:
171
229
  key = (aggregation_id, stat.referee_1_id)
172
230
  if key in stats_dict:
173
- stats_dict[key]['penalties_given'] += stat.penalties_given / 2
174
- stats_dict[key]['gm_given'] += stat.gm_given / 2
175
- stats_dict[key]['game_ids'].append(stat.game_id)
231
+ stats_dict[key]["penalties_given"] += stat.penalties_given / 2
232
+ stats_dict[key]["gm_given"] += stat.gm_given / 2
233
+ stats_dict[key]["game_ids"].append(stat.game_id)
176
234
 
177
235
  if stat.referee_2_id and stat.referee_2_id not in human_ids_to_filter:
178
236
  key = (aggregation_id, stat.referee_2_id)
179
237
  if key in stats_dict:
180
- stats_dict[key]['penalties_given'] += stat.penalties_given / 2
181
- stats_dict[key]['gm_given'] += stat.gm_given / 2
182
- stats_dict[key]['game_ids'].append(stat.game_id)
238
+ stats_dict[key]["penalties_given"] += stat.penalties_given / 2
239
+ stats_dict[key]["gm_given"] += stat.gm_given / 2
240
+ stats_dict[key]["game_ids"].append(stat.game_id)
183
241
 
184
242
  # Calculate per game stats (using games_with_stats as denominator for accuracy)
185
243
  for key, stat in stats_dict.items():
186
- if stat['games_with_stats'] > 0:
187
- stat['penalties_per_game'] = stat['penalties_given'] / stat['games_with_stats']
188
- stat['gm_per_game'] = stat['gm_given'] / stat['games_with_stats']
244
+ if stat["games_with_stats"] > 0:
245
+ stat["penalties_per_game"] = (
246
+ stat["penalties_given"] / stat["games_with_stats"]
247
+ )
248
+ stat["gm_per_game"] = stat["gm_given"] / stat["games_with_stats"]
189
249
 
190
250
  # Ensure all keys have valid human_id values
191
251
  stats_dict = {key: value for key, value in stats_dict.items() if key[1] is not None}
192
252
 
193
253
  # Populate first_game_id and last_game_id
194
254
  for key, stat in stats_dict.items():
195
- all_game_ids = stat['game_ids']
255
+ all_game_ids = stat["game_ids"]
196
256
  if all_game_ids:
197
- first_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date, Game.time).first()
198
- last_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date.desc(), Game.time.desc()).first()
199
- stat['first_game_id'] = first_game.id if first_game else None
200
- stat['last_game_id'] = last_game.id if last_game else None
257
+ first_game = (
258
+ session.query(Game)
259
+ .filter(Game.id.in_(all_game_ids))
260
+ .order_by(Game.date, Game.time)
261
+ .first()
262
+ )
263
+ last_game = (
264
+ session.query(Game)
265
+ .filter(Game.id.in_(all_game_ids))
266
+ .order_by(Game.date.desc(), Game.time.desc())
267
+ .first()
268
+ )
269
+ stat["first_game_id"] = first_game.id if first_game else None
270
+ stat["last_game_id"] = last_game.id if last_game else None
201
271
 
202
272
  # Calculate total_in_rank
203
273
  total_in_rank = len(stats_dict)
204
274
 
205
275
  # Assign ranks
206
- assign_ranks(stats_dict, 'games_reffed')
207
- assign_ranks(stats_dict, 'games_participated') # Rank by total participation
208
- assign_ranks(stats_dict, 'games_with_stats') # Rank by games with full stats
209
- assign_ranks(stats_dict, 'penalties_given')
210
- assign_ranks(stats_dict, 'penalties_per_game')
211
- assign_ranks(stats_dict, 'gm_given')
212
- assign_ranks(stats_dict, 'gm_per_game')
276
+ assign_ranks(stats_dict, "games_reffed")
277
+ assign_ranks(stats_dict, "games_participated") # Rank by total participation
278
+ assign_ranks(stats_dict, "games_with_stats") # Rank by games with full stats
279
+ assign_ranks(stats_dict, "penalties_given")
280
+ assign_ranks(stats_dict, "penalties_per_game")
281
+ assign_ranks(stats_dict, "gm_given")
282
+ assign_ranks(stats_dict, "gm_per_game")
213
283
 
214
284
  # Insert aggregated stats into the appropriate table with progress output
215
285
  total_items = len(stats_dict)
@@ -219,23 +289,29 @@ def aggregate_referee_stats(session, aggregation_type, aggregation_id, aggregati
219
289
  referee_stat = StatsModel(
220
290
  aggregation_id=aggregation_id,
221
291
  human_id=human_id,
222
- games_reffed=stat['games_reffed'], # DEPRECATED - for backward compatibility
223
- games_participated=stat['games_participated'], # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
224
- games_participated_rank=stat['games_participated_rank'],
225
- games_with_stats=stat['games_with_stats'], # Games with full stats: FINAL, FINAL_SO only
226
- games_with_stats_rank=stat['games_with_stats_rank'],
227
- penalties_given=stat['penalties_given'],
228
- penalties_per_game=stat['penalties_per_game'],
229
- gm_given=stat['gm_given'],
230
- gm_per_game=stat['gm_per_game'],
231
- games_reffed_rank=stat['games_reffed_rank'],
232
- penalties_given_rank=stat['penalties_given_rank'],
233
- penalties_per_game_rank=stat['penalties_per_game_rank'],
234
- gm_given_rank=stat['gm_given_rank'],
235
- gm_per_game_rank=stat['gm_per_game_rank'],
292
+ games_reffed=stat[
293
+ "games_reffed"
294
+ ], # DEPRECATED - for backward compatibility
295
+ games_participated=stat[
296
+ "games_participated"
297
+ ], # Total games: FINAL, FINAL_SO, FORFEIT, NOEVENTS
298
+ games_participated_rank=stat["games_participated_rank"],
299
+ games_with_stats=stat[
300
+ "games_with_stats"
301
+ ], # Games with full stats: FINAL, FINAL_SO only
302
+ games_with_stats_rank=stat["games_with_stats_rank"],
303
+ penalties_given=stat["penalties_given"],
304
+ penalties_per_game=stat["penalties_per_game"],
305
+ gm_given=stat["gm_given"],
306
+ gm_per_game=stat["gm_per_game"],
307
+ games_reffed_rank=stat["games_reffed_rank"],
308
+ penalties_given_rank=stat["penalties_given_rank"],
309
+ penalties_per_game_rank=stat["penalties_per_game_rank"],
310
+ gm_given_rank=stat["gm_given_rank"],
311
+ gm_per_game_rank=stat["gm_per_game_rank"],
236
312
  total_in_rank=total_in_rank,
237
- first_game_id=stat['first_game_id'],
238
- last_game_id=stat['last_game_id']
313
+ first_game_id=stat["first_game_id"],
314
+ last_game_id=stat["last_game_id"],
239
315
  )
240
316
  session.add(referee_stat)
241
317
  # Commit in batches
@@ -243,6 +319,7 @@ def aggregate_referee_stats(session, aggregation_type, aggregation_id, aggregati
243
319
  session.commit()
244
320
  session.commit()
245
321
 
322
+
246
323
  def run_aggregate_referee_stats():
247
324
  session = create_session("boss")
248
325
  human_id_to_debug = None
@@ -253,51 +330,116 @@ def run_aggregate_referee_stats():
253
330
 
254
331
  for org_id in org_ids:
255
332
  division_ids = get_all_division_ids_for_org(session, org_id)
256
- org_name = session.query(Organization.organization_name).filter(Organization.id == org_id).scalar() or f"org_id {org_id}"
257
-
333
+ org_name = (
334
+ session.query(Organization.organization_name)
335
+ .filter(Organization.id == org_id)
336
+ .scalar()
337
+ or f"org_id {org_id}"
338
+ )
339
+
258
340
  if human_id_to_debug is None and division_ids:
259
341
  # Process divisions with progress tracking
260
- progress = create_progress_tracker(len(division_ids), f"Processing {len(division_ids)} divisions for {org_name}")
342
+ progress = create_progress_tracker(
343
+ len(division_ids),
344
+ f"Processing {len(division_ids)} divisions for {org_name}",
345
+ )
261
346
  for i, division_id in enumerate(division_ids):
262
- aggregate_referee_stats(session, aggregation_type='division', aggregation_id=division_id)
263
- aggregate_referee_stats(session, aggregation_type='division', aggregation_id=division_id, aggregation_window='Weekly')
264
- aggregate_referee_stats(session, aggregation_type='division', aggregation_id=division_id, aggregation_window='Daily')
347
+ aggregate_referee_stats(
348
+ session, aggregation_type="division", aggregation_id=division_id
349
+ )
350
+ aggregate_referee_stats(
351
+ session,
352
+ aggregation_type="division",
353
+ aggregation_id=division_id,
354
+ aggregation_window="Weekly",
355
+ )
356
+ aggregate_referee_stats(
357
+ session,
358
+ aggregation_type="division",
359
+ aggregation_id=division_id,
360
+ aggregation_window="Daily",
361
+ )
265
362
  progress.update(i + 1)
266
363
  else:
267
364
  # Debug mode or no divisions - process without progress tracking
268
365
  for division_id in division_ids:
269
- aggregate_referee_stats(session, aggregation_type='division', aggregation_id=division_id)
270
- aggregate_referee_stats(session, aggregation_type='division', aggregation_id=division_id, aggregation_window='Weekly')
271
- aggregate_referee_stats(session, aggregation_type='division', aggregation_id=division_id, aggregation_window='Daily')
366
+ aggregate_referee_stats(
367
+ session, aggregation_type="division", aggregation_id=division_id
368
+ )
369
+ aggregate_referee_stats(
370
+ session,
371
+ aggregation_type="division",
372
+ aggregation_id=division_id,
373
+ aggregation_window="Weekly",
374
+ )
375
+ aggregate_referee_stats(
376
+ session,
377
+ aggregation_type="division",
378
+ aggregation_id=division_id,
379
+ aggregation_window="Daily",
380
+ )
272
381
 
273
382
  # Process org-level stats with progress tracking
274
383
  if human_id_to_debug is None:
275
- org_progress = create_progress_tracker(3, f"Processing org-level stats for {org_name}")
276
- aggregate_referee_stats(session, aggregation_type='org', aggregation_id=org_id)
384
+ org_progress = create_progress_tracker(
385
+ 3, f"Processing org-level stats for {org_name}"
386
+ )
387
+ aggregate_referee_stats(
388
+ session, aggregation_type="org", aggregation_id=org_id
389
+ )
277
390
  org_progress.update(1)
278
- aggregate_referee_stats(session, aggregation_type='org', aggregation_id=org_id, aggregation_window='Weekly')
391
+ aggregate_referee_stats(
392
+ session,
393
+ aggregation_type="org",
394
+ aggregation_id=org_id,
395
+ aggregation_window="Weekly",
396
+ )
279
397
  org_progress.update(2)
280
- aggregate_referee_stats(session, aggregation_type='org', aggregation_id=org_id, aggregation_window='Daily')
398
+ aggregate_referee_stats(
399
+ session,
400
+ aggregation_type="org",
401
+ aggregation_id=org_id,
402
+ aggregation_window="Daily",
403
+ )
281
404
  org_progress.update(3)
282
405
  else:
283
- aggregate_referee_stats(session, aggregation_type='org', aggregation_id=org_id)
284
- aggregate_referee_stats(session, aggregation_type='org', aggregation_id=org_id, aggregation_window='Weekly')
285
- aggregate_referee_stats(session, aggregation_type='org', aggregation_id=org_id, aggregation_window='Daily')
286
-
406
+ aggregate_referee_stats(
407
+ session, aggregation_type="org", aggregation_id=org_id
408
+ )
409
+ aggregate_referee_stats(
410
+ session,
411
+ aggregation_type="org",
412
+ aggregation_id=org_id,
413
+ aggregation_window="Weekly",
414
+ )
415
+ aggregate_referee_stats(
416
+ session,
417
+ aggregation_type="org",
418
+ aggregation_id=org_id,
419
+ aggregation_window="Daily",
420
+ )
421
+
287
422
  # Aggregate by level
288
423
  level_ids = session.query(Division.level_id).distinct().all()
289
424
  level_ids = [level_id[0] for level_id in level_ids if level_id[0] is not None]
290
-
425
+
291
426
  if human_id_to_debug is None and level_ids:
292
427
  # Process levels with progress tracking
293
- level_progress = create_progress_tracker(len(level_ids), f"Processing {len(level_ids)} skill levels")
428
+ level_progress = create_progress_tracker(
429
+ len(level_ids), f"Processing {len(level_ids)} skill levels"
430
+ )
294
431
  for i, level_id in enumerate(level_ids):
295
- aggregate_referee_stats(session, aggregation_type='level', aggregation_id=level_id)
432
+ aggregate_referee_stats(
433
+ session, aggregation_type="level", aggregation_id=level_id
434
+ )
296
435
  level_progress.update(i + 1)
297
436
  else:
298
437
  # Debug mode or no levels - process without progress tracking
299
438
  for level_id in level_ids:
300
- aggregate_referee_stats(session, aggregation_type='level', aggregation_id=level_id)
439
+ aggregate_referee_stats(
440
+ session, aggregation_type="level", aggregation_id=level_id
441
+ )
442
+
301
443
 
302
444
  if __name__ == "__main__":
303
445
  run_aggregate_referee_stats()