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.
- hockey_blast_common_lib/aggregate_all_stats.py +7 -4
- hockey_blast_common_lib/aggregate_goalie_stats.py +303 -113
- hockey_blast_common_lib/aggregate_h2h_stats.py +64 -33
- hockey_blast_common_lib/aggregate_human_stats.py +566 -281
- hockey_blast_common_lib/aggregate_referee_stats.py +287 -145
- hockey_blast_common_lib/aggregate_s2s_stats.py +85 -25
- hockey_blast_common_lib/aggregate_scorekeeper_stats.py +231 -119
- hockey_blast_common_lib/aggregate_skater_stats.py +595 -240
- hockey_blast_common_lib/assign_skater_skill.py +21 -11
- hockey_blast_common_lib/db_connection.py +59 -8
- hockey_blast_common_lib/embedding_utils.py +309 -0
- hockey_blast_common_lib/h2h_models.py +150 -56
- hockey_blast_common_lib/hockey_blast_sample_backup.sql.gz +0 -0
- hockey_blast_common_lib/models.py +305 -149
- hockey_blast_common_lib/options.py +30 -15
- hockey_blast_common_lib/progress_utils.py +21 -13
- hockey_blast_common_lib/skills_in_divisions.py +170 -33
- hockey_blast_common_lib/skills_propagation.py +164 -70
- hockey_blast_common_lib/stats_models.py +489 -245
- hockey_blast_common_lib/stats_utils.py +6 -3
- hockey_blast_common_lib/utils.py +89 -25
- hockey_blast_common_lib/wsgi.py +7 -5
- {hockey_blast_common_lib-0.1.62.dist-info → hockey_blast_common_lib-0.1.64.dist-info}/METADATA +1 -1
- hockey_blast_common_lib-0.1.64.dist-info/RECORD +29 -0
- hockey_blast_common_lib-0.1.62.dist-info/RECORD +0 -28
- {hockey_blast_common_lib-0.1.62.dist-info → hockey_blast_common_lib-0.1.64.dist-info}/WHEEL +0 -0
- {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
|
|
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
|
-
|
|
8
|
+
|
|
8
9
|
import sqlalchemy
|
|
9
|
-
from
|
|
10
|
-
|
|
10
|
+
from sqlalchemy.sql import case, func
|
|
11
|
+
|
|
11
12
|
from hockey_blast_common_lib.db_connection import create_session
|
|
12
|
-
from
|
|
13
|
-
from hockey_blast_common_lib.options import
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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 ==
|
|
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 =
|
|
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(
|
|
37
|
-
|
|
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 ==
|
|
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 ==
|
|
45
|
-
if aggregation_window ==
|
|
71
|
+
elif aggregation_type == "division":
|
|
72
|
+
if aggregation_window == "Daily":
|
|
46
73
|
StatsModel = DivisionStatsDailyReferee
|
|
47
|
-
elif aggregation_window ==
|
|
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 ==
|
|
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(
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
(Game.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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 =
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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][
|
|
140
|
-
stats_dict[key][
|
|
141
|
-
stats_dict[key][
|
|
142
|
-
stats_dict[key][
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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][
|
|
162
|
-
stats_dict[key][
|
|
163
|
-
stats_dict[key][
|
|
164
|
-
stats_dict[key][
|
|
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 = {
|
|
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][
|
|
174
|
-
stats_dict[key][
|
|
175
|
-
stats_dict[key][
|
|
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][
|
|
181
|
-
stats_dict[key][
|
|
182
|
-
stats_dict[key][
|
|
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[
|
|
187
|
-
stat[
|
|
188
|
-
|
|
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[
|
|
255
|
+
all_game_ids = stat["game_ids"]
|
|
196
256
|
if all_game_ids:
|
|
197
|
-
first_game =
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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,
|
|
207
|
-
assign_ranks(stats_dict,
|
|
208
|
-
assign_ranks(stats_dict,
|
|
209
|
-
assign_ranks(stats_dict,
|
|
210
|
-
assign_ranks(stats_dict,
|
|
211
|
-
assign_ranks(stats_dict,
|
|
212
|
-
assign_ranks(stats_dict,
|
|
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[
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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[
|
|
238
|
-
last_game_id=stat[
|
|
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 =
|
|
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(
|
|
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(
|
|
263
|
-
|
|
264
|
-
|
|
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(
|
|
270
|
-
|
|
271
|
-
|
|
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(
|
|
276
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
284
|
-
|
|
285
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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()
|