Skip to content
Snippets Groups Projects
Commit f9a604d5 authored by Jan Maximilian Michal's avatar Jan Maximilian Michal
Browse files

Questions are now single python classes and file generation is moore abstract

parent bb90f7ec
No related branches found
No related tags found
No related merge requests found
...@@ -19,7 +19,6 @@ question. ...@@ -19,7 +19,6 @@ question.
* Add more functionality (gap, alignment, etc.) * Add more functionality (gap, alignment, etc.)
* Make parsers more robust. * Make parsers more robust.
* reverse ILIAS authentication mechanism for automated upload. * reverse ILIAS authentication mechanism for automated upload.
* Enable LaTeX through custom lexer in mistune.
### Notes ### Notes
......
...@@ -6,7 +6,7 @@ import os ...@@ -6,7 +6,7 @@ import os
import sys import sys
# local import # local import
from hallgrim.IliasXMLCreator import multi, single from hallgrim.IliasXMLCreator import packer
from hallgrim.messages import * from hallgrim.messages import *
from hallgrim.parser import * from hallgrim.parser import *
...@@ -17,9 +17,9 @@ def filename_to_module(name): ...@@ -17,9 +17,9 @@ def filename_to_module(name):
def type_selector(type): def type_selector(type):
if 'multiple' in type: if 'multiple' in type:
return multi return 'MULTIPLE CHOICE QUESTION'
if 'single' in type: if 'single' in type:
return single return 'SINGLE CHOICE QUESTION'
def parseme(): def parseme():
...@@ -44,6 +44,7 @@ def main(): ...@@ -44,6 +44,7 @@ def main():
output, script_name = parseme() output, script_name = parseme()
script = importlib.import_module(filename_to_module(script_name)) script = importlib.import_module(filename_to_module(script_name))
data = { data = {
'type': type_selector(script.meta['type']),
'description': "_description", 'description': "_description",
'question_text': markdown(script.task), 'question_text': markdown(script.task),
'author': script.meta['author'], 'author': script.meta['author'],
...@@ -55,7 +56,7 @@ def main(): ...@@ -55,7 +56,7 @@ def main():
output = os.path.join( output = os.path.join(
'output', script.meta['title']) + '.xml' if not output else output 'output', script.meta['title']) + '.xml' if not output else output
type_selector(script.meta['type']).convert_and_print(data, output) packer.convert_and_print(data, output)
info('Processed "{}" and wrote xml to "{}".'.format(script_name, output)) info('Processed "{}" and wrote xml to "{}".'.format(script_name, output))
if __name__ == '__main__': if __name__ == '__main__':
......
import xml.etree.ElementTree as et import xml.etree.ElementTree as et
from hallgrim.IliasXMLCreator.xmlBuildingBlocks import *
def simple_elemet(name, text=None, attrib={}):
if not text: class MultipleChoiceQuestion:
return et.Element(name, attrib=attrib) """docstring for MultipleChoiceQuestion"""
node = et.Element(name, attrib=attrib) def __init__(self, type, description, question_text, author, title, maxattempts, questions, shuffle=True):
node.text = text self.type = type
return node self.description = description
self.question_text = question_text
self.author = author
def qtimetadatafield(label, entry): self.title = title
root = et.Element('qtimetadatafield') self.maxattempts = maxattempts
root.append(simple_elemet('fieldlabel', text=label)) self.shuffle = shuffle
root.append(simple_elemet('fieldentry', text=entry)) self.questions = questions
return root
self.itemmetadata = self.itemmetadata(feedback_setting=1)
self.presentation = self.presentation()
def itemmetadata(type, author, feedback_setting=1): self.resprocessing = self.resprocessing()
subroot = et.Element('qtimetadata') self.xml_representation = self.create_item()
subroot.append(qtimetadatafield('ILIAS_VERSION', '5.1.8 2016-08-03'))
subroot.append(qtimetadatafield('QUESTIONTYPE', type)) def __call__(self):
subroot.append(qtimetadatafield('AUTHOR', author)) return self.xml_representation
subroot.append(qtimetadatafield('additional_cont_edit_mode', 'default'))
subroot.append(qtimetadatafield('externalId', '99.99')) def is_single(self):
subroot.append(qtimetadatafield('thumb_size', None)) return self.type == 'SINGLE CHOICE QUESTION'
subroot.append(qtimetadatafield('feedback_setting', str(feedback_setting)))
root = et.Element('itemmetadata') def itemmetadata(self, feedback_setting=1):
root.append(subroot) subroot = et.Element('qtimetadata')
return root subroot.append(qtimetadatafield('ILIAS_VERSION', '5.1.8 2016-08-03'))
subroot.append(qtimetadatafield('QUESTIONTYPE', self.type))
########################################################################## subroot.append(qtimetadatafield('AUTHOR', self.author))
def material(content): subroot.append(qtimetadatafield('additional_cont_edit_mode', 'default'))
material = et.Element('material') subroot.append(qtimetadatafield('externalId', '99.99'))
material.append(simple_elemet( subroot.append(qtimetadatafield('thumb_size', None))
'mattext', subroot.append(qtimetadatafield('feedback_setting', str(feedback_setting)))
text=content, root = et.Element('itemmetadata')
attrib={'texttype': 'text/xhtml'} root.append(subroot)
)) return root
return material
############################################################################
def presentation(self):
def response_label(content, count): root = et.Element('presentation', attrib={'label': self.title})
response_label = et.Element('response_label', attrib={'ident': str(count)}) flow = et.Element('flow')
response_label.append(material(content)) response_lid = et.Element('response_lid', attrib={
return response_label 'ident': 'MCMR',
'rcardinality': 'Multiple' if not self.is_single() else 'Single'
})
def presentation(title, question_text, questions, shuffle=True): render_choice = et.Element(
root = et.Element('presentation', attrib={'label': title}) 'render_choice', attrib={'shuffle': 'Yes' if self.shuffle else 'No'})
flow = et.Element('flow') for i, (answer, _, _) in enumerate(self.questions):
response_lid = et.Element( render_choice.append(response_label(answer, i))
'response_lid', attrib={'ident': 'MCMR', 'rcardinality': 'Multiple'})
render_choice = et.Element( root.append(flow)
'render_choice', attrib={'shuffle': 'Yes' if shuffle else 'No'}) flow.append(material(self.question_text))
for i, (answer, _, _) in enumerate(questions): flow.append(response_lid)
render_choice.append(response_label(answer, i)) response_lid.append(render_choice)
return root
root.append(flow)
flow.append(material(question_text)) ############################################################################
flow.append(response_lid) def resprocessing(self):
response_lid.append(render_choice) root = et.Element('resprocessing')
return root outcomes = et.Element('outcomes')
outcomes.append(simple_elemet('decvar'))
########################################################################## root.append(outcomes)
def respcondition(points, count, correct=True): for i, (_, correct, points) in enumerate(self.questions):
root = et.Element('respcondition', attrib={'continue': 'Yes'}) root.append(respcondition(points if correct else 0, i, True))
conditionvar = et.Element('conditionvar') root.append(respcondition(points if not correct else 0, i, False))
varequal = simple_elemet( return root
'varequal',
text=str(count), ############################################################################
attrib={'respident': 'MCMR'} @staticmethod
) def itemfeedback(count):
root = et.Element(
if correct: 'itemfeedback',
conditionvar.append(varequal) attrib={'ident': 'response_{}'.format(count), 'view': 'All'}
else: )
_not = et.Element('not') flow_mat = et.Element('flow_mat')
_not.append(varequal) flow_mat.append(material('NONE'))
conditionvar.append(_not) root.append(flow_mat)
return root
root.append(conditionvar)
### returns the final object ###############################################
setvar = simple_elemet( def create_item(self):
'setvar', """ This method stacks all the previously created structures together"""
text=str(points), item = et.Element('item', attrib={
attrib={'action': 'Add'} 'ident': 'undefined',
) 'title': self.title,
root.append(setvar) 'maxattempts': self.maxattempts
})
if correct:
displayfeedback = et.Element( item.append(simple_elemet('description', text=self.description))
'displayfeedback', item.append(simple_elemet('duration', text='P0Y0M0DT0H30M0S')) # 30 min
attrib={'feedbacktype': 'Response', item.append(self.itemmetadata)
'linkrefid': 'response_{}'.format(count)}) item.append(self.presentation)
root.append(displayfeedback) item.append(self.resprocessing)
return root for i, _ in enumerate(self.questions):
item.append(self.itemfeedback(i))
return item
def resprocessing(questions):
root = et.Element('resprocessing')
outcomes = et.Element('outcomes')
outcomes.append(simple_elemet('decvar'))
root.append(outcomes)
for i, (_, correct, points) in enumerate(questions):
root.append(respcondition(points if correct else 0, i, True))
root.append(respcondition(points if not correct else 0, i, False))
return root
##########################################################################
def itemfeedback(count):
root = et.Element(
'itemfeedback',
attrib={'ident': 'response_{}'.format(count), 'view': 'All'}
)
flow_mat = et.Element('flow_mat')
flow_mat.append(material('NONE'))
root.append(flow_mat)
return root
##########################################################################
def create_xml_tree(type, description, question_text, author, title, maxattempts, shuffle, questions):
root = et.Element('questestinterop')
tree = et.ElementTree(root)
item = et.Element('item', attrib={
'ident': 'undefined',
'title': title,
'maxattempts': maxattempts
})
item.append(simple_elemet('description', text=description))
item.append(simple_elemet('duration', text='P0Y0M0DT0H30M0S'))
item.append(itemmetadata(type, author))
item.append(presentation(title, question_text, questions, shuffle))
item.append(resprocessing(questions))
for i, _ in enumerate(questions):
item.append(itemfeedback(i))
root.append(item)
return tree
def convert_and_print(data, output):
tree = create_xml_tree('MULTIPLE CHOICE QUESTION', **data)
tree.write(output, encoding="utf-8", xml_declaration=True)
import xml.etree.ElementTree as et
from hallgrim.IliasXMLCreator import multi, single
def create_xml_tree(item_list):
root = et.Element('questestinterop')
tree = et.ElementTree(root)
for item in item_list:
root.append(item)
return tree
def convert_and_print(data, output):
if data['type'] == 'MULTIPLE CHOICE QUESTION':
item = multi.MultipleChoiceQuestion(**data)()
if data['type'] == 'SINGLE CHOICE QUESTION':
item = single.SingleChoiceQuestion(**data)()
tree = create_xml_tree([item])
tree.write(output, encoding="utf-8", xml_declaration=True)
from .multi import * import xml.etree.ElementTree as et
def resprocessing(questions): from hallgrim.IliasXMLCreator.multi import *
root = et.Element('resprocessing')
outcomes = et.Element('outcomes')
outcomes.append(simple_elemet('decvar'))
root.append(outcomes)
for i, (_, correct, points) in enumerate(questions):
root.append(respcondition(points if correct else 0, i, True))
return root
def convert_and_print(data, output): class SingleChoiceQuestion(MultipleChoiceQuestion):
tree = create_xml_tree('SINGLE CHOICE QUESTION', **data) """ is just a subclass of multi with the exception of this method.
tree.write(output, encoding="utf-8", xml_declaration=True) Some other minor differences exists but they are handled in the
\ No newline at end of file parent since they only concert irrelevant fields. """
def resprocessing(self):
root = et.Element('resprocessing')
outcomes = et.Element('outcomes')
outcomes.append(simple_elemet('decvar'))
root.append(outcomes)
for i, (_, correct, points) in enumerate(self.questions):
root.append(respcondition(points if correct else 0, i, True))
return root
import xml.etree.ElementTree as et
### static methods #############################################################
def simple_elemet(name, text=None, attrib={}):
if not text:
return et.Element(name, attrib=attrib)
node = et.Element(name, attrib=attrib)
node.text = text
return node
def qtimetadatafield(label, entry):
root = et.Element('qtimetadatafield')
root.append(simple_elemet('fieldlabel', text=label))
root.append(simple_elemet('fieldentry', text=entry))
return root
def material(content):
material = et.Element('material')
material.append(simple_elemet(
'mattext',
text=content,
attrib={'texttype': 'text/xhtml'}
))
return material
def response_label(content, count):
response_label = et.Element('response_label', attrib={'ident': str(count)})
response_label.append(material(content))
return response_label
def respcondition(points, count, correct=True):
root = et.Element('respcondition', attrib={'continue': 'Yes'})
conditionvar = et.Element('conditionvar')
varequal = simple_elemet(
'varequal',
text=str(count),
attrib={'respident': 'MCMR'}
)
if correct:
conditionvar.append(varequal)
else:
_not = et.Element('not')
_not.append(varequal)
conditionvar.append(_not)
root.append(conditionvar)
setvar = simple_elemet(
'setvar',
text=str(points),
attrib={'action': 'Add'}
)
root.append(setvar)
if correct:
displayfeedback = et.Element(
'displayfeedback',
attrib={'feedbacktype': 'Response',
'linkrefid': 'response_{}'.format(count)})
root.append(displayfeedback)
return root
...@@ -5,7 +5,8 @@ meta = { ...@@ -5,7 +5,8 @@ meta = {
'points': 0.5, # per correct choice 'points': 0.5, # per correct choice
} }
task = """ Hier der Anfang der Datei `punkte.csv`, die Komma-getrennte Angaben task = """
Hier der Anfang der Datei `punkte.csv`, die Komma-getrennte Angaben
zu erreichten Übungspunkten enthält [[Example Formula \\sum_{i=0}^n i]]: zu erreichten Übungspunkten enthält [[Example Formula \\sum_{i=0}^n i]]:
``` ```
......
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