Commit 6bd5c0063bc65b6b402407251f3c60fb80836ede
1 parent
d378e701
Exists in
master
and in
1 other branch
converted test generation to be done asynchronously.
Showing
4 changed files
with
38 additions
and
32 deletions
Show diff stats
BUGS.md
1 | 1 | |
2 | 2 | # BUGS |
3 | 3 | |
4 | +- numeric interval deve converter respostas que usam virgulas para pontos decimais | |
4 | 5 | - a revisao do teste não mostra as imagens. |
5 | 6 | - se aluno tem teste activo e é allowed uma segunda vez, deve manter o mesmo teste. adicionar opcao para eliminar um teste em curso. |
6 | 7 | - melhorar o botao de autorizar (desliga-se), usar antes um botao? | ... | ... |
app.py
... | ... | @@ -136,16 +136,16 @@ class App(object): |
136 | 136 | logger.info(f'Student {uid}: logged out.') |
137 | 137 | |
138 | 138 | # ----------------------------------------------------------------------- |
139 | - def generate_test(self, uid): | |
139 | + async def generate_test(self, uid): | |
140 | 140 | if uid in self.online: |
141 | 141 | logger.info(f'Student {uid}: generating new test.') |
142 | 142 | student_id = self.online[uid]['student'] |
143 | - self.online[uid]['test'] = self.testfactory.generate(student_id) | |
143 | + self.online[uid]['test'] = await self.testfactory.generate(student_id) | |
144 | + logger.debug(f'Student {uid}: test ok.') | |
144 | 145 | return self.online[uid]['test'] |
145 | 146 | else: |
146 | 147 | # this implies an error in the code. should never be here! |
147 | 148 | logger.critical(f'Student {uid}: offline, can\'t generate test') |
148 | - return None | |
149 | 149 | |
150 | 150 | # ----------------------------------------------------------------------- |
151 | 151 | # ans is a dictionary {question_index: answer, ...} | ... | ... |
serve.py
... | ... | @@ -24,7 +24,7 @@ from app import App, AppException |
24 | 24 | from tools import load_yaml, md_to_html |
25 | 25 | |
26 | 26 | # ---------------------------------------------------------------------------- |
27 | -# Decorator used to restrict access only to the administrator | |
27 | +# Decorator used to restrict access to the administrator | |
28 | 28 | # ---------------------------------------------------------------------------- |
29 | 29 | def admin_only(func): |
30 | 30 | @functools.wraps(func) |
... | ... | @@ -96,7 +96,7 @@ class LoginHandler(BaseHandler): |
96 | 96 | self.set_secure_cookie("user", str(uid), expires_days=30) |
97 | 97 | self.redirect(self.get_argument("next", "/")) |
98 | 98 | else: |
99 | - self.render("login.html", error='Não autorizado ou número/senha inválido') | |
99 | + self.render("login.html", error='Não autorizado ou senha inválida') | |
100 | 100 | |
101 | 101 | |
102 | 102 | # ---------------------------------------------------------------------------- |
... | ... | @@ -199,10 +199,11 @@ class TestHandler(BaseHandler): |
199 | 199 | |
200 | 200 | # --- GET |
201 | 201 | @tornado.web.authenticated |
202 | - def get(self): | |
202 | + async def get(self): | |
203 | 203 | uid = self.current_user |
204 | - # FIXME make generate async? | |
205 | - t = self.testapp.get_student_test(uid) or self.testapp.generate_test(uid) | |
204 | + t = self.testapp.get_student_test(uid) # reload page returns same test | |
205 | + if t is None: | |
206 | + t = await self.testapp.generate_test(uid) | |
206 | 207 | self.render('test.html', t=t, md=md_to_html, templ=self._templates) |
207 | 208 | |
208 | 209 | # --- POST | ... | ... |
test.py
... | ... | @@ -6,6 +6,7 @@ import random |
6 | 6 | from datetime import datetime |
7 | 7 | import json |
8 | 8 | import logging |
9 | +import asyncio | |
9 | 10 | |
10 | 11 | # this project |
11 | 12 | import questionfactory as questions |
... | ... | @@ -36,29 +37,30 @@ class TestFactory(dict): |
36 | 37 | |
37 | 38 | if conf['review']: |
38 | 39 | logger.info('Review mode. No questions loaded.') |
39 | - else: | |
40 | - # loads yaml files to question_factory | |
41 | - self.question_factory = questions.QuestionFactory() | |
42 | - self.question_factory.load_files(files=self['files'], questions_dir=self['questions_dir']) | |
43 | - | |
44 | - # check if all questions exist ('ref' keys are correct?) | |
45 | - errors_found = False | |
46 | - for q in self['questions']: | |
47 | - for r in q['ref']: | |
48 | - logger.info(f'Checking question "{r}".') | |
49 | - try: | |
50 | - self.question_factory.generate(r) | |
51 | - # except questions.QuestionFactoryException: | |
52 | - # logger.critical(f'Can\'t generate question "{r}".') | |
53 | - except: | |
54 | - logger.critical(f'Can\'t generate question "{r}".') | |
55 | - errors_found = True | |
56 | - | |
57 | - if errors_found: | |
58 | - logger.critical('Errors found while generating questions.') | |
59 | - raise TestFactoryException() | |
40 | + return | |
60 | 41 | |
61 | - logger.info(f'Test factory ready for "{self["ref"]}".') | |
42 | + # loads yaml files to question_factory | |
43 | + self.question_factory = questions.QuestionFactory() | |
44 | + self.question_factory.load_files(files=self['files'], questions_dir=self['questions_dir']) | |
45 | + | |
46 | + # check if all questions exist ('ref' keys are correct?) | |
47 | + errors_found = False | |
48 | + for q in self['questions']: | |
49 | + for r in q['ref']: | |
50 | + logger.info(f'Checking question "{r}".') | |
51 | + try: | |
52 | + self.question_factory.generate(r) | |
53 | + # except questions.QuestionFactoryException: | |
54 | + # logger.critical(f'Can\'t generate question "{r}".') | |
55 | + except: | |
56 | + logger.critical(f'Can\'t generate question "{r}".') | |
57 | + errors_found = True | |
58 | + | |
59 | + if errors_found: | |
60 | + logger.critical('Errors found while generating questions.') | |
61 | + raise TestFactoryException() | |
62 | + | |
63 | + logger.info(f'Test factory ready for "{self["ref"]}".') | |
62 | 64 | |
63 | 65 | |
64 | 66 | # ----------------------------------------------------------------------- |
... | ... | @@ -144,17 +146,19 @@ class TestFactory(dict): |
144 | 146 | # Given a dictionary with a student id {'name':'john', 'number': 123} |
145 | 147 | # returns instance of Test() for that particular student |
146 | 148 | # ----------------------------------------------------------------------- |
147 | - def generate(self, student): | |
149 | + async def generate(self, student): | |
148 | 150 | test = [] |
149 | 151 | total_points = 0.0 |
150 | 152 | |
151 | 153 | n = 1 |
154 | + loop = asyncio.get_running_loop() | |
155 | + | |
152 | 156 | for qq in self['questions']: |
153 | 157 | # generate Question() selected randomly from list of references |
154 | 158 | qref = random.choice(qq['ref']) |
155 | 159 | |
156 | 160 | try: |
157 | - q = self.question_factory.generate(qref) | |
161 | + q = await loop.run_in_executor(None, self.question_factory.generate, qref) | |
158 | 162 | except: |
159 | 163 | logger.error(f'Can\'t generate question "{qref}". Skipping.') |
160 | 164 | continue | ... | ... |