diff --git a/courseware/grades.py b/courseware/grades.py index 43ed0c8155..b90e143c92 100644 --- a/courseware/grades.py +++ b/courseware/grades.py @@ -1,12 +1,12 @@ -import logging -import urllib -from lxml import etree - import courseware.content_parser as content_parser -from models import StudentModule -from django.conf import settings import courseware.modules +import logging +import random +import urllib +from django.conf import settings +from lxml import etree +from models import StudentModule from student.models import UserProfile log = logging.getLogger("mitx.courseware") @@ -17,7 +17,7 @@ def get_grade(user, problem, cache): correct = 0 # If the ID is not in the cache, add the item - if id not in cache: + if id not in cache: module = StudentModule(module_type = 'problem', # TODO: Move into StudentModule.__init__? module_id = id, student = user, @@ -44,6 +44,17 @@ def get_grade(user, problem, cache): return (correct, total) def grade_sheet(student): + """ + This pulls a summary of all problems in the course. It returns a dictionary with two datastructures: + + - courseware_summary is a summary of all sections with problems in the course. It is organized as an array of chapters, + each containing an array of sections, each containing an array of scores. This contains information for graded and ungraded + problems, and is good for displaying a course summary with due dates, etc. + + - grade_summary is a summary of how the final grade breaks down. It is an array of "sections". Each section can either be + a conglomerate of scores (like labs or homeworks) which has subscores and a totalscore, or a section can be all from one assignment + (such as a midterm or final) and only has a totalscore. Each section has a weight that shows how it contributes to the total grade. + """ dom=content_parser.course_file(student) course = dom.xpath('//course/@name')[0] xmlChapters = dom.xpath('//course[@name=$course]/chapter', course=course) @@ -54,7 +65,7 @@ def grade_sheet(student): response_by_id[response.module_id] = response - total_scores = {} + totaled_scores = {} chapters=[] for c in xmlChapters: sections = [] @@ -93,13 +104,13 @@ def grade_sheet(student): graded_total = (sum([score[0] for score in scores if score[2]]), sum([score[1] for score in scores if score[2]])) - #Add the graded total to total_scores + #Add the graded total to totaled_scores format = s.get('format') if s.get('format') else "" subtitle = s.get('subtitle') if s.get('subtitle') else format if format and graded_total[1] > 0: - format_scores = total_scores[ format ] if format in total_scores else [] + format_scores = totaled_scores[ format ] if format in totaled_scores else [] format_scores.append( graded_total + (s.get("name"),) ) - total_scores[ format ] = format_scores + totaled_scores[ format ] = format_scores score={'section':s.get("name"), 'scores':scores, @@ -114,7 +125,20 @@ def grade_sheet(student): chapters.append({'course':course, 'chapter' : c.get("name"), 'sections' : sections,}) - + + + grade_summary = grade_summary_6002x(totaled_scores) + + return {'courseware_summary' : chapters, + 'grade_summary' : grade_summary} + + +def grade_summary_6002x(totaled_scores): + """ + This function takes the a dictionary of (graded) section scores, and applies the course grading rules to create + the grade_summary. For 6.002x this means homeworks and labs all have equal weight, with the lowest 2 of each + being dropped. There is one midterm and one final. + """ def totalWithDrops(scores, drop_count): #Note that this key will sort the list descending @@ -131,7 +155,7 @@ def grade_sheet(student): return aggregate_score, dropped_indices #Figure the homework scores - homework_scores = total_scores['Homework'] if 'Homework' in total_scores else [] + homework_scores = totaled_scores['Homework'] if 'Homework' in totaled_scores else [] homework_percentages = [] for i in range(12): if i < len(homework_scores): @@ -153,7 +177,7 @@ def grade_sheet(student): homework_total, homework_dropped_indices = totalWithDrops(homework_percentages, 2) #Figure the lab scores - lab_scores = total_scores['Lab'] if 'Lab' in total_scores else [] + lab_scores = totaled_scores['Lab'] if 'Lab' in totaled_scores else [] lab_percentages = [] log.debug("lab_scores: {0}".format(lab_scores)) for i in range(12): @@ -196,7 +220,8 @@ def grade_sheet(student): 'category': 'Homework', 'subscores' : homework_percentages, 'dropped_indices' : homework_dropped_indices, - 'totalscore' : {'score' : homework_total, 'summary' : "Homework Average - {0:.0%}".format(homework_total)}, + 'totalscore' : homework_total, + 'totalscore_summary' : "Homework Average - {0:.0%}".format(homework_total), 'totallabel' : 'HW Avg', 'weight' : 0.15, }, @@ -204,25 +229,25 @@ def grade_sheet(student): 'category': 'Labs', 'subscores' : lab_percentages, 'dropped_indices' : lab_dropped_indices, - 'totalscore' : {'score' : lab_total, 'summary' : "Lab Average - {0:.0%}".format(lab_total)}, + 'totalscore' : lab_total, + 'totalscore_summary' : "Lab Average - {0:.0%}".format(lab_total), 'totallabel' : 'Lab Avg', 'weight' : 0.15, }, { 'category': 'Midterm', - 'totalscore' : {'score' : midterm_percentage, 'summary' : "Midterm - {0:.0%} ({1}/{2})".format(midterm_percentage, midterm_score[0], midterm_score[1])}, + 'totalscore' : midterm_percentage, + 'totalscore_summary' : "Midterm - {0:.0%} ({1}/{2})".format(midterm_percentage, midterm_score[0], midterm_score[1]), 'totallabel' : 'Midterm', 'weight' : 0.30, }, { 'category': 'Final', - 'totalscore' : {'score' : final_percentage, 'summary' : "Final - {0:.0%} ({1}/{2})".format(final_percentage, final_score[0], final_score[1])}, + 'totalscore' : final_percentage, + 'totalscore_summary' : "Final - {0:.0%} ({1}/{2})".format(final_percentage, final_score[0], final_score[1]), 'totallabel' : 'Final', 'weight' : 0.40, } ] - return {'grade_summary' : grade_summary, - 'chapters':chapters} - - + return grade_summary