Skip to content

Commit

Permalink
Merge pull request #64 from QuizApp-Group/fix-reports
Browse files Browse the repository at this point in the history
Fix reports
  • Loading branch information
PlasmaSheep authored Sep 16, 2016
2 parents 211535d + aca8b75 commit 7c53430
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 23 deletions.
65 changes: 44 additions & 21 deletions quizApp/views/experiments.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Views that handle CRUD for experiments and rendering questions for
participants.
"""
from collections import defaultdict
from collections import defaultdict, Counter
from datetime import datetime
import json
import os
Expand Down Expand Up @@ -420,7 +420,7 @@ def results_experiment(experiment_id):
num_participants = Participant.query.count()
num_finished = AssignmentSet.query.\
filter_by(experiment_id=experiment.id).\
filter_by(progress=-1).count()
filter_by(complete=True).count()

percent_finished = num_finished / float(num_participants)

Expand Down Expand Up @@ -471,6 +471,28 @@ def export_results_experiment(experiment_id):
attachment_filename="experiment_{}_report.xlsx".format(experiment.id))


def get_activity_column_index(activity, activity_column_mapping,
activity_counter, headers):
"""Find the column index for this occurrence of the given activity. This
will update headers, counter, and mapping if necessary.
"""
activity_occurrence = activity_counter[activity.id]
activity_counter[activity.id] += 1
try:
return activity_column_mapping[activity.id][activity_occurrence]
except KeyError:
activity_column_mapping[activity.id] = [len(headers) + 1]
headers.append("{}: {}".format(activity.id, activity))
headers.append("Correct?")
headers.append("Points")
except IndexError:
activity_column_mapping[activity.id].append(len(headers) + 1)
headers.append("{}: {}".format(activity.id, activity))
headers.append("Correct?")
headers.append("Points")
return activity_column_mapping[activity.id][activity_occurrence]


def get_results_workbook(experiment):
"""Analyze the assignment sets in the experiment and return an excel
workbook.
Expand All @@ -481,11 +503,19 @@ def get_results_workbook(experiment):
next_participant_row = 2
participant_row_mapping = {}

# The same activity can appear multiple times in an assignment set. To
# display them properly, we keep a list of their ocurrences in
# activity_column_mapping, like so:
# {1: [3, 7, 10], ...} means activity 1 occurs in columns 3, 7, and 10
# When populating a row, we will use the earliest occurrence of the
# activity possible.

workbook = openpyxl.Workbook()
sheet = workbook.active
sheet.title = "Experiment {} - Report".format(experiment.id)

for assignment_set in assignment_sets:
activity_counter = Counter()
participant = assignment_set.participant

if not participant:
Expand All @@ -501,35 +531,28 @@ def get_results_workbook(experiment):

for assignment in assignment_set.assignments:
activity = assignment.activity

if activity.id not in activity_column_mapping:
activity_column_mapping[activity.id] = len(headers) + 1
headers.append("{}/{}: {}".format(assignment.id,
activity.id, activity))
headers.append("Correct?")
headers.append("Points")
activity_column_index = get_activity_column_index(
activity,
activity_column_mapping,
activity_counter,
headers)

if not assignment.result:
continue
row = ["_BLANK_"] * 3
else:
row = ["{}:{}".format(assignment.id, assignment.result),
assignment.correct,
assignment.score]

populate_row_segment(
sheet,
participant_row_mapping[participant.id],
activity_column_mapping[activity.id],
[str(assignment.result),
assignment.correct,
assignment.score]
activity_column_index,
row
)

populate_row_segment(sheet, 1, 1, headers)

# Put a special token in all blank spaces
for r in range(1, next_participant_row):
for c in range(1, len(headers) + 1):
value = sheet.cell(row=r, column=c).value
if value is None:
sheet.cell(row=r, column=c).value = "_BLANK_"

# Specify experiment ID
sheet.cell(row=1, column=len(headers) + 1).value = "Experiment ID"
sheet.cell(row=2, column=len(headers) + 1).value = experiment.id
Expand Down
28 changes: 26 additions & 2 deletions tests/test_views_experiments.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"""
from __future__ import unicode_literals
from builtins import str
from collections import Counter
import json
import random
import mock
Expand All @@ -11,9 +12,10 @@
import openpyxl

from quizApp import db
from quizApp.models import AssignmentSet
from quizApp.models import AssignmentSet, Activity
from quizApp.views.experiments import get_next_assignment_url, \
POST_FINALIZE_HANDLERS, validate_assignment_set, populate_row_segment
POST_FINALIZE_HANDLERS, validate_assignment_set, populate_row_segment, \
get_activity_column_index
from tests.factories import ExperimentFactory, create_experiment, \
ParticipantFactory, create_result
from tests.auth import login_participant, get_participant, \
Expand Down Expand Up @@ -726,3 +728,25 @@ def test_export_experiment_results(client, users):
url = "/experiments/{}/results/export".format(exp.id)
response = client.get(url)
assert response.status_code == 200


def test_get_activity_column_index():
activity = mock.MagicMock(autospec=Activity)
activity.id = 5
activity.__str__.return_value = ""
counter = Counter()
mapping = {}
headers = []

get_activity_column_index(activity, mapping, counter, headers)

assert mapping[activity.id][0] == 1 # 1-indexed due to openpyxl
assert len(mapping[activity.id]) == 1
assert counter[activity.id] == 1

get_activity_column_index(activity, mapping, counter, headers)

assert mapping[activity.id][0] == 1
assert mapping[activity.id][1] == 4
assert len(mapping[activity.id]) == 2
assert counter[activity.id] == 2

0 comments on commit 7c53430

Please sign in to comment.