Commit 31b2eb9f019cbc319be7a3bd6ddcd6961f15d1a9

Authored by Miguel Barão
1 parent 9e0e3d3c
Exists in master and in 1 other branch dev

add --correct option

Showing 2 changed files with 58 additions and 61 deletions   Show diff stats
perguntations/app.py
... ... @@ -8,6 +8,7 @@ Description: Main application logic.
8 8 import asyncio
9 9 import csv
10 10 import io
  11 +import json
11 12 import logging
12 13 import os
13 14 from typing import Optional
... ... @@ -23,6 +24,8 @@ import yaml
23 24 from .models import Student, Test, Question
24 25 from .tools import load_yaml
25 26 from .testfactory import TestFactory, TestFactoryException
  27 +from .test import Test as TestInstance
  28 +from .questions import question_from
26 29  
27 30 # setup logger for this module
28 31 logger = logging.getLogger(__name__)
... ... @@ -59,6 +62,8 @@ class App():
59 62 self._make_test_factory(config['testfile'])
60 63 self._db_setup() # setup engine and load all students
61 64  
  65 + asyncio.get_event_loop().run_until_complete(self._assign_tests())
  66 +
62 67 # command line options: --allow-all, --allow-list filename
63 68 if config['allow_all']:
64 69 self.allow_all_students()
... ... @@ -67,8 +72,8 @@ class App():
67 72 else:
68 73 logger.info('Students login not yet allowed')
69 74  
70   - # if config['correct']:
71   - # self._correct_tests()
  75 + if config['correct']:
  76 + self._correct_tests()
72 77  
73 78 # ------------------------------------------------------------------------
74 79 def _db_setup(self) -> None:
... ... @@ -255,65 +260,57 @@ class App():
255 260 session.commit()
256 261 logger.info('"%s" database updated.', uid)
257 262  
258   -# # ------------------------------------------------------------------------
259   -# def _correct_tests(self):
260   -# with Session(self._engine, future=True) as session:
261   -# # Find which tests have to be corrected
262   -# dbtests = session.execute(
263   -# select(Test).
264   -# where(Test.ref == self.testfactory['ref']).
265   -# where(Test.state == "SUBMITTED")
266   -# ).all()
267   -# # dbtests = session.query(Test)\
268   -# # .filter(Test.ref == self.testfactory['ref'])\
269   -# # .filter(Test.state == "SUBMITTED")\
270   -# # .all()
271   -
272   -# logger.info('Correcting %d tests...', len(dbtests))
273   -# for dbtest in dbtests:
274   -# try:
275   -# with open(dbtest.filename) as file:
276   -# testdict = json.load(file)
277   -# except FileNotFoundError:
278   -# logger.error('File not found: %s', dbtest.filename)
279   -# continue
280   -
281   -# # creates a class Test with the methods to correct it
282   -# # the questions are still dictionaries, so we have to call
283   -# # question_from() to produce Question() instances that can be
284   -# # corrected. Finally the test can be corrected.
285   -# test = perguntations.test.Test(testdict)
286   -# test['questions'] = [question_from(q) for q in test['questions']]
287   -# test.correct()
288   -# logger.info('Student %s: grade = %f', test['student']['number'], test['grade'])
289   -
290   -# # save JSON file (overwriting the old one)
291   -# uid = test['student']['number']
292   -# ref = test['ref']
293   -# finish_time = test['finish_time']
294   -# answers_dir = test['answers_dir']
295   -# fname = f'{uid}--{ref}--{finish_time}.json'
296   -# fpath = os.path.join(answers_dir, fname)
297   -# test.save_json(fpath)
298   -# logger.info('%s saved JSON file.', uid)
299   -
300   -# # update database
301   -# dbtest.grade = test['grade']
302   -# dbtest.state = test['state']
303   -# dbtest.questions = [
304   -# Question(
305   -# number=n,
306   -# ref=q['ref'],
307   -# grade=q['grade'],
308   -# comment=q.get('comment', ''),
309   -# starttime=str(test['start_time']),
310   -# finishtime=str(test['finish_time']),
311   -# test_id=test['ref']
312   -# )
313   -# for n, q in enumerate(test['questions'])
314   -# ]
315   -# logger.info('%s database updated.', uid)
  263 + # ------------------------------------------------------------------------
  264 + def _correct_tests(self) -> None:
  265 + with Session(self._engine, future=True) as session:
  266 + # Find which tests have to be corrected
  267 + query = select(Test) \
  268 + .where(Test.ref == self._testfactory['ref']) \
  269 + .where(Test.state == "SUBMITTED")
  270 + dbtests = session.execute(query).scalars().all()
  271 + if not dbtests:
  272 + logger.info('No tests to correct')
  273 + return
316 274  
  275 + logger.info('Correcting %d tests...', len(dbtests))
  276 + for dbtest in dbtests:
  277 + try:
  278 + with open(dbtest.filename) as file:
  279 + testdict = json.load(file)
  280 + except OSError:
  281 + logger.error('Failed: %s', dbtest.filename)
  282 + continue
  283 +
  284 + # creates a class Test with the methods to correct it
  285 + # the questions are still dictionaries, so we have to call
  286 + # question_from() to produce Question() instances that can be
  287 + # corrected. Finally the test can be corrected.
  288 + test = TestInstance(testdict)
  289 + test['questions'] = [question_from(q) for q in test['questions']]
  290 + test.correct()
  291 + logger.info(' %s: %f', test['student'], test['grade'])
  292 +
  293 + # save JSON file (overwriting the old one)
  294 + uid = test['student']
  295 + test.save_json(dbtest.filename)
  296 + logger.debug('%s saved JSON file.', uid)
  297 +
  298 + # update database
  299 + dbtest.grade = test['grade']
  300 + dbtest.state = test['state']
  301 + dbtest.questions = [
  302 + Question(
  303 + number=n,
  304 + ref=q['ref'],
  305 + grade=q['grade'],
  306 + comment=q.get('comment', ''),
  307 + starttime=str(test['start_time']),
  308 + finishtime=str(test['finish_time']),
  309 + test_id=test['ref']
  310 + ) for n, q in enumerate(test['questions'])
  311 + ]
  312 + session.commit()
  313 + logger.info('Database updated')
317 314  
318 315 # ------------------------------------------------------------------------
319 316 # def giveup_test(self, uid):
... ...
perguntations/main.py
... ... @@ -76,7 +76,7 @@ def get_logger_config(debug=False) -> dict:
76 76 dateformat = ''
77 77 else:
78 78 level = 'INFO'
79   - fmt = '%(asctime)s |%(levelname)-8s| %(message)s'
  79 + fmt = '%(asctime)s| %(levelname)-8s| %(message)s'
80 80 dateformat = '%Y-%m-%d %H:%M:%S'
81 81 modules = ['main', 'serve', 'app', 'models', 'questions', 'test',
82 82 'testfactory', 'tools']
... ...