Skip to content

Commit

Permalink
fix: QTI support is improved
Browse files Browse the repository at this point in the history
  • Loading branch information
myhailo-chernyshov-rg committed Nov 22, 2024
1 parent e3aee8d commit 13dbbc7
Showing 1 changed file with 33 additions and 9 deletions.
42 changes: 33 additions & 9 deletions src/cc2olx/qti.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import re
import urllib.parse
import xml.dom.minidom
from collections import OrderedDict
Expand Down Expand Up @@ -184,7 +185,7 @@ def _create_fib_problem(self, problem_data):
# and set the type to case insensitive
problem_content = self.doc.createElement("stringresponse")
problem_content.setAttribute("answer", problem_data["answer"])
problem_content.setAttribute("type", "ci")
problem_content.setAttribute("type", self._build_fib_problem_type(problem_data))

if len(problem_data["answer"]) > max_answer_length:
max_answer_length = len(problem_data["answer"])
Expand All @@ -211,6 +212,18 @@ def _create_fib_problem(self, problem_data):

return problem

@staticmethod
def _build_fib_problem_type(problem_data):
"""
Build `stringresponse` OLX type for a fill in the blank problem.
"""
problem_types = ["ci"]

if problem_data["is_regexp"]:
problem_types.append("regexp")

return " ".join(problem_types)

def _create_essay_problem(self, problem_data):
"""
Given parsed essay problem data, returns a openassessment component. If a sample
Expand Down Expand Up @@ -321,7 +334,7 @@ def parse_qti(self):
root = tree.getroot()

# qti xml can contain multiple problems represented by <item/> elements
problems = root.findall(".//qti:section[@ident='root_section']/qti:item", self.NS)
problems = root.findall(".//qti:section/qti:item", self.NS)

parsed_problems = []

Expand All @@ -334,7 +347,8 @@ def parse_qti(self):
# when we're getting malformed course (due to a weird Canvas behaviour)
# with equal identifiers. LMS doesn't support blocks with the same identifiers.
data["ident"] = attributes["ident"] + str(i)
data["title"] = attributes["title"]
if title := attributes.get("title"):
data["title"] = title

cc_profile = self._parse_problem_profile(problem)
data["cc_profile"] = cc_profile
Expand Down Expand Up @@ -516,7 +530,7 @@ def _mark_correct_responses(self, resprocessing, responses):
for ans in correct_answers:
responses[ans.text]["correct"] = True

if respcondition.attrib["continue"] == "No":
if respcondition.attrib.get("continue", "No") == "No":
break

def _parse_multiple_choice_problem(self, problem):
Expand Down Expand Up @@ -553,16 +567,26 @@ def _parse_fib_problem(self, problem):
data["problem_description"] = presentation.find("qti:material/qti:mattext", self.NS).text

answers = []
patterns = []
for respcondition in resprocessing.findall("qti:respcondition", self.NS):
for varequal in respcondition.findall("qti:conditionvar/qti:varequal", self.NS):
answers.append(varequal.text)

if respcondition.attrib["continue"] == "No":
for varsubstring in respcondition.findall("qti:conditionvar/qti:varsubstring", self.NS):
patterns.append(varsubstring.text)

if respcondition.attrib.get("continue", "No") == "No":
break

# Primary answer is the first one, additional answers are what is left
data["answer"] = answers.pop(0)
data["additional_answers"] = answers
data["is_regexp"] = bool(patterns)
if data["is_regexp"]:
data["answer"] = patterns.pop(0)
answers = [re.escape(answer) for answer in answers]
data["additional_answers"] = [*patterns, *answers]
else:
# Primary answer is the first one, additional answers are what is left
data["answer"] = answers.pop(0)
data["additional_answers"] = answers

return data

Expand All @@ -580,7 +604,7 @@ def _parse_essay_problem(self, problem):
data["problem_description"] = presentation.find("qti:material/qti:mattext", self.NS).text

if solution is not None:
sample_solution_selector = "qti:solutionmaterial/qti:material/qti:mattext"
sample_solution_selector = "qti:solutionmaterial//qti:material//qti:mattext"
data["sample_solution"] = solution.find(sample_solution_selector, self.NS).text

if itemfeedback is not None:
Expand Down

0 comments on commit 13dbbc7

Please sign in to comment.