Skip to content

Commit 8de8429

Browse files
committed
update scoring/export to cope with marking sessions
1 parent 889b451 commit 8de8429

File tree

5 files changed

+71
-43
lines changed

5 files changed

+71
-43
lines changed

crowdsourcer/fixtures/basics.json

+17
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@
88
"active": true
99
}
1010
},
11+
{
12+
"model": "crowdsourcer.markingsession",
13+
"pk": 2,
14+
"fields": {
15+
"label": "Second Session",
16+
"start_date": "2023-03-01",
17+
"active": true
18+
}
19+
},
1120
{
1221
"model": "crowdsourcer.section",
1322
"pk": 1,
@@ -64,6 +73,14 @@
6473
"title": "Waste Reduction & Food"
6574
}
6675
},
76+
{
77+
"model": "crowdsourcer.section",
78+
"pk": 8,
79+
"fields": {
80+
"marking_session": 2,
81+
"title": "Second Session Section"
82+
}
83+
},
6784
{
6885
"model": "crowdsourcer.questiongroup",
6986
"pk": 1,

crowdsourcer/management/commands/export_marks.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import pandas as pd
55

6-
from crowdsourcer.models import Question
6+
from crowdsourcer.models import MarkingSession, Question
77
from crowdsourcer.scoring import get_all_question_data, get_scoring_object
88

99

@@ -27,6 +27,10 @@ def add_arguments(self, parser):
2727
"--output_answers", action="store_true", help="Output the all answers file"
2828
)
2929

30+
parser.add_argument(
31+
"--session", action="store", help="Name of the marking session to use"
32+
)
33+
3034
def write_files(
3135
self, percent_marks, raw_marks, linear, answers=None, questions=None
3236
):
@@ -58,11 +62,18 @@ def write_files(
5862
def handle(
5963
self, quiet: bool = False, output_answers: bool = False, *args, **options
6064
):
65+
session_label = options["session"]
66+
try:
67+
session = MarkingSession.objects.get(label=session_label)
68+
except MarkingSession.DoesNotExist:
69+
self.stderr.write(f"No such session: {session_label}")
70+
return
71+
6172
raw = []
6273
percent = []
6374
linear = []
6475

65-
scoring = get_scoring_object()
76+
scoring = get_scoring_object(session)
6677

6778
for council, council_score in scoring["section_totals"].items():
6879

crowdsourcer/scoring.py

+15-15
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,15 @@ def weighting_to_points(weighting="low", max_points=0):
138138
return points
139139

140140

141-
def get_section_maxes(scoring):
141+
def get_section_maxes(scoring, session):
142142
section_maxes = defaultdict(dict)
143143
section_weighted_maxes = defaultdict(dict)
144144
group_totals = defaultdict(int)
145145
q_maxes = defaultdict(int)
146146
q_weighted_maxes = defaultdict(int)
147147
negative_q = defaultdict(int)
148148

149-
for section in Section.objects.all():
149+
for section in Section.objects.filter(marking_session=session):
150150
q_section_maxes = {}
151151
q_section_weighted_maxes = {}
152152
q_section_negatives = {}
@@ -309,21 +309,21 @@ def get_maxes_for_council(scoring, group, country, council):
309309
return maxes, weighted_maxes
310310

311311

312-
def get_blank_section_scores():
312+
def get_blank_section_scores(session):
313313
raw_scores = defaultdict(dict)
314314
weighted = defaultdict(dict)
315315

316316
non_ca_sections = {
317317
x: 0
318-
for x in Section.objects.exclude(title__contains="(CA)").values_list(
319-
"title", flat=True
320-
)
318+
for x in Section.objects.exclude(title__contains="(CA)")
319+
.filter(marking_session=session)
320+
.values_list("title", flat=True)
321321
}
322322
ca_sections = {
323323
x: 0
324-
for x in Section.objects.filter(title__contains="(CA)").values_list(
325-
"title", flat=True
326-
)
324+
for x in Section.objects.filter(
325+
title__contains="(CA)", marking_session=session
326+
).values_list("title", flat=True)
327327
}
328328

329329
for council in PublicAuthority.objects.filter(do_not_mark=False).all():
@@ -346,12 +346,12 @@ def get_weighted_question_score(score, max_score, weighting):
346346
return percentage * weighting_to_points(weighting)
347347

348348

349-
def get_section_scores(scoring):
350-
raw_scores, weighted = get_blank_section_scores()
349+
def get_section_scores(scoring, session):
350+
raw_scores, weighted = get_blank_section_scores(session)
351351

352352
update_with_housing_exceptions()
353353

354-
for section in Section.objects.all():
354+
for section in Section.objects.filter(marking_session=session):
355355
options = (
356356
Response.objects.filter(
357357
response_type__type="Audit",
@@ -526,7 +526,7 @@ def calculate_council_totals(scoring):
526526
scoring["section_totals"] = section_totals
527527

528528

529-
def get_scoring_object():
529+
def get_scoring_object(session):
530530
scoring = {}
531531

532532
council_gss_map, groups, countries, types, control = PublicAuthority.maps()
@@ -539,8 +539,8 @@ def get_scoring_object():
539539
for council in PublicAuthority.objects.all():
540540
scoring["councils"][council.name] = council
541541

542-
get_section_maxes(scoring)
543-
get_section_scores(scoring)
542+
get_section_maxes(scoring, session)
543+
get_section_scores(scoring, session)
544544
calculate_council_totals(scoring)
545545

546546
return scoring

crowdsourcer/tests/test_export.py

+23-24
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from django.core.management import call_command
66
from django.test import TestCase
77

8-
from crowdsourcer.models import Question, Response
8+
from crowdsourcer.models import MarkingSession, Question, Response
99
from crowdsourcer.scoring import get_section_maxes
1010

1111
max_section = {
@@ -161,9 +161,12 @@ class ExportNoMarksTestCase(BaseCommandTestCase):
161161
"options.json",
162162
]
163163

164+
def setUp(self):
165+
self.session = MarkingSession.objects.get(label="Default")
166+
164167
def test_max_calculation(self):
165168
scoring = {}
166-
get_section_maxes(scoring)
169+
get_section_maxes(scoring, self.session)
167170

168171
self.assertEquals(scoring["section_maxes"], max_section)
169172
self.assertEquals(scoring["group_maxes"], max_totals)
@@ -174,7 +177,7 @@ def test_max_calculation_with_unweighted_q(self):
174177
Question.objects.filter(pk=272).update(weighting="unweighted")
175178

176179
scoring = {}
177-
get_section_maxes(scoring)
180+
get_section_maxes(scoring, self.session)
178181

179182
local_max_w = max_weighted.copy()
180183
local_max_w["Buildings & Heating"] = {
@@ -197,9 +200,7 @@ def test_max_calculation_with_unweighted_q(self):
197200
@mock.patch("crowdsourcer.scoring.EXCEPTIONS", {})
198201
@mock.patch("crowdsourcer.scoring.SCORE_EXCEPTIONS", {})
199202
def test_export_with_no_marks(self, write_mock):
200-
self.call_command(
201-
"export_marks",
202-
)
203+
self.call_command("export_marks", session="Default")
203204

204205
expected_percent = [
205206
{
@@ -329,7 +330,7 @@ def test_max_calculation(self):
329330
scoring = {}
330331
expected_max_q = deepcopy(max_questions)
331332
expected_max_q["Buildings & Heating"]["20"] = 0
332-
get_section_maxes(scoring)
333+
get_section_maxes(scoring, MarkingSession.objects.get(label="Default"))
333334

334335
self.assertEquals(scoring["section_maxes"], max_section)
335336
self.assertEquals(scoring["group_maxes"], max_totals)
@@ -478,7 +479,7 @@ class ExportWithMarksTestCase(BaseCommandTestCase):
478479
@mock.patch("crowdsourcer.scoring.EXCEPTIONS", {})
479480
@mock.patch("crowdsourcer.scoring.SCORE_EXCEPTIONS", {})
480481
def test_export(self, write_mock):
481-
self.call_command("export_marks")
482+
self.call_command("export_marks", session="Default")
482483

483484
percent, raw, linear = write_mock.call_args[0]
484485
self.assertEquals(raw, self.expected_raw)
@@ -491,7 +492,7 @@ def test_export(self, write_mock):
491492
def test_export_with_unweighted_q(self, write_mock):
492493
Question.objects.filter(pk=272).update(weighting="unweighted")
493494

494-
self.call_command("export_marks")
495+
self.call_command("export_marks", session="Default")
495496

496497
expected_percent = deepcopy(self.expected_percent)
497498
expected_percent[0]["Buildings & Heating"] = 0.17
@@ -508,7 +509,7 @@ def test_export_with_unweighted_q(self, write_mock):
508509
def test_export_with_exceptions(self, write_mock):
509510
Response.objects.filter(question_id=282, authority_id=2).delete()
510511

511-
self.call_command("export_marks")
512+
self.call_command("export_marks", session="Default")
512513
expected_linear = deepcopy(self.expected_linear)
513514

514515
expected_linear[1] = (
@@ -552,7 +553,7 @@ def test_export_with_score_exceptions(self, write_mock):
552553
r.multi_option.add(161)
553554
r.save()
554555

555-
self.call_command("export_marks")
556+
self.call_command("export_marks", session="Default")
556557
expected_linear = deepcopy(self.expected_linear)
557558

558559
expected_linear[1] = (
@@ -610,7 +611,7 @@ def test_export_with_score_exceptions(self, write_mock):
610611
expected_percent[1]["raw_total"] = 0.07
611612
expected_percent[1]["weighted_total"] = 0.2
612613

613-
self.call_command("export_marks")
614+
self.call_command("export_marks", session="Default")
614615
percent, raw, linear = write_mock.call_args[0]
615616
self.assertEquals(linear, expected_linear)
616617
self.assertEquals(raw, expected_raw)
@@ -622,7 +623,7 @@ def test_export_with_score_exceptions(self, write_mock):
622623
def test_export_with_council_type_exceptions(self, write_mock):
623624
Response.objects.filter(question_id=282, authority_id=2).delete()
624625

625-
self.call_command("export_marks")
626+
self.call_command("export_marks", session="Default")
626627
expected_linear = deepcopy(self.expected_linear)
627628

628629
expected_linear[1] = (
@@ -660,7 +661,7 @@ def test_export_with_council_type_exceptions(self, write_mock):
660661
def test_export_with_council_name_exceptions(self, write_mock):
661662
Response.objects.filter(question_id=282, authority_id=2).delete()
662663

663-
self.call_command("export_marks")
664+
self.call_command("export_marks", session="Default")
664665
expected_linear = deepcopy(self.expected_linear)
665666

666667
expected_linear[1] = (
@@ -703,7 +704,7 @@ def test_export_with_housing_exception(self, write_mock):
703704
r.option_id = 205
704705
r.save()
705706

706-
self.call_command("export_marks")
707+
self.call_command("export_marks", session="Default")
707708

708709
expected_linear = deepcopy(self.expected_linear)
709710

@@ -808,7 +809,7 @@ class ExportWithMarksNegativeQTestCase(BaseCommandTestCase):
808809
@mock.patch("crowdsourcer.scoring.EXCEPTIONS", {})
809810
@mock.patch("crowdsourcer.scoring.SCORE_EXCEPTIONS", {})
810811
def test_export(self, write_mock):
811-
self.call_command("export_marks")
812+
self.call_command("export_marks", session="Default")
812813

813814
percent, raw, linear = write_mock.call_args[0]
814815
self.assertEquals(raw, self.expected_raw)
@@ -829,7 +830,7 @@ class ExportWithMultiMarksTestCase(BaseCommandTestCase):
829830
@mock.patch("crowdsourcer.scoring.EXCEPTIONS", {})
830831
@mock.patch("crowdsourcer.scoring.SCORE_EXCEPTIONS", {})
831832
def test_export(self, write_mock):
832-
self.call_command("export_marks")
833+
self.call_command("export_marks", session="Default")
833834

834835
expected_percent = [
835836
{
@@ -934,7 +935,7 @@ class ExportWithMoreMarksTestCase(BaseCommandTestCase):
934935
@mock.patch("crowdsourcer.scoring.EXCEPTIONS", {})
935936
@mock.patch("crowdsourcer.scoring.SCORE_EXCEPTIONS", {})
936937
def test_export(self, write_mock):
937-
self.call_command("export_marks")
938+
self.call_command("export_marks", session="Default")
938939

939940
expected_percent = [
940941
{
@@ -1039,7 +1040,7 @@ class ExportNoMarksCATestCase(BaseCommandTestCase):
10391040

10401041
def test_max_calculation(self):
10411042
scoring = {}
1042-
get_section_maxes(scoring)
1043+
get_section_maxes(scoring, MarkingSession.objects.get(label="Default"))
10431044

10441045
ca_max_section = {
10451046
**max_section,
@@ -1092,9 +1093,7 @@ def test_max_calculation(self):
10921093
@mock.patch("crowdsourcer.scoring.EXCEPTIONS", {})
10931094
@mock.patch("crowdsourcer.scoring.SCORE_EXCEPTIONS", {})
10941095
def test_export_with_no_marks(self, write_mock):
1095-
self.call_command(
1096-
"export_marks",
1097-
)
1096+
self.call_command("export_marks", session="Default")
10981097

10991098
expected_percent = [
11001099
{
@@ -1379,7 +1378,7 @@ class ExportWithMoreMarksCATestCase(BaseCommandTestCase):
13791378
@mock.patch("crowdsourcer.scoring.EXCEPTIONS", {})
13801379
@mock.patch("crowdsourcer.scoring.SCORE_EXCEPTIONS", {})
13811380
def test_export(self, write_mock):
1382-
self.call_command("export_marks")
1381+
self.call_command("export_marks", session="Default")
13831382

13841383
percent, raw, linear = write_mock.call_args[0]
13851384

@@ -1394,7 +1393,7 @@ def test_export_100_percent(self, write_mock):
13941393
Response.objects.filter(pk=37).update(option_id=196)
13951394
Response.objects.get(pk=36).multi_option.add(195)
13961395

1397-
self.call_command("export_marks")
1396+
self.call_command("export_marks", session="Default")
13981397

13991398
expected_raw = self.expected_raw.copy()
14001399
expected_percent = self.expected_percent.copy()

crowdsourcer/views/stats.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from django.utils.text import slugify
1010
from django.views.generic import ListView, TemplateView
1111

12+
from crowdsourcer.mixins import CurrentMarkingSessionMixin
1213
from crowdsourcer.models import Option, PublicAuthority, Question, Response
1314
from crowdsourcer.scoring import (
1415
get_all_question_data,
@@ -338,12 +339,12 @@ def get_response_data(self, response):
338339
return data
339340

340341

341-
class BaseScoresView(UserPassesTestMixin, TemplateView):
342+
class BaseScoresView(UserPassesTestMixin, CurrentMarkingSessionMixin, TemplateView):
342343
def test_func(self):
343344
return self.request.user.is_superuser
344345

345346
def get_scores(self):
346-
self.scoring = get_scoring_object()
347+
self.scoring = get_scoring_object(self.current_session)
347348

348349
def render_to_response(self, context, **response_kwargs):
349350
response = HttpResponse(

0 commit comments

Comments
 (0)