Commit f28cba2a by David Ormsbee

Merge pull request #88 from MITx/cpennington/courseware_tests

Move courseware tests into the common/xmodule library
parents d7957424 a83fdc71
...@@ -21,8 +21,6 @@ from lxml import etree ...@@ -21,8 +21,6 @@ from lxml import etree
from lxml.etree import Element from lxml.etree import Element
from xml.sax.saxutils import escape, unescape from xml.sax.saxutils import escape, unescape
from mako.template import Template
from util import contextualize_text from util import contextualize_text
import inputtypes import inputtypes
......
...@@ -27,8 +27,6 @@ import shlex # for splitting quoted strings ...@@ -27,8 +27,6 @@ import shlex # for splitting quoted strings
from lxml import etree from lxml import etree
from mitxmako.shortcuts import render_to_string
def get_input_xml_tags(): def get_input_xml_tags():
''' Eventually, this will be for all registered input types ''' ''' Eventually, this will be for all registered input types '''
return SimpleInput.get_xml_tags() return SimpleInput.get_xml_tags()
...@@ -54,7 +52,7 @@ class SimpleInput():# XModule ...@@ -54,7 +52,7 @@ class SimpleInput():# XModule
return ['capa_input', 'capa_transform'] return ['capa_input', 'capa_transform']
def get_html(self): def get_html(self):
return self.xml_tags[self.tag](self.xml, self.value, self.status, self.msg) return self.xml_tags[self.tag](self.xml, self.value, self.status, self.system.render_template, self.msg)
def __init__(self, system, xml, item_id = None, track_url=None, state=None, use = 'capa_input'): def __init__(self, system, xml, item_id = None, track_url=None, state=None, use = 'capa_input'):
self.xml = xml self.xml = xml
...@@ -144,7 +142,7 @@ def register_render_function(fn, names=None, cls=SimpleInput): ...@@ -144,7 +142,7 @@ def register_render_function(fn, names=None, cls=SimpleInput):
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
@register_render_function @register_render_function
def optioninput(element, value, status, msg=''): def optioninput(element, value, status, render_template, msg=''):
''' '''
Select option input type. Select option input type.
...@@ -171,12 +169,12 @@ def optioninput(element, value, status, msg=''): ...@@ -171,12 +169,12 @@ def optioninput(element, value, status, msg=''):
'options':osetdict, 'options':osetdict,
} }
html=render_to_string("optioninput.html", context) html = render_template("optioninput.html", context)
return etree.XML(html) return etree.XML(html)
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
@register_render_function @register_render_function
def choicegroup(element, value, status, msg=''): def choicegroup(element, value, status, render_template, msg=''):
''' '''
Radio button inputs: multiple choice or true/false Radio button inputs: multiple choice or true/false
...@@ -199,11 +197,11 @@ def choicegroup(element, value, status, msg=''): ...@@ -199,11 +197,11 @@ def choicegroup(element, value, status, msg=''):
ctext += choice.text # TODO: fix order? ctext += choice.text # TODO: fix order?
choices[choice.get("name")] = ctext choices[choice.get("name")] = ctext
context={'id':eid, 'value':value, 'state':status, 'type':type, 'choices':choices} context={'id':eid, 'value':value, 'state':status, 'type':type, 'choices':choices}
html=render_to_string("choicegroup.html", context) html = render_template("choicegroup.html", context)
return etree.XML(html) return etree.XML(html)
@register_render_function @register_render_function
def textline(element, value, state, msg=""): def textline(element, value, state, render_template, msg=""):
''' '''
Simple text line input, with optional size specification. Simple text line input, with optional size specification.
''' '''
...@@ -213,13 +211,13 @@ def textline(element, value, state, msg=""): ...@@ -213,13 +211,13 @@ def textline(element, value, state, msg=""):
count = int(eid.split('_')[-2])-1 # HACK count = int(eid.split('_')[-2])-1 # HACK
size = element.get('size') size = element.get('size')
context = {'id':eid, 'value':value, 'state':state, 'count':count, 'size': size, 'msg': msg} context = {'id':eid, 'value':value, 'state':state, 'count':count, 'size': size, 'msg': msg}
html=render_to_string("textinput.html", context) html = render_template("textinput.html", context)
return etree.XML(html) return etree.XML(html)
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
@register_render_function @register_render_function
def textline_dynamath(element, value, status, msg=''): def textline_dynamath(element, value, status, render_template, msg=''):
''' '''
Text line input with dynamic math display (equation rendered on client in real time during input). Text line input with dynamic math display (equation rendered on client in real time during input).
''' '''
...@@ -237,13 +235,13 @@ def textline_dynamath(element, value, status, msg=''): ...@@ -237,13 +235,13 @@ def textline_dynamath(element, value, status, msg=''):
context = {'id':eid, 'value':value, 'state':status, 'count':count, 'size': size, context = {'id':eid, 'value':value, 'state':status, 'count':count, 'size': size,
'msg':msg, 'msg':msg,
} }
html=render_to_string("textinput_dynamath.html", context) html = render_template("textinput_dynamath.html", context)
return etree.XML(html) return etree.XML(html)
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
## TODO: Make a wrapper for <codeinput> ## TODO: Make a wrapper for <codeinput>
@register_render_function @register_render_function
def textbox(element, value, status, msg=''): def textbox(element, value, status, render_template, msg=''):
''' '''
The textbox is used for code input. The message is the return HTML string from The textbox is used for code input. The message is the return HTML string from
evaluating the code, eg error messages, and output from the code tests. evaluating the code, eg error messages, and output from the code tests.
...@@ -261,12 +259,12 @@ def textbox(element, value, status, msg=''): ...@@ -261,12 +259,12 @@ def textbox(element, value, status, msg=''):
'mode':mode, 'linenumbers':linenumbers, 'mode':mode, 'linenumbers':linenumbers,
'rows':rows, 'cols':cols, 'rows':rows, 'cols':cols,
} }
html=render_to_string("textbox.html", context) html = render_template("textbox.html", context)
return etree.XML(html) return etree.XML(html)
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
@register_render_function @register_render_function
def schematic(element, value, status, msg=''): def schematic(element, value, status, render_template, msg=''):
eid = element.get('id') eid = element.get('id')
height = element.get('height') height = element.get('height')
width = element.get('width') width = element.get('width')
...@@ -285,13 +283,13 @@ def schematic(element, value, status, msg=''): ...@@ -285,13 +283,13 @@ def schematic(element, value, status, msg=''):
'analyses':analyses, 'analyses':analyses,
'submit_analyses':submit_analyses, 'submit_analyses':submit_analyses,
} }
html=render_to_string("schematicinput.html", context) html = render_template("schematicinput.html", context)
return etree.XML(html) return etree.XML(html)
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
### TODO: Move out of inputtypes ### TODO: Move out of inputtypes
@register_render_function @register_render_function
def math(element, value, status, msg=''): def math(element, value, status, render_template, msg=''):
''' '''
This is not really an input type. It is a convention from Lon-CAPA, used for This is not really an input type. It is a convention from Lon-CAPA, used for
displaying a math equation. displaying a math equation.
...@@ -316,7 +314,7 @@ def math(element, value, status, msg=''): ...@@ -316,7 +314,7 @@ def math(element, value, status, msg=''):
# mathstr = mathstr.replace('\\displaystyle','') # mathstr = mathstr.replace('\\displaystyle','')
#else: #else:
# isinline = True # isinline = True
# html=render_to_string("mathstring.html",{'mathstr':mathstr,'isinline':isinline,'tail':element.tail}) # html = render_template("mathstring.html",{'mathstr':mathstr,'isinline':isinline,'tail':element.tail})
html = '<html><html>%s</html><html>%s</html></html>' % (mathstr,element.tail) html = '<html><html>%s</html><html>%s</html></html>' % (mathstr,element.tail)
xhtml = etree.XML(html) xhtml = etree.XML(html)
...@@ -326,7 +324,7 @@ def math(element, value, status, msg=''): ...@@ -326,7 +324,7 @@ def math(element, value, status, msg=''):
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
@register_render_function @register_render_function
def solution(element, value, status, msg=''): def solution(element, value, status, render_template, msg=''):
''' '''
This is not really an input type. It is just a <span>...</span> which is given an ID, This is not really an input type. It is just a <span>...</span> which is given an ID,
that is used for displaying an extended answer (a problem "solution") after "show answers" that is used for displaying an extended answer (a problem "solution") after "show answers"
...@@ -341,13 +339,13 @@ def solution(element, value, status, msg=''): ...@@ -341,13 +339,13 @@ def solution(element, value, status, msg=''):
'size': size, 'size': size,
'msg':msg, 'msg':msg,
} }
html=render_to_string("solutionspan.html", context) html = render_template("solutionspan.html", context)
return etree.XML(html) return etree.XML(html)
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
@register_render_function @register_render_function
def imageinput(element, value, status, msg=''): def imageinput(element, value, status, render_template, msg=''):
''' '''
Clickable image as an input field. Element should specify the image source, height, and width, eg Clickable image as an input field. Element should specify the image source, height, and width, eg
<imageinput src="/static/Physics801/Figures/Skier-conservation of energy.jpg" width="388" height="560" /> <imageinput src="/static/Physics801/Figures/Skier-conservation of energy.jpg" width="388" height="560" />
...@@ -378,5 +376,5 @@ def imageinput(element, value, status, msg=''): ...@@ -378,5 +376,5 @@ def imageinput(element, value, status, msg=''):
'state' : status, # to change 'state' : status, # to change
'msg': msg, # to change 'msg': msg, # to change
} }
html=render_to_string("imageinput.html", context) html = render_template("imageinput.html", context)
return etree.XML(html) return etree.XML(html)
...@@ -256,8 +256,7 @@ def sympy_check2(): ...@@ -256,8 +256,7 @@ def sympy_check2():
self.expect = xml.get('expect') or xml.get('answer') self.expect = xml.get('expect') or xml.get('answer')
self.myid = xml.get('id') self.myid = xml.get('id')
if settings.DEBUG: log.debug('answer_ids=%s' % self.answer_ids)
log.info('answer_ids=%s' % self.answer_ids)
# the <answer>...</answer> stanza should be local to the current <customresponse>. So try looking there first. # the <answer>...</answer> stanza should be local to the current <customresponse>. So try looking there first.
self.code = None self.code = None
...@@ -271,7 +270,7 @@ def sympy_check2(): ...@@ -271,7 +270,7 @@ def sympy_check2():
# ie the comparison function is defined in the <script>...</script> stanza instead # ie the comparison function is defined in the <script>...</script> stanza instead
cfn = xml.get('cfn') cfn = xml.get('cfn')
if cfn: if cfn:
if settings.DEBUG: log.info("cfn = %s" % cfn) log.debug("cfn = %s" % cfn)
if cfn in context: if cfn in context:
self.code = context[cfn] self.code = context[cfn]
else: else:
...@@ -346,7 +345,7 @@ def sympy_check2(): ...@@ -346,7 +345,7 @@ def sympy_check2():
# this is an interface to the Tutor2 check functions # this is an interface to the Tutor2 check functions
fn = self.code fn = self.code
ret = None ret = None
if settings.DEBUG: log.info(" submission = %s" % submission) log.debug(" submission = %s" % submission)
try: try:
answer_given = submission[0] if (len(idset)==1) else submission answer_given = submission[0] if (len(idset)==1) else submission
# handle variable number of arguments in check function, for backwards compatibility # handle variable number of arguments in check function, for backwards compatibility
...@@ -358,9 +357,8 @@ def sympy_check2(): ...@@ -358,9 +357,8 @@ def sympy_check2():
for argname in argspec.args[nargs:]: for argname in argspec.args[nargs:]:
kwargs[argname] = self.context[argname] if argname in self.context else None kwargs[argname] = self.context[argname] if argname in self.context else None
if settings.DEBUG: log.debug('[customresponse] answer_given=%s' % answer_given)
log.debug('[courseware.capa.responsetypes.customresponse] answer_given=%s' % answer_given) log.debug('nargs=%d, args=%s, kwargs=%s' % (nargs,args,kwargs))
log.info('nargs=%d, args=%s, kwargs=%s' % (nargs,args,kwargs))
ret = fn(*args[:nargs],**kwargs) ret = fn(*args[:nargs],**kwargs)
except Exception,err: except Exception,err:
...@@ -368,7 +366,7 @@ def sympy_check2(): ...@@ -368,7 +366,7 @@ def sympy_check2():
# print "context = ",self.context # print "context = ",self.context
log.error(traceback.format_exc()) log.error(traceback.format_exc())
raise Exception,"oops in customresponse (cfn) error %s" % err raise Exception,"oops in customresponse (cfn) error %s" % err
if settings.DEBUG: log.info("[courseware.capa.responsetypes.customresponse.get_score] ret = %s" % ret) log.debug("[courseware.capa.responsetypes.customresponse.get_score] ret = %s" % ret)
if type(ret)==dict: if type(ret)==dict:
correct = ['correct']*len(idset) if ret['ok'] else ['incorrect']*len(idset) correct = ['correct']*len(idset) if ret['ok'] else ['incorrect']*len(idset)
msg = ret['msg'] msg = ret['msg']
......
...@@ -10,9 +10,6 @@ import StringIO ...@@ -10,9 +10,6 @@ import StringIO
from datetime import timedelta from datetime import timedelta
from lxml import etree from lxml import etree
## TODO: Abstract out from Django
from mitxmako.shortcuts import render_to_string
from x_module import XModule, XModuleDescriptor from x_module import XModule, XModuleDescriptor
from capa.capa_problem import LoncapaProblem, StudentInputError from capa.capa_problem import LoncapaProblem, StudentInputError
log = logging.getLogger("mitx.courseware") log = logging.getLogger("mitx.courseware")
...@@ -73,10 +70,10 @@ class Module(XModule): ...@@ -73,10 +70,10 @@ class Module(XModule):
return self.lcp.get_max_score() return self.lcp.get_max_score()
def get_html(self): def get_html(self):
return render_to_string('problem_ajax.html', return self.system.render_template('problem_ajax.html', {
{'id':self.item_id, 'id': self.item_id,
'ajax_url':self.ajax_url, 'ajax_url': self.ajax_url,
}) })
def get_problem_html(self, encapsulate=True): def get_problem_html(self, encapsulate=True):
html = self.lcp.get_html() html = self.lcp.get_html()
...@@ -139,7 +136,7 @@ class Module(XModule): ...@@ -139,7 +136,7 @@ class Module(XModule):
'explain': explain, 'explain': explain,
} }
html=render_to_string('problem.html', context) html = self.system.render_template('problem.html', context)
if encapsulate: if encapsulate:
html = '<div id="problem_{id}" class="problem" data-url="{ajax_url}">'.format(id=self.item_id,ajax_url=self.ajax_url)+html+"</div>" html = '<div id="problem_{id}" class="problem" data-url="{ajax_url}">'.format(id=self.item_id,ajax_url=self.ajax_url)+html+"</div>"
......
import abc import abc
import logging import logging
from django.conf import settings
from collections import namedtuple from collections import namedtuple
log = logging.getLogger("mitx.courseware") log = logging.getLogger("mitx.courseware")
...@@ -11,6 +9,34 @@ log = logging.getLogger("mitx.courseware") ...@@ -11,6 +9,34 @@ log = logging.getLogger("mitx.courseware")
# Section either indicates the name of the problem or the name of the section # Section either indicates the name of the problem or the name of the section
Score = namedtuple("Score", "earned possible graded section") Score = namedtuple("Score", "earned possible graded section")
def aggregate_scores(scores, section_name="summary"):
"""
scores: A list of Score objects
returns: A tuple (all_total, graded_total).
all_total: A Score representing the total score summed over all input scores
graded_total: A Score representing the score summed over all graded input scores
"""
total_correct_graded = sum(score.earned for score in scores if score.graded)
total_possible_graded = sum(score.possible for score in scores if score.graded)
total_correct = sum(score.earned for score in scores)
total_possible = sum(score.possible for score in scores)
#regardless of whether or not it is graded
all_total = Score(total_correct,
total_possible,
False,
section_name)
#selecting only graded things
graded_total = Score(total_correct_graded,
total_possible_graded,
True,
section_name)
return all_total, graded_total
def grader_from_conf(conf): def grader_from_conf(conf):
""" """
This creates a CourseGrader from a configuration (such as in course_settings.py). This creates a CourseGrader from a configuration (such as in course_settings.py).
...@@ -162,18 +188,6 @@ class SingleSectionGrader(CourseGrader): ...@@ -162,18 +188,6 @@ class SingleSectionGrader(CourseGrader):
percent = 0.0 percent = 0.0
detail = "{name} - 0% (?/?)".format(name = self.name) detail = "{name} - 0% (?/?)".format(name = self.name)
if settings.GENERATE_PROFILE_SCORES:
points_possible = random.randrange(50, 100)
points_earned = random.randrange(40, points_possible)
percent = points_earned / float(points_possible)
detail = "{name} - {percent:.0%} ({earned:.3n}/{possible:.3n})".format( name = self.name,
percent = percent,
earned = float(points_earned),
possible = float(points_possible))
breakdown = [{'percent': percent, 'label': self.short_label, 'detail': detail, 'category': self.category, 'prominent': True}] breakdown = [{'percent': percent, 'label': self.short_label, 'detail': detail, 'category': self.category, 'prominent': True}]
return {'percent' : percent, return {'percent' : percent,
...@@ -244,17 +258,6 @@ class AssignmentFormatGrader(CourseGrader): ...@@ -244,17 +258,6 @@ class AssignmentFormatGrader(CourseGrader):
percentage = 0 percentage = 0
summary = "{section_type} {index} Unreleased - 0% (?/?)".format(index = i+1, section_type = self.section_type) summary = "{section_type} {index} Unreleased - 0% (?/?)".format(index = i+1, section_type = self.section_type)
if settings.GENERATE_PROFILE_SCORES:
points_possible = random.randrange(10, 50)
points_earned = random.randrange(5, points_possible)
percentage = points_earned / float(points_possible)
summary = "{section_type} {index} - {name} - {percent:.0%} ({earned:.3n}/{possible:.3n})".format(index = i+1,
section_type = self.section_type,
name = "Randomly Generated",
percent = percentage,
earned = float(points_earned),
possible = float(points_possible) )
short_label = "{short_label} {index:02d}".format(index = i+1, short_label = self.short_label) short_label = "{short_label} {index:02d}".format(index = i+1, short_label = self.short_label)
breakdown.append( {'percent': percentage, 'label': short_label, 'detail': summary, 'category': self.category} ) breakdown.append( {'percent': percentage, 'label': short_label, 'detail': summary, 'category': self.category} )
......
import json import json
import logging import logging
from mitxmako.shortcuts import render_to_response, render_to_string
from x_module import XModule, XModuleDescriptor from x_module import XModule, XModuleDescriptor
from lxml import etree from lxml import etree
...@@ -34,8 +32,7 @@ class Module(XModule): ...@@ -34,8 +32,7 @@ class Module(XModule):
except: # For backwards compatibility. TODO: Remove except: # For backwards compatibility. TODO: Remove
if self.DEBUG: if self.DEBUG:
log.info('[courseware.modules.html_module] filename=%s' % self.filename) log.info('[courseware.modules.html_module] filename=%s' % self.filename)
#return render_to_string(self.filename, {'id': self.item_id}) return self.system.render_template(self.filename, {'id': self.item_id}, namespace='course')
return render_to_string(self.filename, {'id': self.item_id},namespace='course')
def __init__(self, system, xml, item_id, state=None): def __init__(self, system, xml, item_id, state=None):
XModule.__init__(self, system, xml, item_id, state) XModule.__init__(self, system, xml, item_id, state)
......
...@@ -2,8 +2,6 @@ import json ...@@ -2,8 +2,6 @@ import json
from lxml import etree from lxml import etree
from mitxmako.shortcuts import render_to_string
from x_module import XModule, XModuleDescriptor from x_module import XModule, XModuleDescriptor
# HACK: This shouldn't be hard-coded to two types # HACK: This shouldn't be hard-coded to two types
...@@ -77,9 +75,9 @@ class Module(XModule): ...@@ -77,9 +75,9 @@ class Module(XModule):
'tag':self.xmltree.tag} 'tag':self.xmltree.tag}
if self.xmltree.tag in ['sequential', 'videosequence']: if self.xmltree.tag in ['sequential', 'videosequence']:
self.content=render_to_string('seq_module.html',params) self.content = self.system.render_template('seq_module.html', params)
if self.xmltree.tag == 'tab': if self.xmltree.tag == 'tab':
self.content=render_to_string('tab_module.html',params) self.content = self.system.render_template('tab_module.html', params)
self.rendered = True self.rendered = True
def __init__(self, system, xml, item_id, state=None): def __init__(self, system, xml, item_id, state=None):
......
import json import json
from mitxmako.shortcuts import render_to_string
from x_module import XModule, XModuleDescriptor from x_module import XModule, XModuleDescriptor
from lxml import etree from lxml import etree
...@@ -24,4 +22,4 @@ class Module(XModule): ...@@ -24,4 +22,4 @@ class Module(XModule):
xmltree = etree.fromstring(xml) xmltree = etree.fromstring(xml)
filename = xmltree[0].text filename = xmltree[0].text
params = dict(xmltree.items()) params = dict(xmltree.items())
self.html = render_to_string(filename, params, namespace = 'custom_tags') self.html = self.system.render_template(filename, params, namespace = 'custom_tags')
...@@ -13,9 +13,8 @@ import numpy ...@@ -13,9 +13,8 @@ import numpy
import xmodule import xmodule
import capa.calc as calc import capa.calc as calc
import capa.capa_problem as lcp import capa.capa_problem as lcp
import courseware.graders as graders from xmodule import graders
from courseware.graders import Score, CourseGrader, WeightedSubsectionsGrader, SingleSectionGrader, AssignmentFormatGrader from xmodule.graders import Score, aggregate_scores
from courseware.grades import aggregate_scores
from nose.plugins.skip import SkipTest from nose.plugins.skip import SkipTest
class I4xSystem(object): class I4xSystem(object):
......
import json import json
from mitxmako.shortcuts import render_to_response, render_to_string
from x_module import XModule, XModuleDescriptor from x_module import XModule, XModuleDescriptor
from lxml import etree from lxml import etree
...@@ -19,7 +17,9 @@ class Module(XModule): ...@@ -19,7 +17,9 @@ class Module(XModule):
return ["vertical", "problemset"] return ["vertical", "problemset"]
def get_html(self): def get_html(self):
return render_to_string('vert_module.html',{'items':self.contents}) return self.system.render_template('vert_module.html', {
'items': self.contents
})
def __init__(self, system, xml, item_id, state=None): def __init__(self, system, xml, item_id, state=None):
XModule.__init__(self, system, xml, item_id, state) XModule.__init__(self, system, xml, item_id, state)
......
...@@ -3,8 +3,6 @@ import logging ...@@ -3,8 +3,6 @@ import logging
from lxml import etree from lxml import etree
from mitxmako.shortcuts import render_to_response, render_to_string
from x_module import XModule, XModuleDescriptor from x_module import XModule, XModuleDescriptor
log = logging.getLogger("mitx.courseware.modules") log = logging.getLogger("mitx.courseware.modules")
...@@ -38,11 +36,13 @@ class Module(XModule): ...@@ -38,11 +36,13 @@ class Module(XModule):
return self.youtube return self.youtube
def get_html(self): def get_html(self):
return render_to_string('video.html',{'streams':self.video_list(), return self.system.render_template('video.html', {
'id':self.item_id, 'streams': self.video_list(),
'position':self.position, 'id': self.item_id,
'name':self.name, 'position': self.position,
'annotations':self.annotations}) 'name': self.name,
'annotations': self.annotations
})
def __init__(self, system, xml, item_id, state=None): def __init__(self, system, xml, item_id, state=None):
XModule.__init__(self, system, xml, item_id, state) XModule.__init__(self, system, xml, item_id, state)
......
from lxml import etree from lxml import etree
import courseware.progress
def dummy_track(event_type, event): def dummy_track(event_type, event):
pass pass
...@@ -71,11 +69,6 @@ class XModule(object): ...@@ -71,11 +69,6 @@ class XModule(object):
### Functions used in the LMS ### Functions used in the LMS
def get_completion(self):
''' This is mostly unimplemented.
It gives a progress indication -- e.g. 30 minutes of 1.5 hours watched. 3 of 5 problems done, etc. '''
return courseware.progress.completion()
def get_state(self): def get_state(self):
''' State of the object, as stored in the database ''' State of the object, as stored in the database
''' '''
......
...@@ -25,8 +25,8 @@ import types ...@@ -25,8 +25,8 @@ import types
from django.conf import settings from django.conf import settings
from courseware import global_course_settings from courseware import global_course_settings
from courseware import graders from xmodule import graders
from courseware.graders import Score from xmodule.graders import Score
from models import StudentModule from models import StudentModule
import courseware.content_parser as content_parser import courseware.content_parser as content_parser
import xmodule import xmodule
...@@ -116,7 +116,7 @@ def grade_sheet(student,coursename=None): ...@@ -116,7 +116,7 @@ def grade_sheet(student,coursename=None):
graded = False graded = False
scores.append( Score(correct,total, graded, p.get("name")) ) scores.append( Score(correct,total, graded, p.get("name")) )
section_total, graded_total = aggregate_scores(scores, s.get("name")) section_total, graded_total = graders.aggregate_scores(scores, s.get("name"))
#Add the graded total to totaled_scores #Add the graded total to totaled_scores
format = s.get('format', "") format = s.get('format', "")
subtitle = s.get('subtitle', format) subtitle = s.get('subtitle', format)
...@@ -146,27 +146,6 @@ def grade_sheet(student,coursename=None): ...@@ -146,27 +146,6 @@ def grade_sheet(student,coursename=None):
return {'courseware_summary' : chapters, return {'courseware_summary' : chapters,
'grade_summary' : grade_summary} 'grade_summary' : grade_summary}
def aggregate_scores(scores, section_name = "summary"):
total_correct_graded = sum(score.earned for score in scores if score.graded)
total_possible_graded = sum(score.possible for score in scores if score.graded)
total_correct = sum(score.earned for score in scores)
total_possible = sum(score.possible for score in scores)
#regardless of whether or not it is graded
all_total = Score(total_correct,
total_possible,
False,
section_name)
#selecting only graded things
graded_total = Score(total_correct_graded,
total_possible_graded,
True,
section_name)
return all_total, graded_total
def get_score(user, problem, cache, coursename=None): def get_score(user, problem, cache, coursename=None):
## HACK: assumes max score is fixed per problem ## HACK: assumes max score is fixed per problem
id = problem.get('id') id = problem.get('id')
......
...@@ -27,7 +27,7 @@ class I4xSystem(object): ...@@ -27,7 +27,7 @@ class I4xSystem(object):
of the courseware (e.g. import into other types of courseware, LMS, of the courseware (e.g. import into other types of courseware, LMS,
or if we want to have a sandbox server for user-contributed content) or if we want to have a sandbox server for user-contributed content)
''' '''
def __init__(self, ajax_url, track_function, render_function, filestore=None): def __init__(self, ajax_url, track_function, render_function, render_template, filestore=None):
self.ajax_url = ajax_url self.ajax_url = ajax_url
self.track_function = track_function self.track_function = track_function
if not filestore: if not filestore:
...@@ -37,6 +37,7 @@ class I4xSystem(object): ...@@ -37,6 +37,7 @@ class I4xSystem(object):
if settings.DEBUG: if settings.DEBUG:
log.info("[courseware.module_render.I4xSystem] filestore path = %s" % filestore) log.info("[courseware.module_render.I4xSystem] filestore path = %s" % filestore)
self.render_function = render_function self.render_function = render_function
self.render_template = render_template
self.exception404 = Http404 self.exception404 = Http404
self.DEBUG = settings.DEBUG self.DEBUG = settings.DEBUG
...@@ -117,6 +118,7 @@ def get_module(user, request, xml_module, module_object_preload, position=None): ...@@ -117,6 +118,7 @@ def get_module(user, request, xml_module, module_object_preload, position=None):
system = I4xSystem(track_function = make_track_function(request), system = I4xSystem(track_function = make_track_function(request),
render_function = lambda x: render_x_module(user, request, x, module_object_preload, position), render_function = lambda x: render_x_module(user, request, x, module_object_preload, position),
render_template = render_to_string,
ajax_url = ajax_url, ajax_url = ajax_url,
filestore = OSFS(data_root), filestore = OSFS(data_root),
) )
...@@ -225,6 +227,7 @@ def modx_dispatch(request, module=None, dispatch=None, id=None): ...@@ -225,6 +227,7 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
# Create the module # Create the module
system = I4xSystem(track_function = make_track_function(request), system = I4xSystem(track_function = make_track_function(request),
render_function = None, render_function = None,
render_template = render_to_string,
ajax_url = ajax_url, ajax_url = ajax_url,
filestore = OSFS(data_root), filestore = OSFS(data_root),
) )
......
...@@ -179,6 +179,7 @@ def quickedit(request, id=None, qetemplate='quickedit.html',coursename=None): ...@@ -179,6 +179,7 @@ def quickedit(request, id=None, qetemplate='quickedit.html',coursename=None):
# Create the module (instance of capa_module.Module) # Create the module (instance of capa_module.Module)
system = I4xSystem(track_function = make_track_function(request), system = I4xSystem(track_function = make_track_function(request),
render_function = None, render_function = None,
render_template = render_to_string,
ajax_url = ajax_url, ajax_url = ajax_url,
filestore = OSFS(settings.DATA_DIR + xp), filestore = OSFS(settings.DATA_DIR + xp),
#role = 'staff' if request.user.is_staff else 'student', # TODO: generalize this #role = 'staff' if request.user.is_staff else 'student', # TODO: generalize this
......
...@@ -58,10 +58,31 @@ task :pylint => LMS_REPORT_DIR do ...@@ -58,10 +58,31 @@ task :pylint => LMS_REPORT_DIR do
end end
end end
desc "Run all django tests on our djangoapps" [:lms].each do |system|
task :test => LMS_REPORT_DIR do task_name = "test_#{system}"
ENV['NOSE_XUNIT_FILE'] = File.join(LMS_REPORT_DIR, "nosetests.xml") report_dir = File.join(REPORT_DIR, task_name)
sh(django_admin(:lms, :test, 'test', *Dir['lms/djangoapps'].each)) directory report_dir
desc "Run all django tests on our djangoapps for the #{system}"
task task_name => report_dir do
ENV['NOSE_XUNIT_FILE'] = File.join(report_dir, "nosetests.xml")
sh(django_admin(:lms, :test, 'test', *Dir['lms/djangoapps'].each))
end
task :test => task_name
end
Dir["common/lib/*"].each do |lib|
task_name = "test_#{lib}"
report_dir = File.join(REPORT_DIR, task_name)
directory report_dir
desc "Run tests for common lib #{lib}"
task task_name do
ENV['NOSE_XUNIT_FILE'] = File.join(report_dir, "nosetests.xml")
sh("nosetests #{lib}")
end
task :test => task_name
end end
desc <<-desc desc <<-desc
......
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