Commit 189f53bc by Sarina Canelake

Fix grades management commands

parent 1e27f177
......@@ -3,6 +3,9 @@ from certificates.models import GeneratedCertificate
from django.test.client import RequestFactory
from django.core.management.base import BaseCommand, CommandError
import os
from opaque_keys import InvalidKeyError
from xmodule.modulestore.keys import CourseKey
from xmodule.modulestore.locations import SlashSeparatedCourseKey
from django.contrib.auth.models import User
from optparse import make_option
import datetime
......@@ -62,24 +65,37 @@ class Command(BaseCommand):
options['output']))
STATUS_INTERVAL = 100
course_id = options['course']
print "Fetching enrolled students for {0}".format(course_id)
# parse out the course into a coursekey
if options['course']:
try:
course_key = CourseKey.from_string(options['course'])
# if it's not a new-style course key, parse it from an old-style
# course key
except InvalidKeyError:
course_key = SlashSeparatedCourseKey.from_deprecated_string(options['course'])
print "Fetching enrolled students for {0}".format(course_key)
enrolled_students = User.objects.filter(
courseenrollment__course_id=course_id)
courseenrollment__course_id=course_key
)
factory = RequestMock()
request = factory.get('/')
total = enrolled_students.count()
print "Total enrolled: {0}".format(total)
course = courses.get_course_by_id(course_id)
course = courses.get_course_by_id(course_key)
total = enrolled_students.count()
start = datetime.datetime.now()
rows = []
header = None
print "Fetching certificate data"
cert_grades = {cert.user.username: cert.grade
for cert in list(GeneratedCertificate.objects.filter(
course_id=course_id).prefetch_related('user'))}
cert_grades = {
cert.user.username: cert.grade
for cert in list(
GeneratedCertificate.objects.filter(course_id=course_key).prefetch_related('user')
)
}
print "Grading students"
for count, student in enumerate(enrolled_students):
count += 1
......
......@@ -6,6 +6,9 @@
from instructor.offline_gradecalc import offline_grade_calculation
from courseware.courses import get_course_by_id
from xmodule.modulestore.django import modulestore
from opaque_keys import InvalidKeyError
from xmodule.modulestore.keys import CourseKey
from xmodule.modulestore.locations import SlashSeparatedCourseKey
from django.core.management.base import BaseCommand
......@@ -25,19 +28,24 @@ class Command(BaseCommand):
else:
print self.help
return
course_key = None
# parse out the course id into a coursekey
try:
course_key = CourseKey.from_string(course_id)
# if it's not a new-style course key, parse it from an old-style
# course key
except InvalidKeyError:
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
try:
course = get_course_by_id(course_id)
course = get_course_by_id(course_key)
except Exception as err:
if course_id in modulestore().courses:
course = modulestore().courses[course_id]
else:
print "-----------------------------------------------------------------------------"
print "Sorry, cannot find course %s" % course_id
print "Please provide a course ID or course data directory name, eg content-mit-801rq"
return
print "-----------------------------------------------------------------------------"
print "Sorry, cannot find course with id {}".format(course_id)
print "Got exception {}".format(err)
print "Please provide a course ID or course data directory name, eg content-mit-801rq"
return
print "-----------------------------------------------------------------------------"
print "Computing grades for %s" % (course.id)
print "Computing grades for {}".format(course_id)
offline_grade_calculation(course.id)
offline_grade_calculation(course_key)
......@@ -7,6 +7,9 @@ import csv
from instructor.views.legacy import get_student_grade_summary_data
from courseware.courses import get_course_by_id
from opaque_keys import InvalidKeyError
from xmodule.modulestore.keys import CourseKey
from xmodule.modulestore.locations import SlashSeparatedCourseKey
from xmodule.modulestore.django import modulestore
from django.core.management.base import BaseCommand
......@@ -39,20 +42,26 @@ class Command(BaseCommand):
get_raw_scores = args[2].lower() == 'raw'
request = DummyRequest()
# parse out the course into a coursekey
try:
course = get_course_by_id(course_id)
except Exception:
if course_id in modulestore().courses:
course = modulestore().courses[course_id]
else:
print "-----------------------------------------------------------------------------"
print "Sorry, cannot find course %s" % course_id
print "Please provide a course ID or course data directory name, eg content-mit-801rq"
return
course_key = CourseKey.from_string(course_id)
# if it's not a new-style course key, parse it from an old-style
# course key
except InvalidKeyError:
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
try:
course = get_course_by_id(course_key)
except Exception as err:
print "-----------------------------------------------------------------------------"
print "Sorry, cannot find course with id {}".format(course_id)
print "Got exception {}".format(err)
print "Please provide a course ID or course data directory name, eg content-mit-801rq"
return
print "-----------------------------------------------------------------------------"
print "Dumping grades from %s to file %s (get_raw_scores=%s)" % (course.id, fn, get_raw_scores)
datatable = get_student_grade_summary_data(request, course, course.id, get_raw_scores=get_raw_scores)
print "Dumping grades from {} to file {} (get_raw_scores={})".format(course.id, fn, get_raw_scores)
datatable = get_student_grade_summary_data(request, course, get_raw_scores=get_raw_scores)
fp = open(fn, 'w')
......@@ -63,4 +72,4 @@ class Command(BaseCommand):
writer.writerow(encoded_row)
fp.close()
print "Done: %d records dumped" % len(datatable['data'])
print "Done: {} records dumped".format(len(datatable['data']))
......@@ -26,21 +26,21 @@ class MyEncoder(JSONEncoder):
yield chunk
def offline_grade_calculation(course_id):
def offline_grade_calculation(course_key):
'''
Compute grades for all students for a specified course, and save results to the DB.
'''
tstart = time.time()
enrolled_students = User.objects.filter(
courseenrollment__course_id=course_id,
courseenrollment__course_id=course_key,
courseenrollment__is_active=1
).prefetch_related("groups").order_by('username')
enc = MyEncoder()
print "%d enrolled students" % len(enrolled_students)
course = get_course_by_id(course_id)
print "{} enrolled students".format(len(enrolled_students))
course = get_course_by_id(course_key)
for student in enrolled_students:
request = DummyRequest()
......@@ -49,7 +49,7 @@ def offline_grade_calculation(course_id):
gradeset = grades.grade(student, request, course, keep_raw_scores=True)
gs = enc.encode(gradeset)
ocg, created = models.OfflineComputedGrade.objects.get_or_create(user=student, course_id=course_id)
ocg, created = models.OfflineComputedGrade.objects.get_or_create(user=student, course_id=course_key)
ocg.gradeset = gs
ocg.save()
print "%s done" % student # print statement used because this is run by a management command
......@@ -57,18 +57,18 @@ def offline_grade_calculation(course_id):
tend = time.time()
dt = tend - tstart
ocgl = models.OfflineComputedGradeLog(course_id=course_id, seconds=dt, nstudents=len(enrolled_students))
ocgl = models.OfflineComputedGradeLog(course_id=course_key, seconds=dt, nstudents=len(enrolled_students))
ocgl.save()
print ocgl
print "All Done!"
def offline_grades_available(course_id):
def offline_grades_available(course_key):
'''
Returns False if no offline grades available for specified course.
Otherwise returns latest log field entry about the available pre-computed grades.
'''
ocgl = models.OfflineComputedGradeLog.objects.filter(course_id=course_id)
ocgl = models.OfflineComputedGradeLog.objects.filter(course_id=course_key)
if not ocgl:
return False
return ocgl.latest('created')
......@@ -86,7 +86,10 @@ def student_grades(student, request, course, keep_raw_scores=False, use_offline=
try:
ocg = models.OfflineComputedGrade.objects.get(user=student, course_id=course.id)
except models.OfflineComputedGrade.DoesNotExist:
return dict(raw_scores=[], section_breakdown=[],
msg='Error: no offline gradeset available for %s, %s' % (student, course.id))
return dict(
raw_scores=[],
section_breakdown=[],
msg='Error: no offline gradeset available for {}, {}'.format(student, course.id)
)
return json.loads(ocg.gradeset)
......@@ -226,19 +226,19 @@ def instructor_dashboard(request, course_id):
if action == 'Dump list of enrolled students' or action == 'List enrolled students':
log.debug(action)
datatable = get_student_grade_summary_data(request, course, course_key, get_grades=False, use_offline=use_offline)
datatable = get_student_grade_summary_data(request, course, get_grades=False, use_offline=use_offline)
datatable['title'] = _('List of students enrolled in {course_key}').format(course_key=course_key.to_deprecated_string())
track.views.server_track(request, "list-students", {}, page="idashboard")
elif 'Dump Grades' in action:
log.debug(action)
datatable = get_student_grade_summary_data(request, course, course_key, get_grades=True, use_offline=use_offline)
datatable = get_student_grade_summary_data(request, course, get_grades=True, use_offline=use_offline)
datatable['title'] = _('Summary Grades of students enrolled in {course_key}').format(course_key=course_key.to_deprecated_string())
track.views.server_track(request, "dump-grades", {}, page="idashboard")
elif 'Dump all RAW grades' in action:
log.debug(action)
datatable = get_student_grade_summary_data(request, course, course_key, get_grades=True,
datatable = get_student_grade_summary_data(request, course, get_grades=True,
get_raw_scores=True, use_offline=use_offline)
datatable['title'] = _('Raw Grades of students enrolled in {course_key}').format(course_key=course_key)
track.views.server_track(request, "dump-grades-raw", {}, page="idashboard")
......@@ -246,12 +246,12 @@ def instructor_dashboard(request, course_id):
elif 'Download CSV of all student grades' in action:
track.views.server_track(request, "dump-grades-csv", {}, page="idashboard")
return return_csv('grades_{0}.csv'.format(course_key.to_deprecated_string()),
get_student_grade_summary_data(request, course, course_key, use_offline=use_offline))
get_student_grade_summary_data(request, course, use_offline=use_offline))
elif 'Download CSV of all RAW grades' in action:
track.views.server_track(request, "dump-grades-csv-raw", {}, page="idashboard")
return return_csv('grades_{0}_raw.csv'.format(course_key.to_deprecated_string()),
get_student_grade_summary_data(request, course, course_key, get_raw_scores=True, use_offline=use_offline))
get_student_grade_summary_data(request, course, get_raw_scores=True, use_offline=use_offline))
elif 'Download CSV of answer distributions' in action:
track.views.server_track(request, "dump-answer-dist-csv", {}, page="idashboard")
......@@ -539,7 +539,7 @@ def instructor_dashboard(request, course_id):
elif action == 'List assignments available for this course':
log.debug(action)
allgrades = get_student_grade_summary_data(request, course, course_key, get_grades=True, use_offline=use_offline)
allgrades = get_student_grade_summary_data(request, course, get_grades=True, use_offline=use_offline)
assignments = [[x] for x in allgrades['assignments']]
datatable = {'header': [_('Assignment Name')]}
......@@ -549,7 +549,7 @@ def instructor_dashboard(request, course_id):
msg += 'assignments=<pre>%s</pre>' % assignments
elif action == 'List enrolled students matching remote gradebook':
stud_data = get_student_grade_summary_data(request, course, course_key, get_grades=False, use_offline=use_offline)
stud_data = get_student_grade_summary_data(request, course, get_grades=False, use_offline=use_offline)
msg2, rg_stud_data = _do_remote_gradebook(request.user, course, 'get-membership')
datatable = {'header': ['Student email', 'Match?']}
rg_students = [x['email'] for x in rg_stud_data['retdata']]
......@@ -568,7 +568,7 @@ def instructor_dashboard(request, course_id):
if not aname:
msg += "<font color='red'>{text}</font>".format(text=_("Please enter an assignment name"))
else:
allgrades = get_student_grade_summary_data(request, course, course_key, get_grades=True, use_offline=use_offline)
allgrades = get_student_grade_summary_data(request, course, get_grades=True, use_offline=use_offline)
if aname not in allgrades['assignments']:
msg += "<font color='red'>{text}</font>".format(
text=_("Invalid assignment name '{name}'").format(name=aname)
......@@ -1354,8 +1354,8 @@ class GradeTable(object):
return self.components.keys()
def get_student_grade_summary_data(request, course, course_key, get_grades=True, get_raw_scores=False, use_offline=False):
'''
def get_student_grade_summary_data(request, course, get_grades=True, get_raw_scores=False, use_offline=False):
"""
Return data arrays with student identity and grades for specified course.
course = CourseDescriptor
......@@ -1370,8 +1370,8 @@ def get_student_grade_summary_data(request, course, course_key, get_grades=True,
data = list (one per student) of lists of data corresponding to the fields
If get_raw_scores=True, then instead of grade summaries, the raw grades for all graded modules are returned.
'''
"""
course_key = course.id
enrolled_students = User.objects.filter(
courseenrollment__course_id=course_key,
courseenrollment__is_active=1,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment