Skip to content

Commit 0e30d01

Browse files
committed
Switch to python 3.10. Update dependencies and tests where needed
1 parent 5f97347 commit 0e30d01

File tree

7 files changed

+107
-63
lines changed

7 files changed

+107
-63
lines changed

assets/css/app.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,8 @@ $font-size-base: 0.95rem !default;
114114

115115
.warning-container:hover .warning-popup {
116116
display: block;
117+
}
118+
119+
.badge-wing-only {
120+
font-size: 0.6rem;
117121
}

mittab/apps/tab/outround_pairing_views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,12 +374,12 @@ def has_team_scratch(judge):
374374
return any(s.team_id in scratched_team_ids for s in judge.scratches.all())
375375

376376
excluded_judges = [
377-
(j.name, j.id, float(j.rank))
377+
(j.name, j.id, float(j.rank), j.wing_only)
378378
for j in excluded_judges
379379
if not has_team_scratch(j)
380380
]
381381
included_judges = [
382-
(j.name, j.id, float(j.rank))
382+
(j.name, j.id, float(j.rank), j.wing_only)
383383
for j in included_judges
384384
if not has_team_scratch(j)
385385
]

mittab/apps/tab/pairing_views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,11 +477,11 @@ def alternative_judges(request, round_id, judge_id=None):
477477
)
478478

479479
excluded_judges = [
480-
(j.name, j.id, float(j.rank), rejudge_display_counts.get(j.id))
480+
(j.name, j.id, float(j.rank), rejudge_display_counts.get(j.id), j.wing_only)
481481
for j in excluded_judges_list
482482
]
483483
included_judges = [
484-
(j.name, j.id, float(j.rank), rejudge_display_counts.get(j.id))
484+
(j.name, j.id, float(j.rank), rejudge_display_counts.get(j.id), j.wing_only)
485485
for j in included_judges_list
486486
]
487487
included_judges = sorted(included_judges, key=lambda x: -x[2])

mittab/libs/assign_judges.py

Lines changed: 74 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -80,23 +80,30 @@ def add_judges():
8080
Round.judges.through.objects.filter(
8181
round__round_number=round_number
8282
).delete()
83-
judges = list(
83+
# Get all checked-in judges
84+
all_judges = list(
8485
Judge.objects.filter(
85-
checkin__round_number=round_number,
86-
wing_only=False
86+
checkin__round_number=round_number
8787
).prefetch_related(
8888
"judges", # poorly named relation for the round
8989
"scratches",
9090
)
9191
)
92+
93+
# Sort all_judges once before creating filtered subsets
94+
random.seed(1337)
95+
random.shuffle(all_judges)
96+
all_judges = sorted(all_judges, key=lambda j: j.rank, reverse=True)
97+
98+
chairs = [j for j in all_judges if not j.wing_only]
99+
92100
pairings = tab_logic.sorted_pairings(round_number)
93101

94102
random.seed(1337)
95103
random.shuffle(pairings)
96-
random.seed(1337)
97-
random.shuffle(judges)
98-
judges = sorted(judges, key=lambda j: j.rank, reverse=True)
99-
judge_scores = construct_judge_scores(judges, settings.mode)
104+
105+
chair_scores = construct_judge_scores(chairs, settings.mode)
106+
100107
bubble_priority = settings.round_priority == InroundRoundPriority.BUBBLE_ROUNDS
101108
if bubble_priority and round_number > 1:
102109
bubble_rounds = [p for p in pairings if is_bubble_round(p, round_number)]
@@ -116,90 +123,104 @@ def add_judges():
116123
all_teams.extend((pairing.gov_team, pairing.opp_team))
117124
rejudge_counts = {}
118125
if settings.allow_rejudges:
119-
rejudge_counts = judge_team_rejudge_counts(judges, all_teams)
126+
rejudge_counts = judge_team_rejudge_counts(chairs, all_teams)
120127

121128
graph_edges = []
122-
for judge_i, judge in enumerate(judges):
123-
judge_score = judge_scores[judge_i]
129+
for chair_i, chair in enumerate(chairs):
130+
chair_score = chair_scores[chair_i]
124131

125132
for pairing_i, pairing in enumerate(pairings):
126133
has_conflict = judge_conflict(
127-
judge,
134+
chair,
128135
pairing.gov_team,
129136
pairing.opp_team,
130137
settings.allow_rejudges,
131138
)
132139
if has_conflict:
133140
continue
134-
weight = calc_weight(judge_score, pairing_i, settings.mode)
135-
judge_counts = rejudge_counts.get(judge.id)
141+
weight = calc_weight(chair_score, pairing_i, settings.mode)
142+
judge_counts = rejudge_counts.get(chair.id)
136143
rejudge_sum = 0
137144
if judge_counts:
138145
rejudge_sum = (
139146
judge_counts.get(pairing.gov_team.id, 0)
140147
+ judge_counts.get(pairing.opp_team.id, 0)
141148
)
142149
if rejudge_sum > 0 and settings.rejudge_penalty > 0:
143-
penalty = settings.rejudge_penalty * (1 + 0.1 * judge_score)
150+
penalty = settings.rejudge_penalty * (1 + 0.1 * chair_score)
144151
weight -= penalty * rejudge_sum
145152

146-
graph_edges.append((pairing_i, num_rounds + judge_i, weight))
153+
graph_edges.append((pairing_i, num_rounds + chair_i, weight))
147154
judge_assignments = mwmatching.maxWeightMatching(graph_edges, maxcardinality=True)
148155

149156
if -1 in judge_assignments[:num_rounds] or (num_rounds > 0 and not graph_edges):
150157
if not graph_edges:
151-
raise errors.JudgeAssignmentError(
152-
"Impossible to assign judges, consider reducing your gaps if you"
153-
" are making panels, otherwise find some more judges."
154-
)
158+
# Check if we have enough judges including wing_only judges
159+
if len(all_judges) >= num_rounds:
160+
raise errors.JudgeAssignmentError(
161+
"Impossible to assign chairs to all rounds. You have enough "
162+
"checked-in judges, but some are marked as wing-only and cannot "
163+
"chair. Either check in more non-wing judges or unmark some "
164+
"wing-only judges to allow them to chair."
165+
)
166+
else:
167+
raise errors.JudgeAssignmentError(
168+
"Impossible to assign judges, consider reducing your gaps if you"
169+
" are making panels, otherwise find some more judges."
170+
)
155171
elif -1 in judge_assignments[:num_rounds]:
156172
pairing_list = judge_assignments[: len(pairings)]
157173
bad_pairing = pairings[pairing_list.index(-1)]
158-
raise errors.JudgeAssignmentError(
159-
"Could not find a judge for: %s" % str(bad_pairing)
160-
)
174+
# Check if we have enough judges including wing_only judges
175+
if len(all_judges) >= num_rounds and len(chairs) < num_rounds:
176+
raise errors.JudgeAssignmentError(
177+
"Impossible to assign chairs to all rounds. You have enough "
178+
"checked-in judges, but some are marked as wing-only and cannot "
179+
"chair. Either check in more non-wing judges or unmark some "
180+
"wing-only judges to allow them to chair."
181+
)
182+
else:
183+
raise errors.JudgeAssignmentError(
184+
"Could not find a judge for: %s" % str(bad_pairing)
185+
)
161186
else:
162187
raise errors.JudgeAssignmentError()
163188

164189
judge_round_joins, chair_by_pairing = [], [None] * num_rounds
165-
assigned_judges = set()
166-
assigned_pairs = set()
167-
for pairing_i, padded_judge_i in enumerate(judge_assignments[:num_rounds]):
168-
judge_i = padded_judge_i - num_rounds
190+
assigned_judge_objects = set() # Track actual Judge objects by ID
191+
for pairing_i, padded_chair_i in enumerate(judge_assignments[:num_rounds]):
192+
chair_i = padded_chair_i - num_rounds
169193

170194
round_obj = pairings[pairing_i]
171-
judge = judges[judge_i]
195+
chair = chairs[chair_i]
172196

173-
round_obj.chair = judge
174-
chair_by_pairing[pairing_i] = judge_i
175-
assigned_judges.add(judge_i)
176-
assigned_pairs.add((pairing_i, judge_i))
197+
round_obj.chair = chair
198+
chair_by_pairing[pairing_i] = chair_i
199+
assigned_judge_objects.add(chair.id) # Track by judge ID
177200
judge_round_joins.append(
178-
Round.judges.through(judge=judge, round=round_obj)
201+
Round.judges.through(judge=chair, round=round_obj)
179202
)
180203

181204
Round.objects.bulk_update(pairings, ["chair"])
182-
if settings.pair_wings and num_rounds and len(judges) > num_rounds:
183-
max_per_round = min(3, len(judges) // num_rounds + 1)
205+
if settings.pair_wings and num_rounds and len(all_judges) > num_rounds:
206+
max_per_round = min(3, len(all_judges) // num_rounds + 1)
184207
for _ in range(1, max_per_round):
185-
available_indices = [
186-
judge_i
187-
for judge_i in range(len(judges))
188-
if judge_i not in assigned_judges
189-
]
190-
if not available_indices:
208+
# Build wing pool from all_judges excluding already assigned
209+
wing_judges = [j for j in all_judges if j.id not in assigned_judge_objects]
210+
if not wing_judges:
191211
break
192212

193-
wing_pool = list(available_indices)
213+
wing_pool = list(range(len(wing_judges)))
194214
pairing_indices = list(range(num_rounds))
195215
if settings.wing_mode == WingPairingMode.RANDOM:
196216
random.shuffle(wing_pool)
197217
random.shuffle(pairing_indices)
198218

199219
wing_edges = []
200-
for relative_rank, judge_i in enumerate(wing_pool):
201-
judge = judges[judge_i]
202-
judge_score = judge_scores[judge_i]
220+
wing_judge_scores = construct_judge_scores(wing_judges, settings.mode)
221+
for relative_rank, wing_judge_i in enumerate(wing_pool):
222+
judge = wing_judges[wing_judge_i]
223+
judge_score = wing_judge_scores[wing_judge_i]
203224
for pairing_i in pairing_indices:
204225
pairing = pairings[pairing_i]
205226
has_conflict = judge_conflict(
@@ -226,34 +247,32 @@ def add_judges():
226247
wing_mode=settings.wing_mode,
227248
chair_judge_i=chair_by_pairing[pairing_i],
228249
relative_judge_rank=relative_rank,
229-
judge_index=judge_i,
250+
judge_index=wing_judge_i,
230251
)
231252
if rejudge_sum > 0 and settings.rejudge_penalty > 0:
232253
penalty = settings.rejudge_penalty * (1 + 0.1 * judge_score)
233254
weight -= penalty * rejudge_sum
234255

235-
wing_edges.append((pairing_i, num_rounds + judge_i, weight))
256+
wing_edges.append((pairing_i, num_rounds + wing_judge_i, weight))
236257

237258
if not wing_edges:
238259
break
239260

240261
wing_matches = mwmatching.maxWeightMatching(wing_edges, maxcardinality=True)
241-
for pairing_i, padded_judge_i in enumerate(wing_matches[:num_rounds]):
242-
if padded_judge_i == -1:
243-
continue
244-
judge_i = padded_judge_i - num_rounds
245-
if judge_i in assigned_judges:
262+
for pairing_i, padded_wing_judge_i in enumerate(wing_matches[:num_rounds]):
263+
if padded_wing_judge_i == -1:
246264
continue
247-
if (pairing_i, judge_i) in assigned_pairs:
265+
wing_judge_i = padded_wing_judge_i - num_rounds
266+
judge = wing_judges[wing_judge_i]
267+
if judge.id in assigned_judge_objects:
248268
continue
249269
judge_round_joins.append(
250270
Round.judges.through(
251-
judge=judges[judge_i],
271+
judge=judge,
252272
round=pairings[pairing_i],
253273
)
254274
)
255-
assigned_judges.add(judge_i)
256-
assigned_pairs.add((pairing_i, judge_i))
275+
assigned_judge_objects.add(judge.id)
257276

258277
Round.judges.through.objects.bulk_create(judge_round_joins)
259278

mittab/templates/outrounds/pairing_card.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ <h6 class="opp-team">
7474
<a class="btn-sm btn-light outround-judge-toggle dropdown-toggle{% if pairing.chair == judge %} chair{% endif %}"
7575
data-toggle="dropdown" href="#">
7676
{{judge.name}} <small>({{judge.rank}})</small>
77+
{% if judge.wing_only %}
78+
<span class="badge badge-warning badge-wing-only ml-1">Wing Only</span>
79+
{% endif %}
7780
</a>
7881
<ul class="dropdown-menu"></ul>
7982
</span>

mittab/templates/pairing/_pairing_card.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ <h6 class="opp-team">
7979
{% if rejudge_count > 1 %}
8080
<span class="badge badge-warning ml-1">({{rejudge_count}})</span>
8181
{% endif %}
82+
{% if judge.wing_only %}
83+
<span class="badge badge-warning badge-wing-only ml-1">Wing Only</span>
84+
{% endif %}
8285
</a>
8386
<ul class="dropdown-menu"></ul>
8487
</span>

mittab/templates/pairing/judge_dropdown.html

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,33 @@ <h6 class="text-center dropdown-header">Current Judge</h6>
2727
{% if not is_outround and current_judge_rejudge_display %}
2828
<span class="badge badge-warning ml-1">({{current_judge_rejudge_display}})</span>
2929
{% endif %}
30+
{% if current_judge_obj and current_judge_obj.wing_only %}
31+
<span class="badge badge-warning badge-wing-only ml-1">Wing Only</span>
32+
{% endif %}
3033
</a>
3134
<div class="dropdown-divider"></div>
3235
<h6 class="text-center dropdown-header">Viable Judges Not Paired In</h6>
3336
{% if is_outround %}
34-
{% for judge_name, judge_id, judge_rank in excluded_judges%}
37+
{% for judge_name, judge_id, judge_rank, wing_only in excluded_judges%}
3538
<a href="#" class="dropdown-item judge-assign searchable" judge-id="{{judge_id}}" round-id="{{round_obj.id}}" current-judge-id="{{current_judge_id}}">
3639
{{judge_name}} - {{judge_rank}}
40+
{% if wing_only %}
41+
<span class="badge badge-warning badge-wing-only ml-1">Wing Only</span>
42+
{% endif %}
3743
</a>
3844
{% empty %}
3945
<a class="dropdown-item">No viable judges</a>
4046
{% endfor %}
4147
{% else %}
42-
{% for judge_name, judge_id, judge_rank, rejudge_count in excluded_judges%}
48+
{% for judge_name, judge_id, judge_rank, rejudge_count, wing_only in excluded_judges%}
4349
<a href="#" class="dropdown-item judge-assign searchable" judge-id="{{judge_id}}" round-id="{{round_obj.id}}" current-judge-id="{{current_judge_id}}">
4450
{{judge_name}} - {{judge_rank}}
4551
{% if rejudge_count %}
4652
<span class="badge badge-warning ml-1">({{rejudge_count}})</span>
4753
{% endif %}
54+
{% if wing_only %}
55+
<span class="badge badge-warning badge-wing-only ml-1">Wing Only</span>
56+
{% endif %}
4857
</a>
4958
{% empty %}
5059
<a class="dropdown-item">No viable judges</a>
@@ -54,20 +63,26 @@ <h6 class="text-center dropdown-header">Viable Judges Not Paired In</h6>
5463
<div class="dropdown-divider"></div>
5564
<h6 class="text-center dropdown-header">Viable Judges Within Pairing</h6>
5665
{% if is_outround %}
57-
{% for judge_name, judge_id, judge_rank in included_judges%}
66+
{% for judge_name, judge_id, judge_rank, wing_only in included_judges%}
5867
<a href="#" class="dropdown-item judge-assign searchable" judge-id="{{judge_id}}" round-id="{{round_obj.id}}" current-judge-id="{{current_judge_id}}">
5968
{{judge_name}} - {{judge_rank}}
69+
{% if wing_only %}
70+
<span class="badge badge-warning badge-wing-only ml-1">Wing Only</span>
71+
{% endif %}
6072
</a>
6173
{% empty %}
6274
<a class="dropdown-item">No viable judges</a>
6375
{% endfor %}
6476
{% else %}
65-
{% for judge_name, judge_id, judge_rank, rejudge_count in included_judges%}
77+
{% for judge_name, judge_id, judge_rank, rejudge_count, wing_only in included_judges%}
6678
<a href="#" class="dropdown-item judge-assign searchable" judge-id="{{judge_id}}" round-id="{{round_obj.id}}" current-judge-id="{{current_judge_id}}">
6779
{{judge_name}} - {{judge_rank}}
6880
{% if rejudge_count %}
6981
<span class="badge badge-warning ml-1">({{rejudge_count}})</span>
7082
{% endif %}
83+
{% if wing_only %}
84+
<span class="badge badge-warning badge-wing-only ml-1">Wing Only</span>
85+
{% endif %}
7186
</a>
7287
{% empty %}
7388
<a class="dropdown-item">No viable judges</a>

0 commit comments

Comments
 (0)