Example #1
0
    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
Example #2
0
 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/>")
Example #3
0
    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
Example #4
0
    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
Example #5
0
    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
Example #6
0
    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
Example #7
0
    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
Example #8
0
    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", ""),
            },
        )
Example #9
0
    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
Example #10
0
    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
Example #11
0
    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
Example #12
0
    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
Example #13
0
    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
Example #14
0
    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)
Example #15
0
    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)
Example #16
0
 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
Example #17
0
    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)
Example #18
0
    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
Example #19
0
 def body(self, page_context, page_data):
     return markup_to_html(page_context, self.page_desc.prompt)
Example #20
0
 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
Example #21
0
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
Example #22
0
 def body(self, page_context, page_data):
     return markup_to_html(page_context, self.page_desc.prompt)
Example #23
0
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