diff --git a/djangoapps/courseware/capa/inputtypes.py b/djangoapps/courseware/capa/inputtypes.py
index 710ff04493..09255d14e9 100644
--- a/djangoapps/courseware/capa/inputtypes.py
+++ b/djangoapps/courseware/capa/inputtypes.py
@@ -253,16 +253,19 @@ def textbox(element, value, status, msg=''):
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.
- TODO: make this use rows and cols attribs, not size
'''
eid=element.get('id')
count = int(eid.split('_')[-2])-1 # HACK
size = element.get('size')
+ rows = element.get('rows') or '30'
+ cols = element.get('cols') or '80'
mode = element.get('mode') or 'python' # mode for CodeMirror, eg "python" or "xml"
linenumbers = element.get('linenumbers') # for CodeMirror
if not value: value = element.text # if no student input yet, then use the default input given by the problem
context = {'id':eid, 'value':value, 'state':status, 'count':count, 'size': size, 'msg':msg,
- 'mode':mode, 'linenumbers':linenumbers }
+ 'mode':mode, 'linenumbers':linenumbers,
+ 'rows':rows, 'cols':cols,
+ }
html=render_to_string("textbox.html", context)
return etree.XML(html)
diff --git a/djangoapps/courseware/capa/responsetypes.py b/djangoapps/courseware/capa/responsetypes.py
index 748e37f0bd..1fcd7b6625 100644
--- a/djangoapps/courseware/capa/responsetypes.py
+++ b/djangoapps/courseware/capa/responsetypes.py
@@ -471,13 +471,55 @@ class SymbolicResponse(CustomResponse):
#-----------------------------------------------------------------------------
class ExternalResponse(GenericResponse):
- """
- Grade the student's input using an external server.
+ '''
+ Grade the students input using an external server.
Typically used by coding problems.
- """
+
+ Example:
+
+
+
+
+
+
+ '''
def __init__(self, xml, context, system=None):
self.xml = xml
+ self.url = xml.get('url') or "http://eecs1.mit.edu:8889/pyloncapa" # FIXME - hardcoded URL
self.answer_ids = xml.xpath('//*[@id=$id]//textbox/@id|//*[@id=$id]//textline/@id',
id=xml.get('id'))
self.context = context
@@ -490,24 +532,29 @@ class ExternalResponse(GenericResponse):
else:
self.code = answer.text
- self.tests = xml.get('answer')
+ self.tests = xml.get('tests')
def get_score(self, student_answers):
- submission = [student_answers[k] for k in sorted(self.answer_ids)]
+ try:
+ submission = [student_answers[k] for k in sorted(self.answer_ids)]
+ except Exception,err:
+ log.error('Error %s: cannot get student answer for %s; student_answers=%s' % (err,self.answer_ids,student_answers))
+ raise Exception,err
+
self.context.update({'submission':submission})
xmlstr = etree.tostring(self.xml, pretty_print=True)
payload = {'xml': xmlstr,
- ### Question: Is this correct/what we want? Shouldn't this be a json.dumps?
- 'LONCAPA_student_response': ''.join(submission),
- 'LONCAPA_correct_answer': self.tests,
+ 'edX_cmd' : 'get_score',
+ 'edX_student_response': json.dumps(submission),
+ 'edX_tests': self.tests,
'processor' : self.code,
}
- # call external server; TODO: get URL from settings.py
- r = requests.post("http://eecs1.mit.edu:8889/pyloncapa",data=payload)
+ r = requests.post(self.url,data=payload) # call external server
+ if settings.DEBUG: log.info('response = %s' % r.text)
rxml = etree.fromstring(r.text) # response is XML; prase it
ad = rxml.find('awarddetail').text
admap = {'EXACT_ANS':'correct', # TODO: handle other loncapa responses
@@ -520,15 +567,32 @@ class ExternalResponse(GenericResponse):
# self.context['correct'] = ['correct','correct']
correct_map = dict(zip(sorted(self.answer_ids), self.context['correct']))
- # TODO: separate message for each answer_id?
- correct_map['msg'] = rxml.find('message').text.replace(' ',' ') # store message in correct_map
+ # store message in correct_map
+ correct_map['msg_%s' % self.answer_ids[0]] = rxml.find('message').text.replace(' ',' ')
return correct_map
def get_answers(self):
- # Since this is explicitly specified in the problem, this will
- # be handled by capa_problem
- return {}
+ '''
+ Use external server to get expected answers
+ '''
+ xmlstr = etree.tostring(self.xml, pretty_print=True)
+
+ payload = {'xml': xmlstr,
+ 'edX_cmd' : 'get_answers',
+ 'edX_tests': self.tests,
+ 'processor' : self.code,
+ }
+
+ r = requests.post(self.url,data=payload) # call external server
+
+ if settings.DEBUG: log.info('response = %s' % r.text)
+ rxml = etree.fromstring(r.text) # response is XML; prase it
+ exans = json.loads(rxml.find('expected').text)
+ if not (len(exans)==len(self.answer_ids)):
+ log.error('Expected %d answers from external server, only got %d!' % (len(self.answer_ids),len(exans)))
+ raise Exception,'Short response from external server'
+ return dict(zip(self.answer_ids,exans))
class StudentInputError(Exception):
pass
diff --git a/djangoapps/courseware/modules/capa_module.py b/djangoapps/courseware/modules/capa_module.py
index 54cb257440..e2ad68a41e 100644
--- a/djangoapps/courseware/modules/capa_module.py
+++ b/djangoapps/courseware/modules/capa_module.py
@@ -351,8 +351,15 @@ class Module(XModule):
self.tracker('save_problem_check', event_info)
+ try:
+ html = self.get_problem_html(encapsulate=False)
+ except Exception,err:
+ log.error('failed to generate html, error %s' % err)
+ raise Exception,err
+
return json.dumps({'success': success,
- 'contents': self.get_problem_html(encapsulate=False)})
+ 'contents': html,
+ })
def save_problem(self, get):
event_info = dict()
diff --git a/templates/textbox.html b/templates/textbox.html
index e6c147141c..d2e3bcc455 100644
--- a/templates/textbox.html
+++ b/templates/textbox.html
@@ -1,5 +1,5 @@