def normalize_flow_desc(flow_desc): if hasattr(flow_desc, "pages"): pages = flow_desc.pages from relate.utils import struct_to_dict, Struct d = struct_to_dict(flow_desc) del d["pages"] d["groups"] = [Struct({"id": "main", "pages": pages})] return Struct(d) if hasattr(flow_desc, "rules"): rules = flow_desc.rules if not hasattr(rules, "grade_identifier"): # Legacy content with grade_identifier in grading rule, # move first found grade_identifier up to rules. rules.grade_identifier = None rules.grade_aggregation_strategy = None for grule in rules.grading: if grule.grade_identifier is not None: rules.grade_identifier = grule.grade_identifier rules.grade_aggregation_strategy = \ grule.grade_aggregation_strategy break return flow_desc
def normalize_page_desc(page_desc): if hasattr(page_desc, "content"): content = page_desc.content from relate.utils import struct_to_dict, Struct d = struct_to_dict(page_desc) del d["content"] d["chunks"] = [Struct({"id": "main", "content": content})] return Struct(d) return page_desc
def normalize_flow_desc(flow_desc): if hasattr(flow_desc, "pages"): pages = flow_desc.pages from relate.utils import struct_to_dict, Struct d = struct_to_dict(flow_desc) del d["pages"] d["groups"] = [Struct({"id": "main", "pages": pages})] return Struct(d) return flow_desc
def normalize_page_desc(page_desc): # type: (StaticPageDesc) -> StaticPageDesc if hasattr(page_desc, "content"): content = page_desc.content from relate.utils import struct_to_dict, Struct d = struct_to_dict(page_desc) del d["content"] d["chunks"] = [Struct({"id": "main", "content": content})] return cast(StaticPageDesc, Struct(d)) return page_desc
def __init__(self, vctx, location, page_desc): super(InlineMultiQuestion, self).__init__(vctx, location, page_desc) expanded_question = page_desc.question self.embedded_wrapped_name_list = WRAPPED_NAME_RE.findall( expanded_question) self.embedded_name_list = NAME_RE.findall(expanded_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) def reverse_func(*args, **kwargs): pass # FIXME This is a bit redundant since validate_markup already calls # markup_to_html. remainder_html = markup_to_html(vctx, page_desc.question, reverse_func=reverse_func) 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) expanded_question = page_desc.question self.embedded_wrapped_name_list = WRAPPED_NAME_RE.findall(expanded_question) self.embedded_name_list = NAME_RE.findall(expanded_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 = [] 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 invalid_answer_name: 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]) )) 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(["'%s'" % d for d in sorted(duplicated)]))) redundant_answer_list = list(set(answers_name_list) - set(self.embedded_name_list)) 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 = 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.strip(): 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: ", _("question has 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 __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