Newer
Older
% location)
self.matchers = [
parse_matcher(
vctx,
"%s, answer %d" % (location, i+1),
answer)
for i, answer in enumerate(page_desc.answers)]
if not any(matcher.correct_answer_text() is not None
for matcher in self.matchers):
raise ValidationError(
string_concat(
"%s: ",
_("no matcher is able to provide a plain-text "
"correct answer"))
% location)
def required_attrs(self):
return super(TextQuestion, self).required_attrs() + (
("answers", list),
)
def allowed_attrs(self):
return super(TextQuestion, self).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
.. 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.
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
.. 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(HumanGradedTextQuestion, self).__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(HumanGradedTextQuestion, self).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