Commit 9508b3f9 by Sarina Canelake

pep8/pylint fixes for capa

parent 862beafd
...@@ -655,6 +655,7 @@ class ChoiceResponse(LoncapaResponse): ...@@ -655,6 +655,7 @@ class ChoiceResponse(LoncapaResponse):
response_tag = 'choiceresponse' response_tag = 'choiceresponse'
max_inputfields = 1 max_inputfields = 1
allowed_inputfields = ['checkboxgroup', 'radiogroup'] allowed_inputfields = ['checkboxgroup', 'radiogroup']
correct_choices = None
def setup_response(self): def setup_response(self):
...@@ -706,6 +707,7 @@ class MultipleChoiceResponse(LoncapaResponse): ...@@ -706,6 +707,7 @@ class MultipleChoiceResponse(LoncapaResponse):
response_tag = 'multiplechoiceresponse' response_tag = 'multiplechoiceresponse'
max_inputfields = 1 max_inputfields = 1
allowed_inputfields = ['choicegroup'] allowed_inputfields = ['choicegroup']
correct_choices = None
def setup_response(self): def setup_response(self):
# call secondary setup for MultipleChoice questions, to set name # call secondary setup for MultipleChoice questions, to set name
...@@ -791,6 +793,7 @@ class OptionResponse(LoncapaResponse): ...@@ -791,6 +793,7 @@ class OptionResponse(LoncapaResponse):
response_tag = 'optionresponse' response_tag = 'optionresponse'
hint_tag = 'optionhint' hint_tag = 'optionhint'
allowed_inputfields = ['optioninput'] allowed_inputfields = ['optioninput']
answer_fields = None
def setup_response(self): def setup_response(self):
self.answer_fields = self.inputfields self.answer_fields = self.inputfields
...@@ -949,6 +952,7 @@ class StringResponse(LoncapaResponse): ...@@ -949,6 +952,7 @@ class StringResponse(LoncapaResponse):
allowed_inputfields = ['textline'] allowed_inputfields = ['textline']
required_attributes = ['answer'] required_attributes = ['answer']
max_inputfields = 1 max_inputfields = 1
correct_answer = None
def setup_response(self): def setup_response(self):
self.correct_answer = contextualize_text( self.correct_answer = contextualize_text(
...@@ -974,7 +978,7 @@ class StringResponse(LoncapaResponse): ...@@ -974,7 +978,7 @@ class StringResponse(LoncapaResponse):
hxml.get('answer'), self.context).strip() hxml.get('answer'), self.context).strip()
if self.check_string(correct_answer, given): if self.check_string(correct_answer, given):
hints_to_show.append(name) hints_to_show.append(name)
log.debug('hints_to_show = %s' % hints_to_show) log.debug('hints_to_show = %s', hints_to_show)
return hints_to_show return hints_to_show
def get_answers(self): def get_answers(self):
...@@ -996,6 +1000,8 @@ class CustomResponse(LoncapaResponse): ...@@ -996,6 +1000,8 @@ class CustomResponse(LoncapaResponse):
'drag_and_drop_input', 'editamoleculeinput', 'drag_and_drop_input', 'editamoleculeinput',
'designprotein2dinput', 'editageneinput', 'designprotein2dinput', 'editageneinput',
'annotationinput', 'jsinput', 'formulaequationinput'] 'annotationinput', 'jsinput', 'formulaequationinput']
code = None
expect = None
def setup_response(self): def setup_response(self):
xml = self.xml xml = self.xml
...@@ -1004,7 +1010,7 @@ class CustomResponse(LoncapaResponse): ...@@ -1004,7 +1010,7 @@ class CustomResponse(LoncapaResponse):
# that # that
self.expect = xml.get('expect') or xml.get('answer') self.expect = xml.get('expect') or xml.get('answer')
log.debug('answer_ids=%s' % self.answer_ids) log.debug('answer_ids=%s', self.answer_ids)
# the <answer>...</answer> stanza should be local to the current <customresponse>. # the <answer>...</answer> stanza should be local to the current <customresponse>.
# So try looking there first. # So try looking there first.
...@@ -1020,7 +1026,7 @@ class CustomResponse(LoncapaResponse): ...@@ -1020,7 +1026,7 @@ class CustomResponse(LoncapaResponse):
# <script>...</script> stanza instead # <script>...</script> stanza instead
cfn = xml.get('cfn') cfn = xml.get('cfn')
if cfn: if cfn:
log.debug("cfn = %s" % cfn) log.debug("cfn = %s", cfn)
# This is a bit twisty. We used to grab the cfn function from # This is a bit twisty. We used to grab the cfn function from
# the context, but now that we sandbox Python execution, we # the context, but now that we sandbox Python execution, we
...@@ -1055,7 +1061,7 @@ class CustomResponse(LoncapaResponse): ...@@ -1055,7 +1061,7 @@ class CustomResponse(LoncapaResponse):
if not self.code: if not self.code:
if answer is None: if answer is None:
log.error("[courseware.capa.responsetypes.customresponse] missing" log.error("[courseware.capa.responsetypes.customresponse] missing"
" code checking script! id=%s" % self.id) " code checking script! id=%s", self.id)
self.code = '' self.code = ''
else: else:
answer_src = answer.get('src') answer_src = answer.get('src')
...@@ -1071,7 +1077,7 @@ class CustomResponse(LoncapaResponse): ...@@ -1071,7 +1077,7 @@ class CustomResponse(LoncapaResponse):
of each key removed (the string before the first "_"). of each key removed (the string before the first "_").
''' '''
log.debug('%s: student_answers=%s' % (unicode(self), student_answers)) log.debug('%s: student_answers=%s', unicode(self), student_answers)
# ordered list of answer id's # ordered list of answer id's
idset = sorted(self.answer_ids) idset = sorted(self.answer_ids)
...@@ -1182,10 +1188,10 @@ class CustomResponse(LoncapaResponse): ...@@ -1182,10 +1188,10 @@ class CustomResponse(LoncapaResponse):
answer_given = submission[0] if (len(idset) == 1) else submission answer_given = submission[0] if (len(idset) == 1) else submission
kwnames = self.xml.get("cfn_extra_args", "").split() kwnames = self.xml.get("cfn_extra_args", "").split()
kwargs = {n: self.context.get(n) for n in kwnames} kwargs = {n: self.context.get(n) for n in kwnames}
log.debug(" submission = %s" % submission) log.debug(" submission = %s", submission)
try: try:
ret = fn(self.expect, answer_given, **kwargs) ret = fn(self.expect, answer_given, **kwargs)
except Exception as err: except Exception as err: # pylint: disable=broad-except
self._handle_exec_exception(err) self._handle_exec_exception(err)
log.debug( log.debug(
"[courseware.capa.responsetypes.customresponse.get_score] ret = %s", "[courseware.capa.responsetypes.customresponse.get_score] ret = %s",
...@@ -1340,22 +1346,21 @@ class SymbolicResponse(CustomResponse): ...@@ -1340,22 +1346,21 @@ class SymbolicResponse(CustomResponse):
debug=self.context.get('debug'), debug=self.context.get('debug'),
) )
except Exception as err: except Exception as err:
log.error("oops in symbolicresponse (cfn) error %s" % err) log.error("oops in symbolicresponse (cfn) error %s", err)
log.error(traceback.format_exc()) log.error(traceback.format_exc())
raise Exception("oops in symbolicresponse (cfn) error %s" % err) raise Exception("oops in symbolicresponse (cfn) error %s", err)
self.context['messages'][0] = self.clean_message_html(ret['msg']) self.context['messages'][0] = self.clean_message_html(ret['msg'])
self.context['correct'] = ['correct' if ret['ok'] else 'incorrect'] * len(idset) self.context['correct'] = ['correct' if ret['ok'] else 'incorrect'] * len(idset)
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
""" ## ScoreMessage named tuple ##
valid: Flag indicating valid score_msg format (Boolean) ## valid: Flag indicating valid score_msg format (Boolean)
correct: Correctness of submission (Boolean) ## correct: Correctness of submission (Boolean)
score: Points to be assigned (numeric, can be float) ## score: Points to be assigned (numeric, can be float)
msg: Message from grader to display to student (string) ## msg: Message from grader to display to student (string)
"""
ScoreMessage = namedtuple('ScoreMessage', ScoreMessage = namedtuple('ScoreMessage', ['valid', 'correct', 'points', 'msg']) # pylint: disable=invalid-name
['valid', 'correct', 'points', 'msg'])
class CodeResponse(LoncapaResponse): class CodeResponse(LoncapaResponse):
...@@ -1377,6 +1382,11 @@ class CodeResponse(LoncapaResponse): ...@@ -1377,6 +1382,11 @@ class CodeResponse(LoncapaResponse):
response_tag = 'coderesponse' response_tag = 'coderesponse'
allowed_inputfields = ['textbox', 'filesubmission', 'matlabinput'] allowed_inputfields = ['textbox', 'filesubmission', 'matlabinput']
max_inputfields = 1 max_inputfields = 1
payload = None
initial_display = None
url = None
answer = None
queue_name = None
def setup_response(self): def setup_response(self):
''' '''
...@@ -1427,8 +1437,8 @@ class CodeResponse(LoncapaResponse): ...@@ -1427,8 +1437,8 @@ class CodeResponse(LoncapaResponse):
except Exception as err: except Exception as err:
log.error( log.error(
'Error in CodeResponse %s: cannot get student answer for %s;' 'Error in CodeResponse %s: cannot get student answer for %s;'
' student_answers=%s' % ' student_answers=%s',
(err, self.answer_id, convert_files_to_filenames(student_answers)) err, self.answer_id, convert_files_to_filenames(student_answers)
) )
raise Exception(err) raise Exception(err)
...@@ -1511,9 +1521,8 @@ class CodeResponse(LoncapaResponse): ...@@ -1511,9 +1521,8 @@ class CodeResponse(LoncapaResponse):
return cmap return cmap
def update_score(self, score_msg, oldcmap, queuekey): def update_score(self, score_msg, oldcmap, queuekey):
"""Updates the user's score based on the returned message from the grader."""
(valid_score_msg, correct, points, (valid_score_msg, correct, points, msg) = self._parse_score_msg(score_msg)
msg) = self._parse_score_msg(score_msg)
if not valid_score_msg: if not valid_score_msg:
oldcmap.set(self.answer_id, oldcmap.set(self.answer_id,
msg='Invalid grader reply. Please contact the course staff.') msg='Invalid grader reply. Please contact the course staff.')
...@@ -1536,8 +1545,11 @@ class CodeResponse(LoncapaResponse): ...@@ -1536,8 +1545,11 @@ class CodeResponse(LoncapaResponse):
self.answer_id, npoints=points, correctness=correctness, self.answer_id, npoints=points, correctness=correctness,
msg=msg.replace('&nbsp;', '&#160;'), queuestate=None) msg=msg.replace('&nbsp;', '&#160;'), queuestate=None)
else: else:
log.debug('CodeResponse: queuekey %s does not match for answer_id=%s.' % log.debug(
(queuekey, self.answer_id)) 'CodeResponse: queuekey %s does not match for answer_id=%s.',
queuekey,
self.answer_id
)
return oldcmap return oldcmap
...@@ -1546,6 +1558,10 @@ class CodeResponse(LoncapaResponse): ...@@ -1546,6 +1558,10 @@ class CodeResponse(LoncapaResponse):
return {self.answer_id: anshtml} return {self.answer_id: anshtml}
def get_initial_display(self): def get_initial_display(self):
"""
The course author can specify an initial display
to be displayed the code response box.
"""
return {self.answer_id: self.initial_display} return {self.answer_id: self.initial_display}
def _parse_score_msg(self, score_msg): def _parse_score_msg(self, score_msg):
...@@ -1566,11 +1582,11 @@ class CodeResponse(LoncapaResponse): ...@@ -1566,11 +1582,11 @@ class CodeResponse(LoncapaResponse):
score_result = json.loads(score_msg) score_result = json.loads(score_msg)
except (TypeError, ValueError): except (TypeError, ValueError):
log.error("External grader message should be a JSON-serialized dict." log.error("External grader message should be a JSON-serialized dict."
" Received score_msg = %s" % score_msg) " Received score_msg = %s", score_msg)
return fail return fail
if not isinstance(score_result, dict): if not isinstance(score_result, dict):
log.error("External grader message should be a JSON-serialized dict." log.error("External grader message should be a JSON-serialized dict."
" Received score_result = %s" % score_result) " Received score_result = %s", score_result)
return fail return fail
for tag in ['correct', 'score', 'msg']: for tag in ['correct', 'score', 'msg']:
if tag not in score_result: if tag not in score_result:
...@@ -1585,9 +1601,9 @@ class CodeResponse(LoncapaResponse): ...@@ -1585,9 +1601,9 @@ class CodeResponse(LoncapaResponse):
msg = score_result['msg'] msg = score_result['msg']
try: try:
etree.fromstring(msg) etree.fromstring(msg)
except etree.XMLSyntaxError as err: except etree.XMLSyntaxError as _err:
log.error("Unable to parse external grader message as valid" log.error("Unable to parse external grader message as valid"
" XML: score_msg['msg']=%s" % msg) " XML: score_msg['msg']=%s", msg)
return fail return fail
return (True, score_result['correct'], score_result['score'], msg) return (True, score_result['correct'], score_result['score'], msg)
......
"""Implements basics of Capa, including class CapaModule."""
import cgi import cgi
import datetime import datetime
import hashlib import hashlib
...@@ -40,11 +41,11 @@ def randomization_bin(seed, problem_id): ...@@ -40,11 +41,11 @@ def randomization_bin(seed, problem_id):
interesting. To avoid having sets of students that always get the same problems, interesting. To avoid having sets of students that always get the same problems,
we'll combine the system's per-student seed with the problem id in picking the bin. we'll combine the system's per-student seed with the problem id in picking the bin.
""" """
h = hashlib.sha1() r_hash = hashlib.sha1()
h.update(str(seed)) r_hash.update(str(seed))
h.update(str(problem_id)) r_hash.update(str(problem_id))
# get the first few digits of the hash, convert to an int, then mod. # get the first few digits of the hash, convert to an int, then mod.
return int(h.hexdigest()[:7], 16) % NUM_RANDOMIZATION_BINS return int(r_hash.hexdigest()[:7], 16) % NUM_RANDOMIZATION_BINS
class Randomization(String): class Randomization(String):
...@@ -220,7 +221,7 @@ class CapaModule(CapaFields, XModule): ...@@ -220,7 +221,7 @@ class CapaModule(CapaFields, XModule):
if self.seed is None: if self.seed is None:
self.seed = self.lcp.seed self.seed = self.lcp.seed
except Exception as err: except Exception as err: # pylint: disable=broad-except
msg = u'cannot create LoncapaProblem {loc}: {err}'.format( msg = u'cannot create LoncapaProblem {loc}: {err}'.format(
loc=self.location.url(), err=err) loc=self.location.url(), err=err)
# TODO (vshnayder): do modules need error handlers too? # TODO (vshnayder): do modules need error handlers too?
...@@ -318,9 +319,9 @@ class CapaModule(CapaFields, XModule): ...@@ -318,9 +319,9 @@ class CapaModule(CapaFields, XModule):
""" """
For now, just return score / max_score For now, just return score / max_score
""" """
d = self.get_score() score_dict = self.get_score()
score = d['score'] score = score_dict['score']
total = d['total'] total = score_dict['total']
if total > 0: if total > 0:
if self.weight is not None: if self.weight is not None:
...@@ -525,7 +526,7 @@ class CapaModule(CapaFields, XModule): ...@@ -525,7 +526,7 @@ class CapaModule(CapaFields, XModule):
# If we cannot construct the problem HTML, # If we cannot construct the problem HTML,
# then generate an error message instead. # then generate an error message instead.
except Exception as err: except Exception as err: # pylint: disable=broad-except
html = self.handle_problem_html_error(err) html = self.handle_problem_html_error(err)
# The convention is to pass the name of the check button # The convention is to pass the name of the check button
...@@ -610,11 +611,11 @@ class CapaModule(CapaFields, XModule): ...@@ -610,11 +611,11 @@ class CapaModule(CapaFields, XModule):
result = handlers[dispatch](data) result = handlers[dispatch](data)
except NotFoundError as err: except NotFoundError as err:
_, _, traceback_obj = sys.exc_info() _, _, traceback_obj = sys.exc_info() # pylint: disable=redefined-outer-name
raise ProcessingError, (not_found_error_message, err), traceback_obj raise ProcessingError, (not_found_error_message, err), traceback_obj
except Exception as err: except Exception as err:
_, _, traceback_obj = sys.exc_info() _, _, traceback_obj = sys.exc_info() # pylint: disable=redefined-outer-name
raise ProcessingError, (generic_error_message, err), traceback_obj raise ProcessingError, (generic_error_message, err), traceback_obj
after = self.get_progress() after = self.get_progress()
...@@ -668,8 +669,8 @@ class CapaModule(CapaFields, XModule): ...@@ -668,8 +669,8 @@ class CapaModule(CapaFields, XModule):
""" """
True iff full points True iff full points
""" """
d = self.get_score() score_dict = self.get_score()
return d['score'] == d['total'] return score_dict['score'] == score_dict['total']
def answer_available(self): def answer_available(self):
""" """
...@@ -757,7 +758,7 @@ class CapaModule(CapaFields, XModule): ...@@ -757,7 +758,7 @@ class CapaModule(CapaFields, XModule):
self.set_state_from_lcp() self.set_state_from_lcp()
return response return response
def get_answer(self, data): def get_answer(self, _data):
""" """
For the "show answer" button. For the "show answer" button.
...@@ -797,7 +798,6 @@ class CapaModule(CapaFields, XModule): ...@@ -797,7 +798,6 @@ class CapaModule(CapaFields, XModule):
""" """
return {'html': self.get_problem_html(encapsulate=False)} return {'html': self.get_problem_html(encapsulate=False)}
@staticmethod @staticmethod
def make_dict_of_responses(data): def make_dict_of_responses(data):
""" """
...@@ -840,7 +840,7 @@ class CapaModule(CapaFields, XModule): ...@@ -840,7 +840,7 @@ class CapaModule(CapaFields, XModule):
# We only want to consider each key a single time, so we use set(data.keys()) # We only want to consider each key a single time, so we use set(data.keys())
for key in set(data.keys()): for key in set(data.keys()):
# e.g. input_resistor_1 ==> resistor_1 # e.g. input_resistor_1 ==> resistor_1
_, _, name = key.partition('_') _, _, name = key.partition('_') # pylint: disable=redefined-outer-name
# If key has no underscores, then partition # If key has no underscores, then partition
# will return (key, '', '') # will return (key, '', '')
......
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