Newer
Older
return (*super().required_attrs(), ("answers", list))
def allowed_attrs(self):
return (*super().allowed_attrs(), ("answer_explanation", "markup"))
def get_validators(self):
return self.matchers
def grade(self, page_context, page_data, answer_data, grade_data):
if answer_data is None:
return AnswerFeedback(correctness=0,
feedback=gettext("No answer provided."))
answer = answer_data["answer"]
# Must start with 'None' to allow matcher to set feedback for zero
# correctness.
afb = None
Andreas Klöckner
committed
for matcher in self.matchers:
try:
matcher.validate(answer)
except forms.ValidationError:
continue
Andreas Klöckner
committed
matcher_afb = matcher.grade(answer)
if matcher_afb.correctness is not None:
if afb is None:
afb = matcher_afb
elif matcher_afb.correctness > afb.correctness:
afb = matcher_afb
if afb is None:
afb = AnswerFeedback(0)
Andreas Klöckner
committed
return afb
def correct_answer(self, page_context, page_data, answer_data, grade_data):
# FIXME: Could use 'best' match to answer
for matcher in self.matchers: # pragma: no branch
unspec_correct_answer_text = matcher.correct_answer_text()
if unspec_correct_answer_text is not None:
break
assert unspec_correct_answer_text
result = CORRECT_ANSWER_PATTERN % unspec_correct_answer_text
if hasattr(self.page_desc, "answer_explanation"):
result += markup_to_html(page_context, self.page_desc.answer_explanation)
return result
Andreas Klöckner
committed
def _is_case_sensitive(self):
return any(matcher.is_case_sensitive for matcher in self.matchers)
# }}}
# {{{ human-graded text question
class HumanGradedTextQuestion(TextQuestionBase, PageBaseWithValue,
PageBaseWithHumanTextFeedback, PageBaseWithCorrectAnswer):
"""
A page asking for a textual answer, with human-graded feedback.
Supports automatic computation of point values from textual feedback.
See :ref:`points-from-feedback`.
.. attribute:: id
|id-page-attr|
.. attribute:: type
``HumanGradedTextQuestion``
.. attribute:: is_optional_page
|is-optional-page-attr|
.. attribute:: access_rules
|access-rules-page-attr|
.. attribute:: title
|title-page-attr|
.. attribute:: value
|value-page-attr|
.. attribute:: prompt
The page's prompt, written in :ref:`markup`.
.. attribute:: widget
.. attribute:: initial_text
Text with which to prepopulate the input widget.
.. attribute:: validators
Optional.
TODO
.. attribute:: correct_answer
Optional.
Content that is revealed when answers are visible
(see :ref:`flow-permissions`). Written in :ref:`markup`.
.. attribute:: rubric
Required.
The grading guideline for this question, in :ref:`markup`.
"""
def __init__(self, vctx, location, page_desc):
super().__init__(vctx, location, page_desc)
self.validators = [
parse_validator(
vctx,
"%s, validator %d" % (location, i+1),
for i, answer in enumerate(
getattr(page_desc, "validators", []))]
def allowed_attrs(self):
return (*super().allowed_attrs(), ("validators", list))
def human_feedback_point_value(self, page_context, page_data):
return self.max_points(page_data)
def get_validators(self):
return self.validators