Skip to content
Snippets Groups Projects
Commit e1b235f1 authored by Mathieu Loiseau's avatar Mathieu Loiseau
Browse files

Cloze type questions

parent 89a3451f
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/env python3
import xml.etree.ElementTree as ET
from unidecode import unidecode
from utils import strip_tags, mlang_2_multiling, score_2_str
import base64
from PIL import Image
from io import BytesIO
from re import findall,DOTALL
class Quizz:
def __init__(self, file_name, target_folder):
......@@ -27,6 +29,8 @@ class Quizz:
newQ = ShortAnswer(q,self.categories[c],len(self.questions[c]),self.folder)
elif q.attrib['type'] == "truefalse":
newQ = TF(q,self.categories[c],len(self.questions[c]),self.folder)
elif q.attrib['type'] == "cloze":
newQ = Cloze(q, self.categories[c], len(self.questions[c]), self.folder)
elif q.attrib['type'] == "matching":
newQ = Question(q,self.categories[c],len(self.questions[c]),self.folder)#non traité
elif q.attrib['type'] == "ddimageortext":
......@@ -65,11 +69,12 @@ class Quizz:
class Question:
def __init__(self,xmlQ,c,n,f):
self.folder = f
self.id = c+"."+mlang_2_multiling(xmlQ.find("name/text").text,"en")+f".{n}"
self.id = unidecode(c+"."+mlang_2_multiling(xmlQ.find("name/text").text.replace(" ",""),"en")+f".{n}")
self.q = strip_tags(mlang_2_multiling(xmlQ.find("questiontext/text").text), self.folder,self.id)
self.category = c
self.env = "todo:"+xmlQ.attrib["type"]
self.max = float(xmlQ.find("defaultgrade").text)
if xmlQ.find("defaultgrade") != None:
self.max = float(xmlQ.find("defaultgrade").text)
self.parseImages(xmlQ.findall(".//file"))
def parseImages(self, file_elements):
......@@ -83,11 +88,62 @@ class Question:
#return "\\element{" + self.category + "}{\n\t\\begin{" + self.env + "}{" + self.id + "}\\nbpoints{" + score_2_str(self.max) + "}\n\t\t" + self.q + "\\end{" + self.env + "}\n"
return ""
class Cloze(Question):
zones = ['A', 'B', 'C', 'D', 'E', 'F','G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
def __init__(self, xmlQ,c,n,f):
super().__init__(xmlQ,c,n,f)
self.max = float(xmlQ.find("penalty").text)
self.choices = []
self.choices_num = {}
self.choice_type = MCQ.VERTICAL
self.env = "questionmult"
self.q = strip_tags(mlang_2_multiling(xmlQ.find("questiontext/text").text.replace("%","øØ")), self.folder,self.id)
if self.__class__.__name__ == "Cloze":
self.__parseAnswers(self.q)
def __parseAnswers(self, txt):
questions = findall(r'\{:MCS?:([^\}]*)\}', txt, DOTALL)
i = 0
for c in questions:
self.create_choices(c, Cloze.zones[i], len(questions))
txt = txt.replace(r"{:MCS:"+c+"}", "\\underline{~~~~~~~~}("+Cloze.zones[i]+")").replace(r"{:MC:"+c+"}", "\\underline{~~~~~~~~}("+Cloze.zones[i]+")")
i += 1
self.q = txt
def create_choices(self, c_list, l, n):
self.choices_num[l] = 0
choices = c_list.split("~")
for c in choices:
self.choices_num[l] += 1
if c[0] == "=":
self.choices.append(Answer(f"{l}) {c[1:]}", 100/n, self.max))
elif c[0:2] =="øØ":
scores = c.split("øØ")
self.choices.append(Answer(f"{l}) {scores[2]}", float(scores[1]), self.max))
else :
self.choices.append(Answer(f"{l}) {c}", 0, self.max))
def __str__(self):
res = "\\element{" + self.category + "}{\n\t\\begin{" + self.env + "}{" + self.id + "}\\nbpoints{" + score_2_str(self.max) + "}\\\\\n" + self.q +"\n\t\t\\begin{multicols}{"+str(len(self.choices_num))+"}\n\t\t\t\\begin{choices}[o]\n\\AMCnoCompleteMulti"
res += "\n"
l = 0
i = 0
for c in self.choices:
i += 1
res += str(c)
if self.choices_num[Cloze.zones[l]] == i:
i = 0
l += 1
if l < len(self.choices_num):
res += "\\vfill\\null\n\\columnbreak\n"
res += "\n\t\t\t\\end{choices} \n\t\t\\end{multicols} \n\t\\end{" + self.env + "}\n}\n\n"
return res
class Answer:
def __init__(self,t,b,max,fb):
def __init__(self,t,b,max,fb=None):
self.status = float(b) > 0
self.text = t
self.points = round(float(b)/(100*float(max)),3)
self.points = round((float(b)/100)*float(max),3)
self.feedback = fb
def __str__(self):
......@@ -187,7 +243,7 @@ class ShortAnswer(TF):
return res
if __name__ == "__main__":
quizz = Quizz("data/SID questions.xml", "data")
quizz = Quizz("data/KNM questions.xml", "data")
#quizz = Quizz("data/quiz-GI-4.xml" , "data")
#print(quizz)
quizz.save()
......@@ -22,7 +22,7 @@ def process_listings(txt, folder="",q="q"):
def remove_moodle_cdata(txt, folder, q):
global unsafe
txt = process_listings(txt, folder, q)
res = sub(r'<img src="[^/]*/([^"]*)" (alt="([^"]*)")?[^>]*>', r"""\\\\\\includegraphics[width=0.8\\linewidth]{Images/\1}""",txt).replace("<![CDATA[","").replace("]]>","").replace("<strong>","\\emph{").replace("</strong>","}")
res = sub(r'<img src="[^/]*/([^"]*)" (alt="([^"]*)")?[^>]*>', r"""\\\\\\includegraphics[width=0.8\\linewidth]{Images/\1}""",txt).replace("<![CDATA[","").replace("]]>","").replace("<strong>","\\emph{").replace("</strong>","}").replace("<em>","\\emph{").replace("</em>","}")
if unsafe:
res = res.replace('<span style="font:monospace">',"\lstinline[language=python]|").replace('<span style="font-family:monospace">',"\lstinline[language=python]|").replace('<span style="font-family=monospace">',"\lstinline[language=python]|").replace("</span>","|")
return res
......@@ -43,5 +43,5 @@ def score_2_str(v):
if int(v)==float(v):
res = str(int(v))
else:
res = str(float(v))
res = str(round(float(v),3))
return res
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment