Commit 1c00dfe6dc95c9382c8994292d5c6d133b6d8bfc
1 parent
2f37bba0
Exists in
master
and in
1 other branch
- improved separation between questions, tests and html server.
- code cleanup.
Showing
3 changed files
with
34 additions
and
26 deletions
Show diff stats
questions.py
... | ... | @@ -401,7 +401,6 @@ class QuestionInformation(Question): |
401 | 401 | '''An instance of QuestionInformation will always have the keys: |
402 | 402 | type (str) |
403 | 403 | text (str) |
404 | - answer (None or an actual answer) | |
405 | 404 | points (0.0) |
406 | 405 | ''' |
407 | 406 | #------------------------------------------------------------------------ |
... | ... | @@ -409,8 +408,7 @@ class QuestionInformation(Question): |
409 | 408 | # create key/values as given in q |
410 | 409 | super().__init__(q) |
411 | 410 | self['text'] = self.get('text', '') |
412 | - self['answer'] = None | |
413 | - self['points'] = 0.0 # FIXME shouldnt be defined on the test??? | |
411 | + self['points'] = 0.0 # always override the points | |
414 | 412 | |
415 | 413 | #------------------------------------------------------------------------ |
416 | 414 | # can return negative values for wrong answers | ... | ... |
serve.py
... | ... | @@ -106,22 +106,22 @@ class Root(object): |
106 | 106 | ans = {} |
107 | 107 | for q in t['questions']: |
108 | 108 | if 'answered-' + q['ref'] in kwargs: |
109 | - ans[q['ref']] = kwargs.get(q['ref'], None) | |
109 | + # HACK: checkboxes in html return None instead of an empty list | |
110 | + # we have to manualy replace by [] | |
111 | + default_ans = [] if q['type'] == 'checkbox' else None | |
112 | + ans[q['ref']] = kwargs.get(q['ref'], default_ans) | |
110 | 113 | |
111 | 114 | # store the answers in the Test, correct it, save JSON and |
112 | 115 | # store results in the database |
113 | 116 | t.update_answers(ans) |
114 | - # try: | |
115 | 117 | t.correct() |
116 | - # except: | |
117 | - # cherrypy.log.error('Failed to correct test of student %s' % t['number'], 'APPLICATION') | |
118 | - # t['grade'] = None | |
119 | 118 | |
120 | 119 | if t['save_answers']: |
121 | 120 | t.save_json(self.testconf['answers_dir']) |
122 | 121 | self.database.save_test(t) |
123 | 122 | |
124 | 123 | if t['practice']: |
124 | + # ---- Repeat the test ---- | |
125 | 125 | raise cherrypy.HTTPRedirect('/test') |
126 | 126 | |
127 | 127 | else: | ... | ... |
test.py
1 | 1 | |
2 | -import os | |
2 | +import os, sys | |
3 | 3 | import random |
4 | 4 | import yaml |
5 | 5 | import json |
6 | 6 | import sqlite3 |
7 | 7 | from datetime import datetime |
8 | + | |
9 | +# my code | |
8 | 10 | import questions |
9 | 11 | import database |
10 | 12 | |
... | ... | @@ -13,10 +15,14 @@ def read_configuration(filename, debug=False, show_points=False, show_hints=Fals |
13 | 15 | # FIXME validar se ficheiros e directorios existem??? |
14 | 16 | if not os.path.isfile(filename): |
15 | 17 | print('Cannot find file "%s"' % filename) |
16 | - os.sys.exit(1) | |
18 | + sys.exit(1) | |
17 | 19 | |
18 | - with open(filename, 'r') as f: | |
19 | - test = yaml.load(f) | |
20 | + try: | |
21 | + with open(filename, 'r') as f: | |
22 | + test = yaml.load(f) | |
23 | + except: | |
24 | + print('Error reading yaml file "{0}".'.format(filename)) | |
25 | + raise | |
20 | 26 | |
21 | 27 | # defaults: |
22 | 28 | test['ref'] = str(test.get('ref', filename)) |
... | ... | @@ -35,7 +41,7 @@ def read_configuration(filename, debug=False, show_points=False, show_hints=Fals |
35 | 41 | |
36 | 42 | if 'database' not in test: |
37 | 43 | print(' * Missing database in the test configuration.') |
38 | - os.sys.exit(1) | |
44 | + sys.exit(1) | |
39 | 45 | |
40 | 46 | if isinstance(test['files'], str): |
41 | 47 | test['files'] = [test['files']] |
... | ... | @@ -48,21 +54,31 @@ def read_configuration(filename, debug=False, show_points=False, show_hints=Fals |
48 | 54 | # each question is a list of alternative versions, even if the list |
49 | 55 | # contains only one element |
50 | 56 | if isinstance(q, str): |
51 | - # questions: some_ref --> questions: [{'ref':'some_ref', 'points':1.0, ...}] | |
52 | - test['questions'][i] = [pool[q]] | |
57 | + # normalize question to a dict | |
58 | + # - some_ref | |
59 | + # becomes | |
60 | + # - ref: some_ref | |
61 | + # points: 1.0 | |
62 | + test['questions'][i] = [pool[q]] # list with just one question | |
53 | 63 | test['questions'][i][0]['points'] = 1.0 |
64 | + # Note: at this moment we do not know the questions types. | |
65 | + # Some questions, like information, should have default points | |
66 | + # set to 0. That must be done later when the question is | |
67 | + # instantiated. | |
54 | 68 | |
55 | 69 | elif isinstance(q, dict): |
56 | 70 | if isinstance(q['ref'], str): |
57 | - q['ref'] = [q['ref']] | |
58 | - | |
59 | - p = float(q.get('points', 1.0)) | |
71 | + q['ref'] = [q['ref']] # ref is always a list | |
72 | + p = float(q.get('points', 1.0)) # default points is 1.0 | |
60 | 73 | |
74 | + # create list of alternatives, normalized | |
61 | 75 | l = [] |
62 | 76 | for r in q['ref']: |
63 | 77 | qq = pool[r] |
64 | 78 | qq['points'] = p |
65 | 79 | l.append(qq) |
80 | + | |
81 | + # add question (i.e. list of alternatives) to the test | |
66 | 82 | test['questions'][i] = l |
67 | 83 | |
68 | 84 | return test |
... | ... | @@ -85,14 +101,8 @@ class Test(dict): |
85 | 101 | '''given a dictionary ans={'ref':'some answer'} updates the answers |
86 | 102 | of the test. FIXME: check if answer is to be corrected or not |
87 | 103 | ''' |
88 | - for i, q in enumerate(self['questions']): | |
89 | - if q['ref'] in ans: | |
90 | - if q['type'] == 'checkbox' and ans[q['ref']] == None: | |
91 | - # HACK: checkboxes in html return none instead of an empty list | |
92 | - # we have to manualy replace by [] | |
93 | - q['answer'] = [] | |
94 | - else: | |
95 | - q['answer'] = ans[q['ref']] | |
104 | + for q in self['questions']: | |
105 | + q['answer'] = ans[q['ref']] if q['ref'] in ans else None | |
96 | 106 | |
97 | 107 | # ----------------------------------------------------------------------- |
98 | 108 | def correct(self): | ... | ... |