def process_choice_string(cls, page_context, s): s = remove_prefix(cls.CORRECT_TAG, s) s = markup_to_html(page_context, s) # allow HTML in option s = mark_safe(s) return s
def get_question(self, page_context, page_data): # for correct render of question with more than one # paragraph, remove heading <p> tags and change </p> # to line break. return markup_to_html( page_context, self.page_desc.question, ).replace("<p>", "").replace("</p>", "<br/>")
def process_choice_string(cls, page_context, s): if not isinstance(s, str): s = str(s) s = markup_to_html(page_context, s) # allow HTML in option s = mark_safe(s) return s
def correct_answer(self, page_context, page_data, answer_data, grade_data): corr_idx_list = self.unpermuted_correct_indices() result = (string_concat(_("The correct answer is"), ": %s.") % self.get_answer_html(page_context, corr_idx_list)) if hasattr(self.page_desc, "answer_explanation"): result += markup_to_html(page_context, self.page_desc.answer_explanation) return result
def correct_answer(self, page_context, page_data, answer_data, grade_data): corr_idx = self.unpermuted_correct_indices()[0] result = (string_concat(_("A correct answer is"), ": '%s'.") % self.process_choice_string( page_context, self.choices[corr_idx].text)) if hasattr(self.page_desc, "answer_explanation"): result += markup_to_html(page_context, self.page_desc.answer_explanation) return result
def correct_answer(self, page_context, page_data, answer_data, grade_data): result = "" if hasattr(self.page_desc, "correct_code_explanation"): result += markup_to_html(page_context, self.page_desc.correct_code_explanation) if hasattr(self.page_desc, "correct_code"): result += "".join([_("The following code is a valid answer"), ": <pre>%s</pre>"]) % escape( self.page_desc.correct_code ) return result
def process_choice_string(cls, page_context, s): if not isinstance(s, str): s = str(s) s = remove_prefix(cls.CORRECT_TAG, s) s_contain_p_tag = "<p>" in s s = markup_to_html(page_context, s) # allow HTML in option if not s_contain_p_tag: s = s.replace("<p>", "").replace("</p>", "") s = mark_safe(s) return s
def body(self, page_context, page_data): from django.template.loader import render_to_string return render_to_string( "course/prompt-code-question.html", { "prompt_html": markup_to_html(page_context, self.page_desc.prompt), "initial_code": self._initial_code(), "show_setup_code": getattr(self.page_desc, "show_setup_code", False), "setup_code": getattr(self.page_desc, "setup_code", ""), "show_test_code": getattr(self.page_desc, "show_test_code", False), "test_code": getattr(self.page_desc, "test_code", ""), }, )
def correct_answer(self, page_context, page_data, answer_data, grade_data): # FIXME: Could use 'best' match to answer for matcher in self.matchers: 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
def correct_answer(self, page_context, page_data, answer_data, grade_data): corr_idx_list = self.unpermuted_correct_indices() always_correct_idx_list = self.unpermuted_always_correct_indices() result = (string_concat(_("The correct answer is"), ": %s") % self.get_answer_html(page_context, corr_idx_list)) if len(always_correct_idx_list) > 0: result = (string_concat(result, string_concat(_("Additional acceptable options are"), ": %s") % self.get_answer_html(page_context, always_correct_idx_list))) if hasattr(self.page_desc, "answer_explanation"): result += markup_to_html(page_context, self.page_desc.answer_explanation) return result
def correct_answer(self, page_context, page_data, answer_data, grade_data): # FIXME: Could use 'best' match to answer CA_PATTERN = string_concat(_("A correct answer is"), ": '%s'.") # noqa for matcher in self.matchers: unspec_correct_answer_text = matcher.correct_answer_text() if unspec_correct_answer_text is not None: break assert unspec_correct_answer_text result = CA_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
def process_choice_string(cls, s): if not isinstance(s, str): s = str(s) s = remove_prefix(cls.CORRECT_TAG, s) from course.content import markup_to_html s_contain_p_tag = "<p>" in s s = markup_to_html( course=None, repo=None, commit_sha=None, text=s, ) # allow HTML in option if not s_contain_p_tag: s = s.replace("<p>", "").replace("</p>", "") s = mark_safe(s) return s
def correct_answer(self, page_context, page_data, answer_data, grade_data): # FIXME: Could use 'best' match to answer cor_answer_output = self.get_question(page_context, page_data) for idx, wrapped in enumerate(self.embedded_wrapped_name_list): correct_answer_i = self.answer_instance_list[idx] \ .get_correct_answer_text(page_context) cor_answer_output = cor_answer_output.replace( wrapped, "<strong>" + correct_answer_i + "</strong>") CA_PATTERN = string_concat(_("A correct answer is"), ": <br/> %s") # noqa result = CA_PATTERN % cor_answer_output if hasattr(self.page_desc, "answer_explanation"): result += markup_to_html(page_context, self.page_desc.answer_explanation) return result
def grade(self, page_context, page_data, answer_data, grade_data): if answer_data is None: return AnswerFeedback(correctness=0, feedback=_("No answer provided.")) if grade_data is not None and not grade_data["released"]: grade_data = None code_feedback = PythonCodeQuestion.grade(self, page_context, page_data, answer_data, grade_data) human_points = self.page_desc.human_feedback_value code_points = self.page_desc.value - human_points correctness = None percentage = None if ( code_feedback is not None and code_feedback.correctness is not None and grade_data is not None and grade_data["grade_percent"] is not None ): correctness = ( code_feedback.correctness * code_points + grade_data["grade_percent"] / 100 * self.page_desc.human_feedback_value ) / self.page_desc.value percentage = correctness * 100 elif ( self.page_desc.human_feedback_value == self.page_desc.value and grade_data is not None and grade_data["grade_percent"] is not None ): correctness = grade_data["grade_percent"] / 100 percentage = correctness * 100 human_feedback_percentage = None human_feedback_text = None human_feedback_points = None if grade_data is not None: if grade_data["feedback_text"] is not None: human_feedback_text = markup_to_html(page_context, grade_data["feedback_text"]) human_feedback_percentage = grade_data["grade_percent"] if human_feedback_percentage is not None: human_feedback_points = human_feedback_percentage / 100.0 * human_points code_feedback_points = None if code_feedback is not None and code_feedback.correctness is not None: code_feedback_points = code_feedback.correctness * code_points from django.template.loader import render_to_string feedback = render_to_string( "course/feedback-code-with-human.html", { "percentage": percentage, "code_feedback": code_feedback, "code_feedback_points": code_feedback_points, "code_points": code_points, "human_feedback_text": human_feedback_text, "human_feedback_points": human_feedback_points, "human_points": human_points, }, ) return AnswerFeedback(correctness=correctness, feedback=feedback, bulk_feedback=code_feedback.bulk_feedback)
def grade(self, page_context, page_data, answer_data, grade_data): if answer_data is None: return AnswerFeedback(correctness=0, feedback=_("No answer provided.")) if grade_data is not None and not grade_data["released"]: grade_data = None code_feedback = PythonCodeQuestion.grade(self, page_context, page_data, answer_data, grade_data) human_points = self.page_desc.human_feedback_value code_points = self.page_desc.value - human_points correctness = None percentage = None if (code_feedback is not None and code_feedback.correctness is not None and grade_data is not None and grade_data["grade_percent"] is not None): correctness = ( code_feedback.correctness * code_points + grade_data["grade_percent"] / 100 * self.page_desc.human_feedback_value) / self.page_desc.value percentage = correctness * 100 elif (self.page_desc.human_feedback_value == self.page_desc.value and grade_data is not None and grade_data["grade_percent"] is not None): correctness = grade_data["grade_percent"] / 100 percentage = correctness * 100 human_feedback_percentage = None human_feedback_text = None human_feedback_points = None if grade_data is not None: if grade_data["feedback_text"] is not None: human_feedback_text = markup_to_html( page_context, grade_data["feedback_text"]) human_feedback_percentage = grade_data["grade_percent"] if human_feedback_percentage is not None: human_feedback_points = (human_feedback_percentage / 100. * human_points) code_feedback_points = None if (code_feedback is not None and code_feedback.correctness is not None): code_feedback_points = code_feedback.correctness * code_points from django.template.loader import render_to_string feedback = render_to_string( "course/feedback-code-with-human.html", { "percentage": percentage, "code_feedback": code_feedback, "code_feedback_points": code_feedback_points, "code_points": code_points, "human_feedback_text": human_feedback_text, "human_feedback_points": human_feedback_points, "human_points": human_points, }) return AnswerFeedback(correctness=correctness, feedback=feedback, bulk_feedback=code_feedback.bulk_feedback)
def correct_answer(self, page_context, page_data, answer_data, grade_data): if hasattr(self.page_desc, "answer_comment"): return markup_to_html(page_context, self.page_desc.answer_comment) else: return None
def __init__(self, vctx, location, page_desc): super(InlineMultiQuestion, self).__init__( vctx, location, page_desc) self.embedded_wrapped_name_list = WRAPPED_NAME_RE.findall( page_desc.question) self.embedded_name_list = NAME_RE.findall(page_desc.question) answer_instance_list = [] for idx, name in enumerate(self.embedded_name_list): answers_desc = getattr(self.page_desc.answers, name) parsed_answer = parse_question( vctx, location, name, answers_desc) answer_instance_list.append(parsed_answer) self.answer_instance_list = answer_instance_list from relate.utils import struct_to_dict answers_name_list = struct_to_dict(page_desc.answers).keys() invalid_answer_name = [] invalid_embedded_name = [] if not answer_instance_list: raise ValidationError( string_concat( "%(location)s: ", _("InlineMultiQuestion requires at least one " "answer field to be defined.")) % {'location': location}) for answers_name in answers_name_list: if NAME_VALIDATE_RE.match(answers_name) is None: invalid_answer_name.append(answers_name) if len(invalid_answer_name) > 0: raise ValidationError( string_concat( "%s: ", _("invalid answers name %s. "), _("A valid name should start with letters. " "Alphanumeric with underscores. " "Do not use spaces.")) % ( location, ", ".join([ "'" + name + "'" for name in invalid_answer_name]) )) for embedded_name in self.embedded_name_list: if NAME_VALIDATE_RE.match(embedded_name) is None: invalid_embedded_name.append(embedded_name) if len(invalid_embedded_name) > 0: raise ValidationError( string_concat( "%s: ", _("invalid embedded question name %s. "), _("A valid name should start with letters. " "Alphanumeric with underscores. " "Do not use spaces.")) % ( location, ", ".join([ "'" + name + "'" for name in invalid_embedded_name]) )) if len(set(self.embedded_name_list)) < len(self.embedded_name_list): duplicated = list( set([x for x in self.embedded_name_list if self.embedded_name_list.count(x) > 1])) raise ValidationError( string_concat( "%s: ", _("embedded question name %s not unique.")) % (location, ", ".join(duplicated))) no_answer_set = set(self.embedded_name_list) - set(answers_name_list) redundant_answer_list = list(set(answers_name_list) - set(self.embedded_name_list)) if no_answer_set: raise ValidationError( string_concat( "%s: ", _("correct answer(s) not provided for question %s.")) % (location, ", ".join( ["'" + item + "'" for item in list(no_answer_set)]))) if redundant_answer_list: if vctx is not None: vctx.add_warning(location, _("redundant answers %s provided for " "non-existing question(s).") % ", ".join( ["'" + item + "'" for item in redundant_answer_list])) if vctx is not None: validate_markup(vctx, location, page_desc.question) remainder_html = markup_to_html(vctx, page_desc.question) html_list = [] for wrapped_name in self.embedded_wrapped_name_list: [html, remainder_html] = remainder_html.split(wrapped_name) html_list.append(html) if remainder_html != "": html_list.append(remainder_html) # make sure all [[ and ]] are paired. embedded_removed = " ".join(html_list) for sep in ["[[", "]]"]: if sep in embedded_removed: raise ValidationError( string_concat( "%s: ", _("have unpaired '%s'.")) % (location, sep)) for idx, name in enumerate(self.embedded_name_list): answers_desc = getattr(page_desc.answers, name) parse_question(vctx, location, name, answers_desc)
def __init__(self, vctx, location, page_desc): super(InlineMultiQuestion, self).__init__( vctx, location, page_desc) self.embeded_wrapped_name_list = WRAPPED_NAME_RE.findall( page_desc.question) self.embeded_name_list = NAME_RE.findall(page_desc.question) from relate.utils import struct_to_dict answers_name_list = struct_to_dict(page_desc.answers).keys() invalid_answer_name = [] invalid_embeded_name = [] for answers_name in answers_name_list: if NAME_VALIDATE_RE.match(answers_name) is None: invalid_answer_name.append(answers_name) if len(invalid_answer_name) > 0: raise ValidationError( string_concat( "%s: ", _("invalid answers name %s. "), _("A valid name should start with letters. " "Alphanumeric with underscores. " "Do not use spaces.")) % ( location, ", ".join([ "'" + name + "'" for name in invalid_answer_name]) )) for embeded_name in self.embeded_name_list: if NAME_VALIDATE_RE.match(embeded_name) is None: invalid_embeded_name.append(embeded_name) if len(invalid_embeded_name) > 0: raise ValidationError( string_concat( "%s: ", _("invalid embeded question name %s. "), _("A valid name should start with letters. " "Alphanumeric with underscores. " "Do not use spaces.")) % ( location, ", ".join([ "'" + name + "'" for name in invalid_embeded_name]) )) if len(set(self.embeded_name_list)) < len(self.embeded_name_list): duplicated = list( set([x for x in self.embeded_name_list if self.embeded_name_list.count(x) > 1])) raise ValidationError( string_concat( "%s: ", _("embeded question name %s not unique.")) % (location, ", ".join(duplicated))) no_answer_set = set(self.embeded_name_list) - set(answers_name_list) redundant_answer_list = list(set(answers_name_list) - set(self.embeded_name_list)) if no_answer_set: raise ValidationError( string_concat( "%s: ", _("correct answer(s) not provided for question %s.")) % (location, ", ".join( ["'" + item + "'" for item in list(no_answer_set)]))) if redundant_answer_list: if vctx is not None: vctx.add_warning(location, _("redundant answers %s provided for " "non-existing question(s).") % ", ".join( ["'" + item + "'" for item in redundant_answer_list])) # for correct render of question with more than one # paragraph, remove heading <p> tags and change </p> # to line break. from course.content import markup_to_html # noqa self.question = remainder_html = markup_to_html( course=None, repo=None, commit_sha=None, text=page_desc.question, ).replace("<p>", "").replace("</p>", "<br/>") self.html_list = [] for wrapped_name in self.embeded_wrapped_name_list: [html, remainder_html] = remainder_html.split(wrapped_name) self.html_list.append(html) if remainder_html != "": self.html_list.append(remainder_html) # make sure all [[ and ]] are paired. embeded_removed = " ".join(self.html_list) for sep in ["[[", "]]"]: if sep in embeded_removed: raise ValidationError( string_concat( "%s: ", _("have unpaired '%s'.")) % (location, sep)) self.answer_instance_list = [] self.total_weight = 0 for idx, name in enumerate(self.embeded_name_list): answers_desc = getattr(page_desc.answers, name) parsed_answer = parse_question( vctx, location, name, answers_desc) self.answer_instance_list.append(parsed_answer) self.total_weight += self.answer_instance_list[idx].weight
def body(self, page_context, page_data): return markup_to_html(page_context, self.page_desc.prompt)
def markup_to_html_plain(page_context, s): s = markup_to_html(page_context, s) if s.startswith("<p>") and s.endswith("</p>"): s = s[3:-4] return s