Commit 84a1054c11302b9054394629529b2363450a5d45
1 parent
64f0b75c
Exists in
master
and in
1 other branch
- Each student is represented by a class Knowledge and checks answers and generates new questions..
- The learn app deals with multiple users, login/logout and database.
Showing
3 changed files
with
51 additions
and
51 deletions
Show diff stats
app.py
| 1 | 1 | ||
| 2 | -import random | 2 | +# python standard library |
| 3 | from contextlib import contextmanager # `with` statement in db sessions | 3 | from contextlib import contextmanager # `with` statement in db sessions |
| 4 | -from datetime import datetime | ||
| 5 | import logging | 4 | import logging |
| 6 | 5 | ||
| 7 | # user installed libraries | 6 | # user installed libraries |
| @@ -14,8 +13,8 @@ except ImportError: | @@ -14,8 +13,8 @@ except ImportError: | ||
| 14 | sys.exit(1) | 13 | sys.exit(1) |
| 15 | 14 | ||
| 16 | # this project | 15 | # this project |
| 17 | -import questions | ||
| 18 | from models import Student, Answer | 16 | from models import Student, Answer |
| 17 | +from knowledge import Knowledge | ||
| 19 | 18 | ||
| 20 | # setup logger for this module | 19 | # setup logger for this module |
| 21 | logger = logging.getLogger(__name__) | 20 | logger = logging.getLogger(__name__) |
| @@ -25,18 +24,15 @@ logger = logging.getLogger(__name__) | @@ -25,18 +24,15 @@ logger = logging.getLogger(__name__) | ||
| 25 | # ============================================================================ | 24 | # ============================================================================ |
| 26 | class LearnApp(object): | 25 | class LearnApp(object): |
| 27 | def __init__(self): | 26 | def __init__(self): |
| 28 | - self.factory = questions.QuestionFactory() | ||
| 29 | - self.factory.load_files(['questions.yaml'], 'demo') # FIXME | ||
| 30 | self.online = {} | 27 | self.online = {} |
| 31 | 28 | ||
| 32 | # connect to database and check registered students | 29 | # connect to database and check registered students |
| 33 | db = 'students.db' # FIXME | 30 | db = 'students.db' # FIXME |
| 34 | engine = create_engine(f'sqlite:///{db}', echo=False) | 31 | engine = create_engine(f'sqlite:///{db}', echo=False) |
| 35 | - # self.Session = scoped_session(sessionmaker(bind=engine)) | ||
| 36 | self.Session = sessionmaker(bind=engine) | 32 | self.Session = sessionmaker(bind=engine) |
| 37 | try: | 33 | try: |
| 38 | with self.db_session() as s: | 34 | with self.db_session() as s: |
| 39 | - n = s.query(Student).count() # filter(Student.id != '0'). | 35 | + n = s.query(Student).count() |
| 40 | except Exception as e: | 36 | except Exception as e: |
| 41 | logger.critical('Database not usable.') | 37 | logger.critical('Database not usable.') |
| 42 | raise e | 38 | raise e |
| @@ -61,68 +57,37 @@ class LearnApp(object): | @@ -61,68 +57,37 @@ class LearnApp(object): | ||
| 61 | self.online[uid] = { | 57 | self.online[uid] = { |
| 62 | 'name': student.name, | 58 | 'name': student.name, |
| 63 | 'number': student.id, | 59 | 'number': student.id, |
| 64 | - 'current': None, | 60 | + 'knowledge': Knowledge(), # FIXME initial state? |
| 65 | } | 61 | } |
| 66 | - print(self.online) | 62 | + # print(self.online) |
| 67 | return True | 63 | return True |
| 68 | 64 | ||
| 69 | # ------------------------------------------------------------------------ | 65 | # ------------------------------------------------------------------------ |
| 70 | # logout | 66 | # logout |
| 71 | def logout(self, uid): | 67 | def logout(self, uid): |
| 72 | - del self.online[uid] # FIXME save current question? | ||
| 73 | - | ||
| 74 | - # ------------------------------------------------------------------------ | ||
| 75 | - def get_current_question(self, uid): | ||
| 76 | - return self.online[uid].get('current', None) | 68 | + del self.online[uid] # FIXME save current state |
| 77 | 69 | ||
| 78 | # ------------------------------------------------------------------------ | 70 | # ------------------------------------------------------------------------ |
| 79 | def get_student_name(self, uid): | 71 | def get_student_name(self, uid): |
| 80 | return self.online[uid].get('name', '') | 72 | return self.online[uid].get('name', '') |
| 81 | 73 | ||
| 82 | # ------------------------------------------------------------------------ | 74 | # ------------------------------------------------------------------------ |
| 83 | - # given the currect state, generates a new question for the student | ||
| 84 | - def new_question_for(self, uid): | ||
| 85 | - # FIXME | ||
| 86 | - questions = list(self.factory) | ||
| 87 | - nextquestion = self.factory.generate(random.choice(questions)) | ||
| 88 | - print(nextquestion) | ||
| 89 | - self.online[uid]['current'] = nextquestion | ||
| 90 | - return nextquestion | ||
| 91 | - | ||
| 92 | - # ------------------------------------------------------------------------ | ||
| 93 | # check answer and if correct returns new question, otherise returns None | 75 | # check answer and if correct returns new question, otherise returns None |
| 94 | def check_answer(self, uid, answer): | 76 | def check_answer(self, uid, answer): |
| 95 | - question = self.get_current_question(uid) | ||
| 96 | - print(question) | ||
| 97 | - print(answer) | ||
| 98 | - | ||
| 99 | - if question is not None: | ||
| 100 | - question['finish_time'] = datetime.now() | ||
| 101 | - grade = question.correct(answer) # correct answer | 77 | + knowledge = self.online[uid]['knowledge'] |
| 78 | + current_question = knowledge.check_answer(answer) | ||
| 102 | 79 | ||
| 80 | + if current_question is not None: | ||
| 103 | with self.db_session() as s: | 81 | with self.db_session() as s: |
| 104 | s.add(Answer( | 82 | s.add(Answer( |
| 105 | - ref=question['ref'], | ||
| 106 | - grade=question['grade'], | ||
| 107 | - starttime=str(question['start_time']), | ||
| 108 | - finishtime=str(question['finish_time']), | 83 | + ref=current_question['ref'], |
| 84 | + grade=current_question['grade'], | ||
| 85 | + starttime=str(current_question['start_time']), | ||
| 86 | + finishtime=str(current_question['finish_time']), | ||
| 109 | student_id=uid)) | 87 | student_id=uid)) |
| 110 | s.commit() | 88 | s.commit() |
| 111 | 89 | ||
| 112 | - correct = grade > 0.99999 | ||
| 113 | - if correct: | ||
| 114 | - print('CORRECT') | ||
| 115 | - question = self.new_question_for(uid) | ||
| 116 | - question['start_time'] = datetime.now() | ||
| 117 | - return question | ||
| 118 | - else: | ||
| 119 | - print('WRONG') | ||
| 120 | - return None | ||
| 121 | - else: | ||
| 122 | - print('FIRST QUESTION') | ||
| 123 | - question = self.new_question_for(uid) | ||
| 124 | - question['start_time'] = datetime.now() | ||
| 125 | - return question | 90 | + return knowledge.new_question() |
| 126 | 91 | ||
| 127 | # ------------------------------------------------------------------------ | 92 | # ------------------------------------------------------------------------ |
| 128 | # helper to manage db sessions using the `with` statement, for example | 93 | # helper to manage db sessions using the `with` statement, for example |
| @@ -0,0 +1,37 @@ | @@ -0,0 +1,37 @@ | ||
| 1 | + | ||
| 2 | +# python standard library | ||
| 3 | +import random | ||
| 4 | +from datetime import datetime | ||
| 5 | + | ||
| 6 | +# this project | ||
| 7 | +import questions | ||
| 8 | + | ||
| 9 | + | ||
| 10 | +# contains the kowledge state of each student. | ||
| 11 | +class Knowledge(object): | ||
| 12 | + def __init__(self): | ||
| 13 | + self.factory = questions.QuestionFactory() | ||
| 14 | + self.factory.load_files(['questions.yaml'], 'demo') # FIXME | ||
| 15 | + self.current_question = None | ||
| 16 | + | ||
| 17 | + def get_current_question(self): | ||
| 18 | + return self.current_question | ||
| 19 | + | ||
| 20 | + # --- generates a new question given the current state | ||
| 21 | + def new_question(self): | ||
| 22 | + # FIXME | ||
| 23 | + if self.current_question is None or self.current_question.get('grade', 0.0) > 0.9999: | ||
| 24 | + questions = list(self.factory) | ||
| 25 | + self.current_question = self.factory.generate(random.choice(questions)) | ||
| 26 | + self.current_question['start_time'] = datetime.now() | ||
| 27 | + | ||
| 28 | + return self.current_question | ||
| 29 | + | ||
| 30 | + # --- checks answer and updates knowledge state | ||
| 31 | + # returns current question with correction, time and comments updated | ||
| 32 | + def check_answer(self, answer): | ||
| 33 | + question = self.current_question | ||
| 34 | + if question is not None: | ||
| 35 | + question['finish_time'] = datetime.now() | ||
| 36 | + question.correct(answer) | ||
| 37 | + return question |
serve.py
| @@ -130,11 +130,9 @@ class QuestionHandler(BaseHandler): | @@ -130,11 +130,9 @@ class QuestionHandler(BaseHandler): | ||
| 130 | 130 | ||
| 131 | @tornado.web.authenticated | 131 | @tornado.web.authenticated |
| 132 | def post(self): | 132 | def post(self): |
| 133 | - print('================= POST ==============') | ||
| 134 | # ref = self.get_body_arguments('question_ref') | 133 | # ref = self.get_body_arguments('question_ref') |
| 135 | user = self.current_user | 134 | user = self.current_user |
| 136 | answer = self.get_body_arguments('answer') | 135 | answer = self.get_body_arguments('answer') |
| 137 | - | ||
| 138 | next_question = self.learn.check_answer(user, answer) | 136 | next_question = self.learn.check_answer(user, answer) |
| 139 | 137 | ||
| 140 | if next_question is not None: | 138 | if next_question is not None: |