hockey-blast-common-lib 0.1.32__tar.gz → 0.1.33__tar.gz
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-0.1.32 → hockey_blast_common_lib-0.1.33}/PKG-INFO +1 -1
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/aggregate_goalie_stats.py +89 -34
- hockey_blast_common_lib-0.1.33/hockey_blast_common_lib/aggregate_human_stats.py +454 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/aggregate_referee_stats.py +55 -48
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/skills_in_divisions.py +1 -1
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/stats_models.py +53 -2
- hockey_blast_common_lib-0.1.33/hockey_blast_common_lib/stats_utils.py +4 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib.egg-info/PKG-INFO +1 -1
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib.egg-info/SOURCES.txt +1 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/setup.py +1 -1
- hockey_blast_common_lib-0.1.32/hockey_blast_common_lib/aggregate_human_stats.py +0 -295
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/MANIFEST.in +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/README.md +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/__init__.py +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/aggregate_skater_stats.py +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/assign_skater_skill.py +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/db_connection.py +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/dump_sample_db.sh +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/hockey_blast_sample_backup.sql.gz +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/models.py +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/options.py +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/restore_sample_db.sh +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/skills_propagation.py +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/utils.py +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib/wsgi.py +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib.egg-info/dependency_links.txt +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib.egg-info/requires.txt +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/hockey_blast_common_lib.egg-info/top_level.txt +0 -0
- {hockey_blast_common_lib-0.1.32 → hockey_blast_common_lib-0.1.33}/setup.cfg +0 -0
@@ -5,16 +5,31 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
5
5
|
|
6
6
|
from datetime import datetime, timedelta
|
7
7
|
import sqlalchemy
|
8
|
-
|
9
|
-
from hockey_blast_common_lib.
|
8
|
+
|
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 OrgStatsGoalie, DivisionStatsGoalie, OrgStatsWeeklyGoalie, OrgStatsDailyGoalie, DivisionStatsWeeklyGoalie, DivisionStatsDailyGoalie, LevelStatsGoalie
|
10
11
|
from hockey_blast_common_lib.db_connection import create_session
|
11
12
|
from sqlalchemy.sql import func, case
|
12
|
-
from hockey_blast_common_lib.options import not_human_names, parse_args, MIN_GAMES_FOR_ORG_STATS, MIN_GAMES_FOR_DIVISION_STATS
|
13
|
+
from hockey_blast_common_lib.options import not_human_names, parse_args, MIN_GAMES_FOR_ORG_STATS, MIN_GAMES_FOR_DIVISION_STATS, MIN_GAMES_FOR_LEVEL_STATS
|
13
14
|
from hockey_blast_common_lib.utils import get_org_id_from_alias, get_human_ids_by_names, get_division_ids_for_last_season_in_all_leagues, get_all_division_ids_for_org
|
15
|
+
from hockey_blast_common_lib.stats_utils import assign_ranks
|
16
|
+
from sqlalchemy import func, case, and_
|
17
|
+
from collections import defaultdict
|
14
18
|
|
15
|
-
def aggregate_goalie_stats(session, aggregation_type, aggregation_id, names_to_filter_out, aggregation_window=None):
|
19
|
+
def aggregate_goalie_stats(session, aggregation_type, aggregation_id, names_to_filter_out, debug_human_id=None, aggregation_window=None):
|
16
20
|
human_ids_to_filter = get_human_ids_by_names(session, names_to_filter_out)
|
17
21
|
|
22
|
+
# Get the name of the aggregation, for debug purposes
|
23
|
+
if aggregation_type == 'org':
|
24
|
+
aggregation_name = session.query(Organization).filter(Organization.id == aggregation_id).first().organization_name
|
25
|
+
print(f"Aggregating goalie stats for {aggregation_name} with window {aggregation_window}...")
|
26
|
+
elif aggregation_type == 'division':
|
27
|
+
aggregation_name = session.query(Division).filter(Division.id == aggregation_id).first().level
|
28
|
+
elif aggregation_type == 'level':
|
29
|
+
aggregation_name = session.query(Level).filter(Level.id == aggregation_id).first().level_name
|
30
|
+
else:
|
31
|
+
aggregation_name = "Unknown"
|
32
|
+
|
18
33
|
if aggregation_type == 'org':
|
19
34
|
if aggregation_window == 'Daily':
|
20
35
|
StatsModel = OrgStatsDailyGoalie
|
@@ -33,6 +48,14 @@ def aggregate_goalie_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
33
48
|
StatsModel = DivisionStatsGoalie
|
34
49
|
min_games = MIN_GAMES_FOR_DIVISION_STATS
|
35
50
|
filter_condition = Game.division_id == aggregation_id
|
51
|
+
elif aggregation_type == 'level':
|
52
|
+
StatsModel = LevelStatsGoalie
|
53
|
+
min_games = MIN_GAMES_FOR_LEVEL_STATS
|
54
|
+
filter_condition = Division.level_id == aggregation_id
|
55
|
+
# Add filter to only include games for the last 5 years
|
56
|
+
five_years_ago = datetime.now() - timedelta(days=5*365)
|
57
|
+
level_window_filter = func.cast(func.concat(Game.date, ' ', Game.time), sqlalchemy.types.TIMESTAMP) >= five_years_ago
|
58
|
+
filter_condition = filter_condition & level_window_filter
|
36
59
|
else:
|
37
60
|
raise ValueError("Invalid aggregation type")
|
38
61
|
|
@@ -55,6 +78,11 @@ def aggregate_goalie_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
55
78
|
session.query(StatsModel).filter(StatsModel.aggregation_id == aggregation_id).delete()
|
56
79
|
session.commit()
|
57
80
|
|
81
|
+
# Filter for specific human_id if provided
|
82
|
+
human_filter = []
|
83
|
+
# if debug_human_id:
|
84
|
+
# human_filter = [GameRoster.human_id == debug_human_id]
|
85
|
+
|
58
86
|
# Aggregate games played, goals allowed, and shots faced for each goalie
|
59
87
|
goalie_stats = session.query(
|
60
88
|
GameRoster.human_id,
|
@@ -62,7 +90,7 @@ def aggregate_goalie_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
62
90
|
func.sum(case((GameRoster.team_id == Game.home_team_id, Game.visitor_final_score), else_=Game.home_final_score)).label('goals_allowed'),
|
63
91
|
func.sum(case((GameRoster.team_id == Game.home_team_id, Game.visitor_period_1_shots + Game.visitor_period_2_shots + Game.visitor_period_3_shots + Game.visitor_ot_shots + Game.visitor_so_shots), else_=Game.home_period_1_shots + Game.home_period_2_shots + Game.home_period_3_shots + Game.home_ot_shots + Game.home_so_shots)).label('shots_faced'),
|
64
92
|
func.array_agg(Game.id).label('game_ids')
|
65
|
-
).join(Game, GameRoster.game_id == Game.id).filter(filter_condition, GameRoster.role
|
93
|
+
).join(Game, GameRoster.game_id == Game.id).join(Division, Game.division_id == Division.id).filter(filter_condition, GameRoster.role.ilike('g')).group_by(GameRoster.human_id).all()
|
66
94
|
|
67
95
|
# Combine the results
|
68
96
|
stats_dict = {}
|
@@ -70,6 +98,8 @@ def aggregate_goalie_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
70
98
|
if stat.human_id in human_ids_to_filter:
|
71
99
|
continue
|
72
100
|
key = (aggregation_id, stat.human_id)
|
101
|
+
if stat.games_played < min_games:
|
102
|
+
continue
|
73
103
|
stats_dict[key] = {
|
74
104
|
'games_played': stat.games_played,
|
75
105
|
'goals_allowed': stat.goals_allowed if stat.goals_allowed is not None else 0,
|
@@ -102,37 +132,43 @@ def aggregate_goalie_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
102
132
|
# Calculate total_in_rank
|
103
133
|
total_in_rank = len(stats_dict)
|
104
134
|
|
105
|
-
# Assign ranks
|
106
|
-
def assign_ranks(stats_dict, field):
|
107
|
-
sorted_stats = sorted(stats_dict.items(), key=lambda x: x[1][field], reverse=True)
|
108
|
-
for rank, (key, stat) in enumerate(sorted_stats, start=1):
|
109
|
-
stats_dict[key][f'{field}_rank'] = rank
|
110
|
-
|
135
|
+
# Assign ranks within each level
|
111
136
|
assign_ranks(stats_dict, 'games_played')
|
112
|
-
assign_ranks(stats_dict, 'goals_allowed')
|
113
|
-
assign_ranks(stats_dict, 'goals_allowed_per_game')
|
137
|
+
assign_ranks(stats_dict, 'goals_allowed', reverse_rank=True)
|
114
138
|
assign_ranks(stats_dict, 'shots_faced')
|
139
|
+
assign_ranks(stats_dict, 'goals_allowed_per_game', reverse_rank=True)
|
115
140
|
assign_ranks(stats_dict, 'save_percentage')
|
116
141
|
|
142
|
+
# Debug output for specific human
|
143
|
+
if debug_human_id:
|
144
|
+
if any(key[1] == debug_human_id for key in stats_dict):
|
145
|
+
human = session.query(Human).filter(Human.id == debug_human_id).first()
|
146
|
+
human_name = f"{human.first_name} {human.last_name}" if human else "Unknown"
|
147
|
+
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}:")
|
148
|
+
for key, stat in stats_dict.items():
|
149
|
+
if key[1] == debug_human_id:
|
150
|
+
for k, v in stat.items():
|
151
|
+
print(f"{k}: {v}")
|
152
|
+
|
117
153
|
# Insert aggregated stats into the appropriate table with progress output
|
118
154
|
total_items = len(stats_dict)
|
119
155
|
batch_size = 1000
|
120
156
|
for i, (key, stat) in enumerate(stats_dict.items(), 1):
|
121
157
|
aggregation_id, human_id = key
|
122
|
-
if stat['games_played']
|
123
|
-
|
158
|
+
goals_allowed_per_game = stat['goals_allowed'] / stat['games_played'] if stat['games_played'] > 0 else 0.0
|
159
|
+
save_percentage = (stat['shots_faced'] - stat['goals_allowed']) / stat['shots_faced'] if stat['shots_faced'] > 0 else 0.0
|
124
160
|
goalie_stat = StatsModel(
|
125
161
|
aggregation_id=aggregation_id,
|
126
162
|
human_id=human_id,
|
127
163
|
games_played=stat['games_played'],
|
128
164
|
goals_allowed=stat['goals_allowed'],
|
129
|
-
goals_allowed_per_game=stat['goals_allowed_per_game'],
|
130
165
|
shots_faced=stat['shots_faced'],
|
131
|
-
|
166
|
+
goals_allowed_per_game=goals_allowed_per_game,
|
167
|
+
save_percentage=save_percentage,
|
132
168
|
games_played_rank=stat['games_played_rank'],
|
133
169
|
goals_allowed_rank=stat['goals_allowed_rank'],
|
134
|
-
goals_allowed_per_game_rank=stat['goals_allowed_per_game_rank'],
|
135
170
|
shots_faced_rank=stat['shots_faced_rank'],
|
171
|
+
goals_allowed_per_game_rank=stat['goals_allowed_per_game_rank'],
|
136
172
|
save_percentage_rank=stat['save_percentage_rank'],
|
137
173
|
total_in_rank=total_in_rank,
|
138
174
|
first_game_id=stat['first_game_id'],
|
@@ -142,23 +178,42 @@ def aggregate_goalie_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
142
178
|
# Commit in batches
|
143
179
|
if i % batch_size == 0:
|
144
180
|
session.commit()
|
145
|
-
print(f"\r{i}/{total_items} ({(i/total_items)*100:.2f}%)", end="")
|
146
181
|
session.commit()
|
147
|
-
print(f"\r{total_items}/{total_items} (100.00%)")
|
148
|
-
print("\nDone.")
|
149
182
|
|
150
|
-
# Example usage
|
151
183
|
if __name__ == "__main__":
|
152
|
-
args = parse_args()
|
153
|
-
org_alias = args.org
|
154
184
|
session = create_session("boss")
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
185
|
+
human_id_to_debug = None
|
186
|
+
|
187
|
+
# Get all org_id present in the Organization table
|
188
|
+
org_ids = session.query(Organization.id).all()
|
189
|
+
org_ids = [org_id[0] for org_id in org_ids]
|
190
|
+
|
191
|
+
for org_id in org_ids:
|
192
|
+
division_ids = get_all_division_ids_for_org(session, org_id)
|
193
|
+
print(f"Aggregating goalie stats for {len(division_ids)} divisions in org_id {org_id}...")
|
194
|
+
total_divisions = len(division_ids)
|
195
|
+
processed_divisions = 0
|
196
|
+
for division_id in division_ids:
|
197
|
+
aggregate_goalie_stats(session, aggregation_type='division', aggregation_id=division_id, names_to_filter_out=not_human_names, debug_human_id=human_id_to_debug)
|
198
|
+
aggregate_goalie_stats(session, aggregation_type='division', aggregation_id=division_id, names_to_filter_out=not_human_names, debug_human_id=human_id_to_debug, aggregation_window='Weekly')
|
199
|
+
aggregate_goalie_stats(session, aggregation_type='division', aggregation_id=division_id, names_to_filter_out=not_human_names, debug_human_id=human_id_to_debug, aggregation_window='Daily')
|
200
|
+
processed_divisions += 1
|
201
|
+
if human_id_to_debug is None:
|
202
|
+
print(f"\rProcessed {processed_divisions}/{total_divisions} divisions ({(processed_divisions/total_divisions)*100:.2f}%)", end="")
|
203
|
+
|
204
|
+
aggregate_goalie_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, debug_human_id=human_id_to_debug)
|
205
|
+
aggregate_goalie_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, debug_human_id=human_id_to_debug, aggregation_window='Weekly')
|
206
|
+
aggregate_goalie_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, debug_human_id=human_id_to_debug, aggregation_window='Daily')
|
207
|
+
|
208
|
+
# Aggregate by level
|
209
|
+
level_ids = session.query(Division.level_id).distinct().all()
|
210
|
+
level_ids = [level_id[0] for level_id in level_ids]
|
211
|
+
total_levels = len(level_ids)
|
212
|
+
processed_levels = 0
|
213
|
+
for level_id in level_ids:
|
214
|
+
if level_id is None:
|
215
|
+
continue
|
216
|
+
if human_id_to_debug is None:
|
217
|
+
print(f"\rProcessed {processed_levels}/{total_levels} levels ({(processed_levels/total_levels)*100:.2f}%)", end="")
|
218
|
+
processed_levels += 1
|
219
|
+
aggregate_goalie_stats(session, aggregation_type='level', aggregation_id=level_id, names_to_filter_out=not_human_names, debug_human_id=human_id_to_debug)
|
@@ -0,0 +1,454 @@
|
|
1
|
+
import sys, os
|
2
|
+
|
3
|
+
# Add the package directory to the Python path
|
4
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
5
|
+
|
6
|
+
|
7
|
+
from datetime import datetime, timedelta
|
8
|
+
import sqlalchemy
|
9
|
+
from hockey_blast_common_lib.models import Game, GameRoster, Organization, Division
|
10
|
+
from hockey_blast_common_lib.stats_models import OrgStatsHuman, DivisionStatsHuman, OrgStatsDailyHuman, OrgStatsWeeklyHuman, DivisionStatsDailyHuman, DivisionStatsWeeklyHuman, LevelStatsHuman
|
11
|
+
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, not_human_names
|
14
|
+
from hockey_blast_common_lib.utils import get_fake_human_for_stats, get_org_id_from_alias, get_human_ids_by_names, get_division_ids_for_last_season_in_all_leagues, get_all_division_ids_for_org
|
15
|
+
from hockey_blast_common_lib.stats_utils import assign_ranks
|
16
|
+
|
17
|
+
def aggregate_human_stats(session, aggregation_type, aggregation_id, names_to_filter_out, human_id_filter=None, aggregation_window=None):
|
18
|
+
human_ids_to_filter = get_human_ids_by_names(session, names_to_filter_out)
|
19
|
+
|
20
|
+
if aggregation_type == 'org':
|
21
|
+
aggregation_name = session.query(Organization).filter(Organization.id == aggregation_id).first().organization_name
|
22
|
+
print(f"Aggregating goalie stats for {aggregation_name} with window {aggregation_window}...")
|
23
|
+
if aggregation_window == 'Daily':
|
24
|
+
StatsModel = OrgStatsDailyHuman
|
25
|
+
elif aggregation_window == 'Weekly':
|
26
|
+
StatsModel = OrgStatsWeeklyHuman
|
27
|
+
else:
|
28
|
+
StatsModel = OrgStatsHuman
|
29
|
+
min_games = MIN_GAMES_FOR_ORG_STATS
|
30
|
+
filter_condition = Game.org_id == aggregation_id
|
31
|
+
elif aggregation_type == 'division':
|
32
|
+
if aggregation_window == 'Daily':
|
33
|
+
StatsModel = DivisionStatsDailyHuman
|
34
|
+
elif aggregation_window == 'Weekly':
|
35
|
+
StatsModel = DivisionStatsWeeklyHuman
|
36
|
+
else:
|
37
|
+
StatsModel = DivisionStatsHuman
|
38
|
+
min_games = MIN_GAMES_FOR_DIVISION_STATS
|
39
|
+
filter_condition = Game.division_id == aggregation_id
|
40
|
+
elif aggregation_type == 'level':
|
41
|
+
StatsModel = LevelStatsHuman
|
42
|
+
min_games = MIN_GAMES_FOR_LEVEL_STATS
|
43
|
+
filter_condition = Division.level_id == aggregation_id
|
44
|
+
# Add filter to only include games for the last 5 years
|
45
|
+
five_years_ago = datetime.now() - timedelta(days=5*365)
|
46
|
+
level_window_filter = func.cast(func.concat(Game.date, ' ', Game.time), sqlalchemy.types.TIMESTAMP) >= five_years_ago
|
47
|
+
filter_condition = filter_condition & level_window_filter
|
48
|
+
else:
|
49
|
+
raise ValueError("Invalid aggregation type")
|
50
|
+
|
51
|
+
# Apply aggregation window filter
|
52
|
+
if aggregation_window:
|
53
|
+
last_game_datetime = session.query(func.max(func.concat(Game.date, ' ', Game.time))).filter(filter_condition, Game.status.like('Final%')).scalar()
|
54
|
+
if last_game_datetime:
|
55
|
+
last_game_datetime = datetime.strptime(last_game_datetime, '%Y-%m-%d %H:%M:%S')
|
56
|
+
if aggregation_window == 'Daily':
|
57
|
+
start_datetime = last_game_datetime - timedelta(days=1)
|
58
|
+
elif aggregation_window == 'Weekly':
|
59
|
+
start_datetime = last_game_datetime - timedelta(weeks=1)
|
60
|
+
else:
|
61
|
+
start_datetime = None
|
62
|
+
if start_datetime:
|
63
|
+
game_window_filter = func.cast(func.concat(Game.date, ' ', Game.time), sqlalchemy.types.TIMESTAMP).between(start_datetime, last_game_datetime)
|
64
|
+
filter_condition = filter_condition & game_window_filter
|
65
|
+
|
66
|
+
# Delete existing items from the stats table
|
67
|
+
session.query(StatsModel).filter(StatsModel.aggregation_id == aggregation_id).delete()
|
68
|
+
session.commit()
|
69
|
+
|
70
|
+
# Filter for specific human_id if provided
|
71
|
+
human_filter = []
|
72
|
+
if human_id_filter:
|
73
|
+
human_filter = [GameRoster.human_id == human_id_filter]
|
74
|
+
|
75
|
+
# Filter games by status
|
76
|
+
game_status_filter = Game.status.like('Final%')
|
77
|
+
|
78
|
+
# Aggregate skater games played
|
79
|
+
skater_stats = session.query(
|
80
|
+
GameRoster.human_id,
|
81
|
+
func.count(func.distinct(Game.id)).label('games_skater'),
|
82
|
+
func.array_agg(func.distinct(Game.id)).label('skater_game_ids')
|
83
|
+
).join(Game, GameRoster.game_id == Game.id).join(Division, Game.division_id == Division.id).filter(filter_condition, game_status_filter, ~GameRoster.role.ilike('G'), *human_filter).group_by(GameRoster.human_id).all()
|
84
|
+
|
85
|
+
# Aggregate goalie games played
|
86
|
+
goalie_stats = session.query(
|
87
|
+
GameRoster.human_id,
|
88
|
+
func.count(func.distinct(Game.id)).label('games_goalie'),
|
89
|
+
func.array_agg(func.distinct(Game.id)).label('goalie_game_ids')
|
90
|
+
).join(Game, GameRoster.game_id == Game.id).join(Division, Game.division_id == Division.id).filter(filter_condition, game_status_filter, GameRoster.role.ilike('G'), *human_filter).group_by(GameRoster.human_id).all()
|
91
|
+
|
92
|
+
# Aggregate referee and scorekeeper games from Game table
|
93
|
+
referee_stats = session.query(
|
94
|
+
Game.referee_1_id.label('human_id'),
|
95
|
+
func.count(func.distinct(Game.id)).label('games_referee'),
|
96
|
+
func.array_agg(func.distinct(Game.id)).label('referee_game_ids')
|
97
|
+
).join(Division, Game.division_id == Division.id).filter(filter_condition, game_status_filter, *human_filter).group_by(Game.referee_1_id).all()
|
98
|
+
|
99
|
+
referee_stats_2 = session.query(
|
100
|
+
Game.referee_2_id.label('human_id'),
|
101
|
+
func.count(func.distinct(Game.id)).label('games_referee'),
|
102
|
+
func.array_agg(func.distinct(Game.id)).label('referee_game_ids')
|
103
|
+
).join(Division, Game.division_id == Division.id).filter(filter_condition, game_status_filter, *human_filter).group_by(Game.referee_2_id).all()
|
104
|
+
|
105
|
+
scorekeeper_stats = session.query(
|
106
|
+
Game.scorekeeper_id.label('human_id'),
|
107
|
+
func.count(func.distinct(Game.id)).label('games_scorekeeper'),
|
108
|
+
func.array_agg(func.distinct(Game.id)).label('scorekeeper_game_ids')
|
109
|
+
).join(Division, Game.division_id == Division.id).filter(filter_condition, game_status_filter, *human_filter).group_by(Game.scorekeeper_id).all()
|
110
|
+
|
111
|
+
# Combine the results
|
112
|
+
stats_dict = {}
|
113
|
+
for stat in skater_stats:
|
114
|
+
if stat.human_id in human_ids_to_filter:
|
115
|
+
continue
|
116
|
+
key = (aggregation_id, stat.human_id)
|
117
|
+
stats_dict[key] = {
|
118
|
+
'games_total': stat.games_skater,
|
119
|
+
'games_skater': stat.games_skater,
|
120
|
+
'games_goalie': 0,
|
121
|
+
'games_referee': 0,
|
122
|
+
'games_scorekeeper': 0,
|
123
|
+
'skater_game_ids': stat.skater_game_ids,
|
124
|
+
'goalie_game_ids': [],
|
125
|
+
'referee_game_ids': [],
|
126
|
+
'scorekeeper_game_ids': [],
|
127
|
+
'first_game_id_skater': None,
|
128
|
+
'last_game_id_skater': None,
|
129
|
+
'first_game_id_goalie': None,
|
130
|
+
'last_game_id_goalie': None,
|
131
|
+
'first_game_id_referee': None,
|
132
|
+
'last_game_id_referee': None,
|
133
|
+
'first_game_id_scorekeeper': None,
|
134
|
+
'last_game_id_scorekeeper': None
|
135
|
+
}
|
136
|
+
|
137
|
+
for stat in goalie_stats:
|
138
|
+
if stat.human_id in human_ids_to_filter:
|
139
|
+
continue
|
140
|
+
key = (aggregation_id, stat.human_id)
|
141
|
+
if key not in stats_dict:
|
142
|
+
stats_dict[key] = {
|
143
|
+
'games_total': stat.games_goalie,
|
144
|
+
'games_skater': 0,
|
145
|
+
'games_goalie': stat.games_goalie,
|
146
|
+
'games_referee': 0,
|
147
|
+
'games_scorekeeper': 0,
|
148
|
+
'skater_game_ids': [],
|
149
|
+
'goalie_game_ids': stat.goalie_game_ids,
|
150
|
+
'referee_game_ids': [],
|
151
|
+
'scorekeeper_game_ids': [],
|
152
|
+
'first_game_id_skater': None,
|
153
|
+
'last_game_id_skater': None,
|
154
|
+
'first_game_id_goalie': None,
|
155
|
+
'last_game_id_goalie': None,
|
156
|
+
'first_game_id_referee': None,
|
157
|
+
'last_game_id_referee': None,
|
158
|
+
'first_game_id_scorekeeper': None,
|
159
|
+
'last_game_id_scorekeeper': None
|
160
|
+
}
|
161
|
+
else:
|
162
|
+
stats_dict[key]['games_goalie'] += stat.games_goalie
|
163
|
+
stats_dict[key]['games_total'] += stat.games_goalie
|
164
|
+
stats_dict[key]['goalie_game_ids'] += stat.goalie_game_ids
|
165
|
+
|
166
|
+
for stat in referee_stats:
|
167
|
+
if stat.human_id in human_ids_to_filter:
|
168
|
+
continue
|
169
|
+
key = (aggregation_id, stat.human_id)
|
170
|
+
if key not in stats_dict:
|
171
|
+
stats_dict[key] = {
|
172
|
+
'games_total': stat.games_referee,
|
173
|
+
'games_skater': 0,
|
174
|
+
'games_goalie': 0,
|
175
|
+
'games_referee': stat.games_referee,
|
176
|
+
'games_scorekeeper': 0,
|
177
|
+
'skater_game_ids': [],
|
178
|
+
'goalie_game_ids': [],
|
179
|
+
'referee_game_ids': stat.referee_game_ids,
|
180
|
+
'scorekeeper_game_ids': [],
|
181
|
+
'first_game_id_skater': None,
|
182
|
+
'last_game_id_skater': None,
|
183
|
+
'first_game_id_goalie': None,
|
184
|
+
'last_game_id_goalie': None,
|
185
|
+
'first_game_id_referee': None,
|
186
|
+
'last_game_id_referee': None,
|
187
|
+
'first_game_id_scorekeeper': None,
|
188
|
+
'last_game_id_scorekeeper': None
|
189
|
+
}
|
190
|
+
else:
|
191
|
+
stats_dict[key]['games_referee'] += stat.games_referee
|
192
|
+
stats_dict[key]['games_total'] += stat.games_referee
|
193
|
+
stats_dict[key]['referee_game_ids'] += stat.referee_game_ids
|
194
|
+
|
195
|
+
for stat in referee_stats_2:
|
196
|
+
if stat.human_id in human_ids_to_filter:
|
197
|
+
continue
|
198
|
+
key = (aggregation_id, stat.human_id)
|
199
|
+
if key not in stats_dict:
|
200
|
+
stats_dict[key] = {
|
201
|
+
'games_total': stat.games_referee,
|
202
|
+
'games_skater': 0,
|
203
|
+
'games_goalie': 0,
|
204
|
+
'games_referee': stat.games_referee,
|
205
|
+
'games_scorekeeper': 0,
|
206
|
+
'skater_game_ids': [],
|
207
|
+
'goalie_game_ids': [],
|
208
|
+
'referee_game_ids': stat.referee_game_ids,
|
209
|
+
'scorekeeper_game_ids': [],
|
210
|
+
'first_game_id_skater': None,
|
211
|
+
'last_game_id_skater': None,
|
212
|
+
'first_game_id_goalie': None,
|
213
|
+
'last_game_id_goalie': None,
|
214
|
+
'first_game_id_referee': None,
|
215
|
+
'last_game_id_referee': None,
|
216
|
+
'first_game_id_scorekeeper': None,
|
217
|
+
'last_game_id_scorekeeper': None
|
218
|
+
}
|
219
|
+
else:
|
220
|
+
stats_dict[key]['games_referee'] += stat.games_referee
|
221
|
+
stats_dict[key]['games_total'] += stat.games_referee
|
222
|
+
stats_dict[key]['referee_game_ids'] += stat.referee_game_ids
|
223
|
+
|
224
|
+
for stat in scorekeeper_stats:
|
225
|
+
if stat.human_id in human_ids_to_filter:
|
226
|
+
continue
|
227
|
+
key = (aggregation_id, stat.human_id)
|
228
|
+
if key not in stats_dict:
|
229
|
+
stats_dict[key] = {
|
230
|
+
'games_total': stat.games_scorekeeper,
|
231
|
+
'games_skater': 0,
|
232
|
+
'games_goalie': 0,
|
233
|
+
'games_referee': 0,
|
234
|
+
'games_scorekeeper': stat.games_scorekeeper,
|
235
|
+
'skater_game_ids': [],
|
236
|
+
'goalie_game_ids': [],
|
237
|
+
'referee_game_ids': [],
|
238
|
+
'scorekeeper_game_ids': stat.scorekeeper_game_ids,
|
239
|
+
'first_game_id_skater': None,
|
240
|
+
'last_game_id_skater': None,
|
241
|
+
'first_game_id_goalie': None,
|
242
|
+
'last_game_id_goalie': None,
|
243
|
+
'first_game_id_referee': None,
|
244
|
+
'last_game_id_referee': None,
|
245
|
+
'first_game_id_scorekeeper': None,
|
246
|
+
'last_game_id_scorekeeper': None
|
247
|
+
}
|
248
|
+
else:
|
249
|
+
stats_dict[key]['games_scorekeeper'] += stat.games_scorekeeper
|
250
|
+
stats_dict[key]['games_total'] += stat.games_scorekeeper
|
251
|
+
stats_dict[key]['scorekeeper_game_ids'] += stat.scorekeeper_game_ids
|
252
|
+
|
253
|
+
# Ensure all keys have valid human_id values
|
254
|
+
stats_dict = {key: value for key, value in stats_dict.items() if key[1] is not None}
|
255
|
+
|
256
|
+
# Calculate total_in_rank
|
257
|
+
total_in_rank = len(stats_dict)
|
258
|
+
|
259
|
+
# Calculate number of items in rank per role
|
260
|
+
skaters_in_rank = len([stat for stat in stats_dict.values() if stat['games_skater'] > 0])
|
261
|
+
goalies_in_rank = len([stat for stat in stats_dict.values() if stat['games_goalie'] > 0])
|
262
|
+
referees_in_rank = len([stat for stat in stats_dict.values() if stat['games_referee'] > 0])
|
263
|
+
scorekeepers_in_rank = len([stat for stat in stats_dict.values() if stat['games_scorekeeper'] > 0])
|
264
|
+
|
265
|
+
# Filter out humans with less than min_games
|
266
|
+
stats_dict = {key: value for key, value in stats_dict.items() if value['games_total'] >= min_games}
|
267
|
+
|
268
|
+
# Assign ranks
|
269
|
+
assign_ranks(stats_dict, 'games_total')
|
270
|
+
assign_ranks(stats_dict, 'games_skater')
|
271
|
+
assign_ranks(stats_dict, 'games_goalie')
|
272
|
+
assign_ranks(stats_dict, 'games_referee')
|
273
|
+
assign_ranks(stats_dict, 'games_scorekeeper')
|
274
|
+
|
275
|
+
# Populate first_game_id and last_game_id for each role
|
276
|
+
for key, stat in stats_dict.items():
|
277
|
+
all_game_ids = stat['skater_game_ids'] + stat['goalie_game_ids'] + stat['referee_game_ids'] + stat['scorekeeper_game_ids']
|
278
|
+
if all_game_ids:
|
279
|
+
first_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date, Game.time).first()
|
280
|
+
last_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date.desc(), Game.time.desc()).first()
|
281
|
+
stat['first_game_id'] = first_game.id if first_game else None
|
282
|
+
stat['last_game_id'] = last_game.id if last_game else None
|
283
|
+
|
284
|
+
if stat['skater_game_ids']:
|
285
|
+
first_game_skater = session.query(Game).filter(Game.id.in_(stat['skater_game_ids'])).order_by(Game.date, Game.time).first()
|
286
|
+
last_game_skater = session.query(Game).filter(Game.id.in_(stat['skater_game_ids'])).order_by(Game.date.desc(), Game.time.desc()).first()
|
287
|
+
stat['first_game_id_skater'] = first_game_skater.id if first_game_skater else None
|
288
|
+
stat['last_game_id_skater'] = last_game_skater.id if last_game_skater else None
|
289
|
+
|
290
|
+
if stat['goalie_game_ids']:
|
291
|
+
first_game_goalie = session.query(Game).filter(Game.id.in_(stat['goalie_game_ids'])).order_by(Game.date, Game.time).first()
|
292
|
+
last_game_goalie = session.query(Game).filter(Game.id.in_(stat['goalie_game_ids'])).order_by(Game.date.desc(), Game.time.desc()).first()
|
293
|
+
stat['first_game_id_goalie'] = first_game_goalie.id if first_game_goalie else None
|
294
|
+
stat['last_game_id_goalie'] = last_game_goalie.id if last_game_goalie else None
|
295
|
+
|
296
|
+
if stat['referee_game_ids']:
|
297
|
+
first_game_referee = session.query(Game).filter(Game.id.in_(stat['referee_game_ids'])).order_by(Game.date, Game.time).first()
|
298
|
+
last_game_referee = session.query(Game).filter(Game.id.in_(stat['referee_game_ids'])).order_by(Game.date.desc(), Game.time.desc()).first()
|
299
|
+
stat['first_game_id_referee'] = first_game_referee.id if first_game_referee else None
|
300
|
+
stat['last_game_id_referee'] = last_game_referee.id if last_game_referee else None
|
301
|
+
|
302
|
+
if stat['scorekeeper_game_ids']:
|
303
|
+
first_game_scorekeeper = session.query(Game).filter(Game.id.in_(stat['scorekeeper_game_ids'])).order_by(Game.date, Game.time).first()
|
304
|
+
last_game_scorekeeper = session.query(Game).filter(Game.id.in_(stat['scorekeeper_game_ids'])).order_by(Game.date.desc(), Game.time.desc()).first()
|
305
|
+
stat['first_game_id_scorekeeper'] = first_game_scorekeeper.id if first_game_scorekeeper else None
|
306
|
+
stat['last_game_id_scorekeeper'] = last_game_scorekeeper.id if last_game_scorekeeper else None
|
307
|
+
|
308
|
+
# Insert aggregated stats into the appropriate table with progress output
|
309
|
+
batch_size = 1000
|
310
|
+
for i, (key, stat) in enumerate(stats_dict.items(), 1):
|
311
|
+
aggregation_id, human_id = key
|
312
|
+
if human_id_filter and human_id != human_id_filter:
|
313
|
+
continue
|
314
|
+
|
315
|
+
human_stat = StatsModel(
|
316
|
+
aggregation_id=aggregation_id,
|
317
|
+
human_id=human_id,
|
318
|
+
games_total=stat['games_total'],
|
319
|
+
games_total_rank=stat['games_total_rank'],
|
320
|
+
games_skater=stat['games_skater'],
|
321
|
+
games_skater_rank=stat['games_skater_rank'],
|
322
|
+
games_goalie=stat['games_goalie'],
|
323
|
+
games_goalie_rank=stat['games_goalie_rank'],
|
324
|
+
games_referee=stat['games_referee'],
|
325
|
+
games_referee_rank=stat['games_referee_rank'],
|
326
|
+
games_scorekeeper=stat['games_scorekeeper'],
|
327
|
+
games_scorekeeper_rank=stat['games_scorekeeper_rank'],
|
328
|
+
total_in_rank=total_in_rank,
|
329
|
+
skaters_in_rank=skaters_in_rank,
|
330
|
+
goalies_in_rank=goalies_in_rank,
|
331
|
+
referees_in_rank=referees_in_rank,
|
332
|
+
scorekeepers_in_rank=scorekeepers_in_rank,
|
333
|
+
first_game_id=stat['first_game_id'],
|
334
|
+
last_game_id=stat['last_game_id'],
|
335
|
+
first_game_id_skater=stat['first_game_id_skater'],
|
336
|
+
last_game_id_skater=stat['last_game_id_skater'],
|
337
|
+
first_game_id_goalie=stat['first_game_id_goalie'],
|
338
|
+
last_game_id_goalie=stat['last_game_id_goalie'],
|
339
|
+
first_game_id_referee=stat['first_game_id_referee'],
|
340
|
+
last_game_id_referee=stat['last_game_id_referee'],
|
341
|
+
first_game_id_scorekeeper=stat['first_game_id_scorekeeper'],
|
342
|
+
last_game_id_scorekeeper=stat['last_game_id_scorekeeper']
|
343
|
+
)
|
344
|
+
session.add(human_stat)
|
345
|
+
# Commit in batches
|
346
|
+
if i % batch_size == 0:
|
347
|
+
session.commit()
|
348
|
+
session.commit()
|
349
|
+
|
350
|
+
# Fetch fake human ID for overall stats
|
351
|
+
fake_human_id = get_fake_human_for_stats(session)
|
352
|
+
|
353
|
+
# Calculate overall stats
|
354
|
+
overall_stats = {
|
355
|
+
'games_total': sum(stat['games_total'] for stat in stats_dict.values()),
|
356
|
+
'games_skater': sum(stat['games_skater'] for stat in stats_dict.values()),
|
357
|
+
'games_goalie': sum(stat['games_goalie'] for stat in stats_dict.values()),
|
358
|
+
'games_referee': sum(stat['games_referee'] for stat in stats_dict.values()),
|
359
|
+
'games_scorekeeper': sum(stat['games_scorekeeper'] for stat in stats_dict.values()),
|
360
|
+
'total_in_rank': total_in_rank,
|
361
|
+
'skaters_in_rank': skaters_in_rank,
|
362
|
+
'goalies_in_rank': goalies_in_rank,
|
363
|
+
'referees_in_rank': referees_in_rank,
|
364
|
+
'scorekeepers_in_rank': scorekeepers_in_rank,
|
365
|
+
'first_game_id': None,
|
366
|
+
'last_game_id': None,
|
367
|
+
'first_game_id_skater': None,
|
368
|
+
'last_game_id_skater': None,
|
369
|
+
'first_game_id_goalie': None,
|
370
|
+
'last_game_id_goalie': None,
|
371
|
+
'first_game_id_referee': None,
|
372
|
+
'last_game_id_referee': None,
|
373
|
+
'first_game_id_scorekeeper': None,
|
374
|
+
'last_game_id_scorekeeper': None
|
375
|
+
}
|
376
|
+
|
377
|
+
# Populate first_game_id and last_game_id for overall stats
|
378
|
+
all_game_ids = [game_id for stat in stats_dict.values() for game_id in stat['skater_game_ids'] + stat['goalie_game_ids'] + stat['referee_game_ids'] + stat['scorekeeper_game_ids']]
|
379
|
+
if all_game_ids:
|
380
|
+
first_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date, Game.time).first()
|
381
|
+
last_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date.desc(), Game.time.desc()).first()
|
382
|
+
overall_stats['first_game_id'] = first_game.id if first_game else None
|
383
|
+
overall_stats['last_game_id'] = last_game.id if last_game else None
|
384
|
+
|
385
|
+
# Insert overall stats for the fake human
|
386
|
+
overall_human_stat = StatsModel(
|
387
|
+
aggregation_id=aggregation_id,
|
388
|
+
human_id=fake_human_id,
|
389
|
+
games_total=overall_stats['games_total'],
|
390
|
+
games_total_rank=0, # Overall stats do not need a rank
|
391
|
+
games_skater=overall_stats['games_skater'],
|
392
|
+
games_skater_rank=0, # Overall stats do not need a rank
|
393
|
+
games_goalie=overall_stats['games_goalie'],
|
394
|
+
games_goalie_rank=0, # Overall stats do not need a rank
|
395
|
+
games_referee=overall_stats['games_referee'],
|
396
|
+
games_referee_rank=0, # Overall stats do not need a rank
|
397
|
+
games_scorekeeper=overall_stats['games_scorekeeper'],
|
398
|
+
games_scorekeeper_rank=0, # Overall stats do not need a rank
|
399
|
+
total_in_rank=overall_stats['total_in_rank'],
|
400
|
+
skaters_in_rank=overall_stats['skaters_in_rank'],
|
401
|
+
goalies_in_rank=overall_stats['goalies_in_rank'],
|
402
|
+
referees_in_rank=overall_stats['referees_in_rank'],
|
403
|
+
scorekeepers_in_rank=overall_stats['scorekeepers_in_rank'],
|
404
|
+
first_game_id=overall_stats['first_game_id'],
|
405
|
+
last_game_id=overall_stats['last_game_id'],
|
406
|
+
first_game_id_skater=overall_stats['first_game_id_skater'],
|
407
|
+
last_game_id_skater=overall_stats['last_game_id_skater'],
|
408
|
+
first_game_id_goalie=overall_stats['first_game_id_goalie'],
|
409
|
+
last_game_id_goalie=overall_stats['last_game_id_goalie'],
|
410
|
+
first_game_id_referee=overall_stats['first_game_id_referee'],
|
411
|
+
last_game_id_referee=overall_stats['last_game_id_referee'],
|
412
|
+
first_game_id_scorekeeper=overall_stats['first_game_id_scorekeeper'],
|
413
|
+
last_game_id_scorekeeper=overall_stats['last_game_id_scorekeeper']
|
414
|
+
)
|
415
|
+
session.add(overall_human_stat)
|
416
|
+
session.commit()
|
417
|
+
|
418
|
+
if __name__ == "__main__":
|
419
|
+
session = create_session("boss")
|
420
|
+
human_id_to_debug = None
|
421
|
+
|
422
|
+
# Get all org_id present in the Organization table
|
423
|
+
# org_ids = session.query(Organization.id).all()
|
424
|
+
# org_ids = [org_id[0] for org_id in org_ids]
|
425
|
+
|
426
|
+
# for org_id in org_ids:
|
427
|
+
# division_ids = get_all_division_ids_for_org(session, org_id)
|
428
|
+
# print(f"Aggregating human stats for {len(division_ids)} divisions in org_id {org_id}...")
|
429
|
+
# total_divisions = len(division_ids)
|
430
|
+
# processed_divisions = 0
|
431
|
+
# for division_id in division_ids:
|
432
|
+
# aggregate_human_stats(session, aggregation_type='division', aggregation_id=division_id, names_to_filter_out=not_human_names, human_id_filter=human_id_to_debug)
|
433
|
+
# aggregate_human_stats(session, aggregation_type='division', aggregation_id=division_id, names_to_filter_out=not_human_names, human_id_filter=human_id_to_debug, aggregation_window='Weekly')
|
434
|
+
# aggregate_human_stats(session, aggregation_type='division', aggregation_id=division_id, names_to_filter_out=not_human_names, human_id_filter=human_id_to_debug, aggregation_window='Daily')
|
435
|
+
# processed_divisions += 1
|
436
|
+
# if human_id_to_debug is None:
|
437
|
+
# print(f"\rProcessed {processed_divisions}/{total_divisions} divisions ({(processed_divisions/total_divisions)*100:.2f}%)", end="")
|
438
|
+
# print("")
|
439
|
+
# aggregate_human_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, human_id_filter=human_id_to_debug)
|
440
|
+
# aggregate_human_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, human_id_filter=human_id_to_debug, aggregation_window='Weekly')
|
441
|
+
# aggregate_human_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, human_id_filter=human_id_to_debug, aggregation_window='Daily')
|
442
|
+
|
443
|
+
# Aggregate by level
|
444
|
+
level_ids = session.query(Division.level_id).distinct().all()
|
445
|
+
level_ids = [level_id[0] for level_id in level_ids]
|
446
|
+
total_levels = len(level_ids)
|
447
|
+
processed_levels = 0
|
448
|
+
for level_id in level_ids:
|
449
|
+
if level_id is None:
|
450
|
+
continue
|
451
|
+
if human_id_to_debug is None:
|
452
|
+
print(f"\rProcessed {processed_levels}/{total_levels} levels ({(processed_levels/total_levels)*100:.2f}%)", end="")
|
453
|
+
processed_levels += 1
|
454
|
+
aggregate_human_stats(session, aggregation_type='level', aggregation_id=level_id, names_to_filter_out=not_human_names, human_id_filter=human_id_to_debug)
|