Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 1833
Image: ubuntu2004
1
from .exercise import Exercise
2
from lxml import etree
3
from .xml import xml_boilerplate
4
import subprocess, os, json
5
import io
6
from contextlib import redirect_stdout
7
from html import escape as escape_html
8
9
class Outcome():
10
def __init__(self, title=None, slug=None, description=None, bank=None):
11
self.title = title
12
self.slug = slug
13
self.description = description
14
self.bank = bank
15
16
def template_filepath(self):
17
return os.path.join(
18
"banks",
19
self.bank.slug,
20
"outcomes",
21
f"{self.slug}.xml"
22
)
23
24
def generator_directory_path(self):
25
return os.path.join(
26
"banks",
27
self.bank.slug,
28
"outcomes"
29
)
30
31
def generator_filename(self):
32
return f"{self.slug}.sage"
33
34
def generate_exercises(self,public=False,amount=300,regenerate=False,save=True):
35
if not(regenerate):
36
try:
37
return self.__exercises
38
except:
39
pass
40
# get sage script to run generator
41
script_path = os.path.join("wrappers","sage_wrapper.sage")
42
# run script to return JSON output with [amount] seeds
43
command = ["sage",script_path,self.generator_directory_path(),self.generator_filename(),str(amount)]
44
if public:
45
command.append("PUBLIC")
46
else:
47
command.append("PRIVATE")
48
if public:
49
exs = "public exercises"
50
else:
51
exs = "private exercises"
52
print(f"Generating {amount} {exs} for {self.slug}...",end=" ")
53
# returns json list of exercise objects
54
result = subprocess.run(command,capture_output=True)
55
if result.stderr:
56
print("ERROR, no exercises generated:")
57
print(result.stdout.decode())
58
print(result.stderr.decode())
59
return []
60
data_json_list = result.stdout
61
print("Done!")
62
data_list = json.loads(data_json_list)
63
exercises = [
64
Exercise(data["values"],data["seed"],self) \
65
for data in data_list
66
]
67
if save:
68
self.__exercises = exercises
69
return exercises
70
71
def generate_dict(self,public=False,amount=300,regenerate=False):
72
exercises = self.generate_exercises(public,amount,regenerate)
73
return {
74
"title": self.title,
75
"slug": self.slug,
76
"description": self.description,
77
"exercises": [e.dict() for e in exercises],
78
}
79
80
def canvas_tree(self,public=False,amount=300,regenerate=False):
81
tree = etree.fromstring(f"""<?xml version="1.0"?>
82
<questestinterop xmlns="http://www.imsglobal.org/xsd/ims_qtiasiv1p2"
83
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
84
xsi:schemaLocation="http://www.imsglobal.org/xsd/ims_qtiasiv1p2 http://www.imsglobal.org/xsd/ims_qtiasiv1p2p1.xsd">
85
<objectbank ident="{self.bank.slug}_{self.slug}">
86
<qtimetadata>
87
<qtimetadatafield/>
88
</qtimetadata>
89
</objectbank>
90
</questestinterop>""")
91
label = etree.SubElement(tree.find("*/*/*"), "fieldlabel")
92
label.text = "bank_title"
93
entry = etree.SubElement(tree.find("*/*/*"), "fieldentry")
94
entry.text = f"{self.bank.title} | {self.slug}: {self.title}"
95
for exercise in self.generate_exercises(public,amount,regenerate):
96
tree.find("*").append(exercise.canvas_tree())
97
return tree
98
99
def brightspace_tree(self,public=False,amount=300,regenerate=False):
100
tree = xml_boilerplate("brightspace_questiondb_outcome")
101
tree.getroot().set("title", f"{self.bank.title} | {self.slug}: {self.title}")
102
tree.find("presentation_material//mattext").text = self.description
103
for exercise in self.generate_exercises(public,amount,regenerate):
104
tree.getroot().append(exercise.brightspace_tree())
105
return tree
106
107
def moodle_xmle(self,public=False,amount=300,regenerate=False):
108
root = etree.Element("quiz")
109
header = etree.SubElement(root,"question")
110
header.set("type","category")
111
category = etree.SubElement(header,"category")
112
category_text = etree.SubElement(category,"text")
113
category_text.text = f"$course$/top/checkit/{self.bank.slug}/{self.slug}"
114
info = etree.SubElement(header,"info")
115
info_text = etree.SubElement(info,"text")
116
info_text.text = f"{self.slug} | {self.title}"
117
root.append(header)
118
for exercise in self.generate_exercises(public,amount,regenerate):
119
root.append(exercise.moodle_xmle())
120
return root
121
122
def csv_row(self,count,oid_suffix):
123
return [
124
f"checkit_{self.bank.slug}_{count:02}_{self.slug}_{oid_suffix:06}",
125
"outcome",
126
f"{count:02}-{self.slug}: {self.title}",
127
"",
128
self.slug,
129
"n_mastery",
130
"2",
131
"3",
132
"4",
133
"Exceeds Mastery",
134
"3",
135
"Meets Mastery",
136
"2",
137
"Near Mastery",
138
"1",
139
"Well Below Mastery",
140
"0",
141
"Insufficient Work to Assess",
142
]
143
144
def HTML_preview(self):
145
ex = self.generate_exercises(amount=1,regenerate=True,save=False)[0]
146
html = "<h2>Preview:</h2>\n"
147
html += ex.html()
148
html += "\n"
149
html += "<pre>"
150
f = io.StringIO()
151
with redirect_stdout(f):
152
ex.print_preview()
153
html += escape_html(f.getvalue())
154
html += "</pre>"
155
return html
156
157