Commit 34b58efe7ddde7d3dd1aec1b98410e6ec5c100dc
1 parent
9bace4f6
Exists in
master
and in
1 other branch
- replaced key 'stdin' by 'arg' in questions of type generator
- updated manual and demo
Showing
5 changed files
with
224 additions
and
181 deletions
Show diff stats
BUGS.md
@@ -7,7 +7,6 @@ | @@ -7,7 +7,6 @@ | ||
7 | - parece que é preciso criar à mão a pasta para as respostas (ans/...) depois apercebo-me que os caminhos no teste dizem respeito à directoria donde o teste é corrido... as respostas deveriam guardadas no directório dado. | 7 | - parece que é preciso criar à mão a pasta para as respostas (ans/...) depois apercebo-me que os caminhos no teste dizem respeito à directoria donde o teste é corrido... as respostas deveriam guardadas no directório dado. |
8 | - se database for mal configurada, é criada uma base de dados vazia e rebenta na autenticacao. | 8 | - se database for mal configurada, é criada uma base de dados vazia e rebenta na autenticacao. |
9 | - testar regex na definicao das perguntas. como se faz rawstring em yaml? singlequote? problemas de backslash??? sim... necessário fazer \\ em varios casos, mas não é claro! e.g. \n é convertido em espaço mas \w é convertido em \\ e w. | 9 | - testar regex na definicao das perguntas. como se faz rawstring em yaml? singlequote? problemas de backslash??? sim... necessário fazer \\ em varios casos, mas não é claro! e.g. \n é convertido em espaço mas \w é convertido em \\ e w. |
10 | -- testar envio de parametros para stdin para perguntas tipo generator. | ||
11 | 10 | ||
12 | # TODO | 11 | # TODO |
13 | 12 | ||
@@ -26,6 +25,7 @@ | @@ -26,6 +25,7 @@ | ||
26 | 25 | ||
27 | # FIXED | 26 | # FIXED |
28 | 27 | ||
28 | +- testar envio de parametros para stdin para perguntas tipo generator. | ||
29 | - mathjax e jquery no login | 29 | - mathjax e jquery no login |
30 | - mostrar erro quando nao consegue importar questions files | 30 | - mostrar erro quando nao consegue importar questions files |
31 | - pacotes exactos usados para instalar. | 31 | - pacotes exactos usados para instalar. |
MANUAL.md
@@ -2,29 +2,29 @@ | @@ -2,29 +2,29 @@ | ||
2 | 2 | ||
3 | ### Requirements and instalation | 3 | ### Requirements and instalation |
4 | 4 | ||
5 | -Install: | ||
6 | - | ||
7 | -- python3.4 | ||
8 | -- cherrypy3 | ||
9 | -- mako | ||
10 | -- yaml | ||
11 | -- markdown | 5 | +Install python 3.4 and the following packages from pip: |
12 | 6 | ||
7 | +- CherryPy (3.7.0) | ||
8 | +- Mako (1.0.1) | ||
9 | +- Markdown (2.6.2) | ||
10 | +- PyYAML (3.11) | ||
13 | 11 | ||
14 | Before using the program you need to | 12 | Before using the program you need to |
15 | 13 | ||
16 | 1. Create the students database | 14 | 1. Create the students database |
17 | 1. Create questions | 15 | 1. Create questions |
18 | 1. Create a test | 16 | 1. Create a test |
19 | -1. Configure the server (the default may be enough) | 17 | +1. Configure the server (the default should be enough) |
20 | 18 | ||
21 | ### Create students database | 19 | ### Create students database |
22 | 20 | ||
23 | We need a sqlite3 database to store students, passwords, test results, and questions results, etc. | 21 | We need a sqlite3 database to store students, passwords, test results, and questions results, etc. |
24 | 22 | ||
25 | -The database can be initialized from a list of students in CSV format using the script | 23 | +The database can be initialized from a list of students in CSV format by running in the terminal |
26 | 24 | ||
27 | - $ ./initdb_from_csv.py list_of_students.csv | 25 | +```sh |
26 | +./initdb_from_csv.py list_of_students.csv | ||
27 | +``` | ||
28 | 28 | ||
29 | This script will create a new sqlite3 database with the correct tables and insert the students with empty passwords. | 29 | This script will create a new sqlite3 database with the correct tables and insert the students with empty passwords. |
30 | It also adds a special user number 0. This is the administrator user (Professor). | 30 | It also adds a special user number 0. This is the administrator user (Professor). |
@@ -36,24 +36,26 @@ The passwords will be defined on the first login. | @@ -36,24 +36,26 @@ The passwords will be defined on the first login. | ||
36 | Questions are defined in `yaml` files and can reside anywhere in the filesystem. | 36 | Questions are defined in `yaml` files and can reside anywhere in the filesystem. |
37 | Each file contains a list of questions, where each question is a dictionary. Example | 37 | Each file contains a list of questions, where each question is a dictionary. Example |
38 | 38 | ||
39 | - - | ||
40 | - ref: question-1 | ||
41 | - type: radio | ||
42 | - text: Select the correct option | ||
43 | - options: | ||
44 | - - correct | ||
45 | - - wrong | ||
46 | - | ||
47 | - - | ||
48 | - ref: question-2 | ||
49 | - type: checkbox | ||
50 | - text: Which ones are correct? | ||
51 | - options: | ||
52 | - - correct | ||
53 | - - correct | ||
54 | - - wrong | ||
55 | - correct: [1, 1, -1] | ||
56 | - hint: There are two correct answers! | 39 | +```yaml |
40 | +- | ||
41 | + ref: question-1 | ||
42 | + type: radio | ||
43 | + text: Select the correct option | ||
44 | + options: | ||
45 | + - correct | ||
46 | + - wrong | ||
47 | + | ||
48 | +- | ||
49 | + ref: question-2 | ||
50 | + type: checkbox | ||
51 | + text: Which ones are correct? | ||
52 | + options: | ||
53 | + - correct | ||
54 | + - correct | ||
55 | + - wrong | ||
56 | + correct: [1, 1, -1] | ||
57 | + hint: There are two correct answers! | ||
58 | +``` | ||
57 | 59 | ||
58 | There are several kinds of questions: | 60 | There are several kinds of questions: |
59 | 61 | ||
@@ -72,84 +74,90 @@ Detailed information on each question type is described later on. | @@ -72,84 +74,90 @@ Detailed information on each question type is described later on. | ||
72 | 74 | ||
73 | A test is a file in `yaml` format that can reside anywhere on the filesystem. It has the following structure: | 75 | A test is a file in `yaml` format that can reside anywhere on the filesystem. It has the following structure: |
74 | 76 | ||
75 | - ref: this-is-a-key | ||
76 | - title: Titulo do teste | ||
77 | - database: db/mystudents.db | ||
78 | - | ||
79 | - # Will save the entire test of each student in JSON format. | ||
80 | - # If tests are to be saved, we must specify the directory. | ||
81 | - # The directory is created if it doesn't exist already. | ||
82 | - # The name of the JSON files will include the student number, test | ||
83 | - # reference key, date and time. | ||
84 | - save_answers: True | ||
85 | - answers_dir: ans/asc1_test4 | ||
86 | - | ||
87 | - # Some questions can contain hints, embedded videos, etc | ||
88 | - show_hints: True | ||
89 | - | ||
90 | - # Each question has some number of points. Show them normalized to 0-20. | ||
91 | - show_points: True | ||
92 | - | ||
93 | - # In train mode, the correction of the test is shown and the test can | ||
94 | - # be repeated | ||
95 | - practice_mode: True | ||
96 | - | ||
97 | - # Show the data structures obtained from the test and the questions | ||
98 | - debug: False | ||
99 | - | ||
100 | - # Show the file and ref field of each question | ||
101 | - show_ref: True | ||
102 | - | ||
103 | - # ------------------------------------------------------------------------- | ||
104 | - # This are the questions database to be imported. | ||
105 | - files: | ||
106 | - - questions/file1.yaml | ||
107 | - - questions/file2.yaml | ||
108 | - - questions/file3.yaml | ||
109 | - # ------------------------------------------------------------------------- | ||
110 | - # This is the actual test configuration. Selection of questions and points | ||
111 | - # It'a defined as a list of questions. Each question can be a single | ||
112 | - # question key or a list of keys from which one is chosen at random. | ||
113 | - # Each question has a default value of 1.0 point, but it can be overridden. | ||
114 | - # The points defined here do not need to be normalized (it's automatic). | ||
115 | - questions: | ||
116 | - - ref: | ||
117 | - - first-question-1 # randomly choose one from these 3 questions | ||
118 | - - first-question-2 | ||
119 | - - first-question-3 | ||
120 | - points: 0.5 | ||
121 | - | ||
122 | - - ref: second-question # one question, 1.0 point (unnormalized) | ||
123 | - | ||
124 | - - third-question # "ref:" not needed in simple cases | 77 | +```yaml |
78 | +ref: this-is-a-key | ||
79 | +title: Titulo do teste | ||
80 | +database: db/mystudents.db | ||
81 | + | ||
82 | +# Will save the entire test of each student in JSON format. | ||
83 | +# If tests are to be saved, we must specify the directory. | ||
84 | +# The directory is created if it doesn't exist already. | ||
85 | +# The name of the JSON files will include the student number, test | ||
86 | +# reference key, date and time. | ||
87 | +save_answers: True | ||
88 | +answers_dir: ans/asc1_test4 | ||
89 | + | ||
90 | +# Some questions can contain hints, embedded videos, etc | ||
91 | +show_hints: True | ||
92 | + | ||
93 | +# Each question has some number of points. Show them normalized to 0-20. | ||
94 | +show_points: True | ||
95 | + | ||
96 | +# In train mode, the correction of the test is shown and the test can | ||
97 | +# be repeated | ||
98 | +practice_mode: True | ||
99 | + | ||
100 | +# Show the data structures obtained from the test and the questions | ||
101 | +debug: False | ||
102 | + | ||
103 | +# Show the file and ref field of each question | ||
104 | +show_ref: True | ||
105 | + | ||
106 | +# ------------------------------------------------------------------------- | ||
107 | +# This are the questions database to be imported. | ||
108 | +files: | ||
109 | + - questions/file1.yaml | ||
110 | + - questions/file2.yaml | ||
111 | + - questions/file3.yaml | ||
112 | +# ------------------------------------------------------------------------- | ||
113 | +# This is the actual test configuration. Selection of questions and points | ||
114 | +# It'a defined as a list of questions. Each question can be a single | ||
115 | +# question key or a list of keys from which one is chosen at random. | ||
116 | +# Each question has a default value of 1.0 point, but it can be overridden. | ||
117 | +# The points defined here do not need to be normalized (it's automatic). | ||
118 | +questions: | ||
119 | + - ref: | ||
120 | + - first-question-1 # randomly choose one from these 3 questions | ||
121 | + - first-question-2 | ||
122 | + - first-question-3 | ||
123 | + points: 0.5 | ||
124 | + | ||
125 | + - ref: second-question # one question, 1.0 point (unnormalized) | ||
126 | + | ||
127 | + - third-question # "ref:" not needed in simple cases | ||
125 | 128 | ||
126 | This following one is wrong: | 129 | This following one is wrong: |
127 | 130 | ||
128 | - - wrong-question # missing "ref:" key | ||
129 | - points: 2 | 131 | + - wrong-question # missing "ref:" key |
132 | + points: 2 | ||
133 | +``` | ||
130 | 134 | ||
131 | Some of the options have default values if they are omitted. The defaults are the following: | 135 | Some of the options have default values if they are omitted. The defaults are the following: |
132 | 136 | ||
133 | - ref: filename.yaml | ||
134 | - title: '' | ||
135 | - save_answers: False | ||
136 | - show_hints: False | ||
137 | - show_points: False | ||
138 | - practice_mode: False | ||
139 | - show_ref: False | ||
140 | - debug: False | ||
141 | - points: 1.0 | ||
142 | - | 137 | +```yaml |
138 | +ref: filename.yaml | ||
139 | +title: '' | ||
140 | +save_answers: False | ||
141 | +show_hints: False | ||
142 | +show_points: False | ||
143 | +practice_mode: False | ||
144 | +show_ref: False | ||
145 | +debug: False | ||
146 | +points: 1.0 | ||
147 | +``` | ||
143 | ### Running an existing test | 148 | ### Running an existing test |
144 | 149 | ||
145 | A test is a file in `yaml` format. Just run `serve.py` with the test to run as argument: | 150 | A test is a file in `yaml` format. Just run `serve.py` with the test to run as argument: |
146 | 151 | ||
147 | - $ ./serve.py tests_dir/mytest.yaml | 152 | +```sh |
153 | +$ ./serve.py tests_dir/mytest.yaml | ||
154 | +``` | ||
148 | 155 | ||
149 | Some defaults can be overriden with command line options. Example | 156 | Some defaults can be overriden with command line options. Example |
150 | 157 | ||
151 | - $ ./serve.py mytest.yaml --debug --show_points --show_hints --practice_mode --save_answers | ||
152 | - | 158 | +```sh |
159 | +$ ./serve.py mytest.yaml --debug --show_points --show_hints --practice_mode --save_answers | ||
160 | +``` | ||
153 | To terminate the test just do `^C` on the keyboard. | 161 | To terminate the test just do `^C` on the keyboard. |
154 | 162 | ||
155 | ## Questions | 163 | ## Questions |
@@ -160,29 +168,31 @@ Every question should have a `ref` and a `type`. The other keys depend on the ty | @@ -160,29 +168,31 @@ Every question should have a `ref` and a `type`. The other keys depend on the ty | ||
160 | 168 | ||
161 | Not a real question. Just text to be shown without expecting an answer. | 169 | Not a real question. Just text to be shown without expecting an answer. |
162 | 170 | ||
163 | - - | ||
164 | - ref: some-key | ||
165 | - type: information | ||
166 | - text: Tomorrow will rain. | ||
167 | - | 171 | +```yaml |
172 | +- | ||
173 | + ref: some-key | ||
174 | + type: information | ||
175 | + text: Tomorrow will rain. | ||
176 | +``` | ||
168 | Correcting an information will always be considered correct, but the grade will be zero because it has 0.0 points by default. | 177 | Correcting an information will always be considered correct, but the grade will be zero because it has 0.0 points by default. |
169 | 178 | ||
170 | ### Radio | 179 | ### Radio |
171 | 180 | ||
172 | Only one option is correct. | 181 | Only one option is correct. |
173 | 182 | ||
174 | - - | ||
175 | - ref: some-key | ||
176 | - type: radio | ||
177 | - text: The horse is white. # optional (default: '') | ||
178 | - options: | ||
179 | - - The horse is white | ||
180 | - - The horse is not black | ||
181 | - - The horse is black | ||
182 | - correct: 0 # optional (default: 0). Index is 0-based. | ||
183 | - shuffle: True # optional (default: True) | ||
184 | - discount: True # optional (default: True) | ||
185 | - | 183 | +```yaml |
184 | +- | ||
185 | + ref: some-key | ||
186 | + type: radio | ||
187 | + text: The horse is white. # optional (default: '') | ||
188 | + options: | ||
189 | + - The horse is white | ||
190 | + - The horse is not black | ||
191 | + - The horse is black | ||
192 | + correct: 0 # optional (default: 0). Index is 0-based. | ||
193 | + shuffle: True # optional (default: True) | ||
194 | + discount: True # optional (default: True) | ||
195 | +``` | ||
186 | The `correct` value can also be defined as a list of degrees of correctness between 0 (wrong) and 1 (correct), e.g. if answering "the horse is not black" should be considered half-right, then we should use `correct: [1, 0.5, 0]`. | 196 | The `correct` value can also be defined as a list of degrees of correctness between 0 (wrong) and 1 (correct), e.g. if answering "the horse is not black" should be considered half-right, then we should use `correct: [1, 0.5, 0]`. |
187 | 197 | ||
188 | Wrong answers discount by default. If there are half-right answers, the discount values are calculated automatically. `discount: False` disables the discount calculation and the values are the ones defined in `correct`. | 198 | Wrong answers discount by default. If there are half-right answers, the discount values are calculated automatically. `discount: False` disables the discount calculation and the values are the ones defined in `correct`. |
@@ -191,20 +201,22 @@ Wrong answers discount by default. If there are half-right answers, the discount | @@ -191,20 +201,22 @@ Wrong answers discount by default. If there are half-right answers, the discount | ||
191 | 201 | ||
192 | There can be several options correct. Each option is like answering an independent question. | 202 | There can be several options correct. Each option is like answering an independent question. |
193 | 203 | ||
194 | - - | ||
195 | - ref: some-key | ||
196 | - type: checkbox | ||
197 | - text: The horse is white. # optional (default: '') | ||
198 | - options: | ||
199 | - - The horse is white | ||
200 | - - The horse is not black | ||
201 | - - The horse is black | ||
202 | - correct: [1,1,-1] # optional (default: [0,0,0]). | ||
203 | - shuffle: True # optional (default: True) | ||
204 | - discount: True # optional (default: True) | ||
205 | - | 204 | +```yaml |
205 | +- | ||
206 | + ref: some-key | ||
207 | + type: checkbox | ||
208 | + text: The horse is white. # optional (default: '') | ||
209 | + options: | ||
210 | + - The horse is white | ||
211 | + - The horse is not black | ||
212 | + - The horse is black | ||
213 | + correct: [1,1,-1] # optional (default: [0,0,0]). | ||
214 | + shuffle: True # optional (default: True) | ||
215 | + discount: True # optional (default: True) | ||
216 | +``` | ||
206 | Wrong answers discount by default. The discount values are calculated automatically and are simply the symmetric of the correct value. | 217 | Wrong answers discount by default. The discount values are calculated automatically and are simply the symmetric of the correct value. |
207 | E.g. consider `correct: [1, 0.5, -1]`, then | 218 | E.g. consider `correct: [1, 0.5, -1]`, then |
219 | + | ||
208 | - if the first option is marked the value is 1, otherwise if it's unmarked the value is -1. | 220 | - if the first option is marked the value is 1, otherwise if it's unmarked the value is -1. |
209 | - if the second option is marked the value is 0.5, otherwise if it's unmarked the value is -0.5. | 221 | - if the second option is marked the value is 0.5, otherwise if it's unmarked the value is -0.5. |
210 | - if the third option is marked the value is -1, otherwise if it's unmarked the value is 1. (the student shouldn't have marked this one) | 222 | - if the third option is marked the value is -1, otherwise if it's unmarked the value is 1. (the student shouldn't have marked this one) |
@@ -216,26 +228,29 @@ E.g. consider `correct: [1, 0.5, -1]`, then | @@ -216,26 +228,29 @@ E.g. consider `correct: [1, 0.5, -1]`, then | ||
216 | The answer is a line of text. | 228 | The answer is a line of text. |
217 | The server will check if the answer exactly matches the correct one. | 229 | The server will check if the answer exactly matches the correct one. |
218 | 230 | ||
219 | - - | ||
220 | - ref: some-key | ||
221 | - type: text | ||
222 | - text: What's your favorite color? # optional (default: '') | ||
223 | - correct: white | ||
224 | - | 231 | +```yaml |
232 | +- | ||
233 | + ref: some-key | ||
234 | + type: text | ||
235 | + text: What's your favorite color? # optional (default: '') | ||
236 | + correct: white | ||
237 | +``` | ||
225 | alternatively, we can give a list of acceptable answers | 238 | alternatively, we can give a list of acceptable answers |
226 | - | ||
227 | - correct: ['white', 'blue', 'red'] | ||
228 | - | 239 | +```yaml |
240 | + correct: ['white', 'blue', 'red'] | ||
241 | +``` | ||
229 | ### Regular expression | 242 | ### Regular expression |
230 | 243 | ||
231 | The answer is a line of text. | 244 | The answer is a line of text. |
232 | The server will check if the answer matches a regular expression. | 245 | The server will check if the answer matches a regular expression. |
233 | 246 | ||
234 | - - | ||
235 | - ref: some-key | ||
236 | - type: text_regex | ||
237 | - text: What's your favorite color? # optional (default: '') | ||
238 | - correct: '[Ww]hite' | 247 | +```yaml |
248 | +- | ||
249 | + ref: some-key | ||
250 | + type: text_regex | ||
251 | + text: What's your favorite color? # optional (default: '') | ||
252 | + correct: '[Ww]hite' | ||
253 | +``` | ||
239 | 254 | ||
240 | Careful: yaml does not support raw text. Some characters have to be escaped. | 255 | Careful: yaml does not support raw text. Some characters have to be escaped. |
241 | 256 | ||
@@ -245,23 +260,27 @@ The answer is given in a textarea. The text (usually code) is sent to an externa | @@ -245,23 +260,27 @@ The answer is given in a textarea. The text (usually code) is sent to an externa | ||
245 | The external program should accept input from stdin, and print to stdout a single number in the interval 0.0 to 1.0 indicating the level of correctness. | 260 | The external program should accept input from stdin, and print to stdout a single number in the interval 0.0 to 1.0 indicating the level of correctness. |
246 | The server will try to convert the printed message to a float, a failure will give 0.0. | 261 | The server will try to convert the printed message to a float, a failure will give 0.0. |
247 | 262 | ||
248 | - - | ||
249 | - ref: some-key | ||
250 | - type: textarea | ||
251 | - text: write an expression to add x and y. # optional (default: '') | ||
252 | - correct: path/to/myscript | 263 | +```yaml |
264 | +- | ||
265 | + ref: some-key | ||
266 | + type: textarea | ||
267 | + text: write an expression to add x and y. # optional (default: '') | ||
268 | + correct: path/to/myscript | ||
269 | +``` | ||
253 | 270 | ||
254 | An example of a script in python that validades an answer is | 271 | An example of a script in python that validades an answer is |
255 | 272 | ||
256 | - #!/usr/bin/env python3.4 | 273 | +```python |
274 | +#!/usr/bin/env python3.4 | ||
257 | 275 | ||
258 | - import sys | ||
259 | - s = sys.stdin.read() | ||
260 | - if s == 'Alibaba': | ||
261 | - print(1.0) | ||
262 | - else: | ||
263 | - print(0.0) | ||
264 | - exit(0) | 276 | +import sys |
277 | +s = sys.stdin.read() | ||
278 | +if s == 'Alibaba': | ||
279 | + print(1.0) | ||
280 | +else: | ||
281 | + print(0.0) | ||
282 | +exit(0) | ||
283 | +``` | ||
265 | 284 | ||
266 | but any script language or executable program can be used for this purpose. | 285 | but any script language or executable program can be used for this purpose. |
267 | 286 | ||
@@ -270,25 +289,38 @@ but any script language or executable program can be used for this purpose. | @@ -270,25 +289,38 @@ but any script language or executable program can be used for this purpose. | ||
270 | 289 | ||
271 | A generator question will run an external program that is expected to print a question in yaml format to stdout. After running the generator, the question can be any of the other types (but not another generator!). | 290 | A generator question will run an external program that is expected to print a question in yaml format to stdout. After running the generator, the question can be any of the other types (but not another generator!). |
272 | 291 | ||
273 | - - | ||
274 | - ref: some-key | ||
275 | - type: generator | ||
276 | - script: path/to/generator_script | 292 | +```yaml |
293 | +- | ||
294 | + ref: some-key | ||
295 | + type: generator | ||
296 | + script: path/to/generator_script | ||
297 | + # arg: "optional string passed on to stdin of the script" | ||
298 | +``` | ||
277 | 299 | ||
278 | An example of a question generator is the following | 300 | An example of a question generator is the following |
279 | 301 | ||
280 | - #!/usr/bin/env python3.4 | ||
281 | - from random import randint | ||
282 | - | ||
283 | - x = randint(10,20) | ||
284 | - y = randint(10,20) | ||
285 | - s = ''' | ||
286 | - ref: addition | ||
287 | - type: text | ||
288 | - text: How much is {0} plus {1}? | ||
289 | - correct: {2} | ||
290 | - '''.format(x, y, x + y) | ||
291 | - print(s) | 302 | +```python |
303 | +#!/usr/bin/env python3.4 | ||
304 | +from random import randint | ||
305 | +import sys | ||
306 | + | ||
307 | +# read arguments from stdin and convert to integers | ||
308 | +arg = sys.stdin.read() | ||
309 | +a,b = (int(n) for n in arg.split(',')) | ||
310 | + | ||
311 | +# generate question | ||
312 | +x = randint(a, b) | ||
313 | +y = randint(a, b) | ||
314 | +s = ''' | ||
315 | +ref: addition | ||
316 | +type: text | ||
317 | +text: How much is {0} plus {1}? | ||
318 | +correct: {2} | ||
319 | +'''.format(x, y, x + y) | ||
320 | + | ||
321 | +# send question to stdout | ||
322 | +print(s) | ||
323 | +``` | ||
292 | 324 | ||
293 | ## Writing good looking questions | 325 | ## Writing good looking questions |
294 | 326 | ||
@@ -296,13 +328,16 @@ The text of the questions (and options in radio and checkbox type questios) is p | @@ -296,13 +328,16 @@ The text of the questions (and options in radio and checkbox type questios) is p | ||
296 | 328 | ||
297 | A good way to define multiple lines of text in the questions is to use the bar |. Yaml will use all the text that is indented to the right of that column. Example | 329 | A good way to define multiple lines of text in the questions is to use the bar |. Yaml will use all the text that is indented to the right of that column. Example |
298 | 330 | ||
299 | - text: | | ||
300 | - Text is parsed as __markdown__. We can include equations $\sqrt{\pi}$ like in LaTeX | ||
301 | - and pretty code in several languages | 331 | +```yaml |
332 | + text: | | ||
333 | + Text is parsed as __markdown__. We can include equations $\sqrt{\pi}$ like in LaTeX | ||
334 | + and pretty code in several languages | ||
335 | + | ||
336 | + ```.C | ||
337 | + int main(){ | ||
338 | + return 0; | ||
339 | + } | ||
340 | + ``` | ||
341 | + # this line stops the text because it is not indented | ||
342 | +``` | ||
302 | 343 | ||
303 | - ```.C | ||
304 | - int main(){ | ||
305 | - return 0; | ||
306 | - } | ||
307 | - ``` | ||
308 | - # this line does stops the text because it is not indented |
demo/generate-question.py
1 | #!/usr/bin/env python3.4 | 1 | #!/usr/bin/env python3.4 |
2 | 2 | ||
3 | from random import randint | 3 | from random import randint |
4 | +import sys | ||
4 | 5 | ||
6 | +arg = sys.stdin.read() # read arguments | ||
7 | + | ||
8 | +a,b = (int(n) for n in arg.split(',')) | ||
5 | 9 | ||
6 | q = ''' | 10 | q = ''' |
7 | type: checkbox | 11 | type: checkbox |
8 | -text: Indique quais das seguintes adições resultam em overflow quando se considera a adição de números com sinal (complemento para 2) em registos de 8 bits. | 12 | +text: | |
13 | + Indique quais das seguintes adições resultam em overflow quando se considera a adição de números com sinal (complemento para 2) em registos de 8 bits. | ||
14 | + | ||
15 | + Os números foram gerados aleatoriamente no intervalo de {0} a {1}. | ||
9 | options: | 16 | options: |
10 | -''' | 17 | +'''.format(a,b) |
11 | 18 | ||
12 | correct = [] | 19 | correct = [] |
13 | for i in range(5): | 20 | for i in range(5): |
14 | - x = randint(11,120) | ||
15 | - y = randint(11,120) | 21 | + x = randint(a, b) |
22 | + y = randint(a, b) | ||
16 | q += '- "`{} + {}`"\n'.format(x, y) | 23 | q += '- "`{} + {}`"\n'.format(x, y) |
17 | correct.append(1 if x + y > 127 else -1) | 24 | correct.append(1 if x + y > 127 else -1) |
18 | 25 |
demo/questions.yaml
@@ -51,6 +51,7 @@ | @@ -51,6 +51,7 @@ | ||
51 | ref: question-whatever | 51 | ref: question-whatever |
52 | type: generator | 52 | type: generator |
53 | script: demo/generate-question.py | 53 | script: demo/generate-question.py |
54 | + arg: "11,120" | ||
54 | # the script should print a question in yaml format like the ones above. | 55 | # the script should print a question in yaml format like the ones above. |
55 | # Print only the dictionary, not the list (hiffen). | 56 | # Print only the dictionary, not the list (hiffen). |
56 | # --------------------------------------------------------------------------- | 57 | # --------------------------------------------------------------------------- |
questions.py
@@ -114,7 +114,7 @@ def question_generator(q): | @@ -114,7 +114,7 @@ def question_generator(q): | ||
114 | '''Run an external script that will generate a question in yaml format. | 114 | '''Run an external script that will generate a question in yaml format. |
115 | This function will return the yaml converted back to a dict.''' | 115 | This function will return the yaml converted back to a dict.''' |
116 | 116 | ||
117 | - q['stdin'] = q.get('stdin', '') | 117 | + q['arg'] = q.get('arg', '') # send this string to stdin |
118 | 118 | ||
119 | try: | 119 | try: |
120 | p = subprocess.Popen([q['script']], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) | 120 | p = subprocess.Popen([q['script']], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) |
@@ -122,7 +122,7 @@ def question_generator(q): | @@ -122,7 +122,7 @@ def question_generator(q): | ||
122 | print(' * Script "{0}" defined in question "{1}" of file "{2}" could not be found'.format(q['script'], q['ref'], q['filename'])) | 122 | print(' * Script "{0}" defined in question "{1}" of file "{2}" could not be found'.format(q['script'], q['ref'], q['filename'])) |
123 | 123 | ||
124 | try: | 124 | try: |
125 | - qyaml = p.communicate(input=q['stdin'].encode('utf-8'), timeout=5)[0].decode('utf-8') | 125 | + qyaml = p.communicate(input=q['arg'].encode('utf-8'), timeout=5)[0].decode('utf-8') |
126 | except subprocess.TimeoutExpired: | 126 | except subprocess.TimeoutExpired: |
127 | p.kill() | 127 | p.kill() |
128 | 128 |