Commit 9161ff755aa99eb0ba6ef8e0cd109e56a68422fd
1 parent
c1422ade
Exists in
master
and in
1 other branch
choose number of questions per topic in the yaml configuration
Showing
5 changed files
with
18 additions
and
42 deletions
Show diff stats
BUGS.md
@@ -5,10 +5,6 @@ | @@ -5,10 +5,6 @@ | ||
5 | "file: questions.yaml" (default questions.yaml) | 5 | "file: questions.yaml" (default questions.yaml) |
6 | "shuffle: True/False" (default False) | 6 | "shuffle: True/False" (default False) |
7 | "choose: 6" (default tudo) | 7 | "choose: 6" (default tudo) |
8 | -- SQLAlchemy error (rollback em accao no final de um topico): | ||
9 | - Users/mjsb/Library/Python/3.7/lib/python/site-packages/sqlalchemy/sql/crud.py:700: SAWarning: Column 'studenttopic.student_id' is marked as a member of the primary key for table 'studenttopic', but has no Python-side or server-side default generator indicated, nor does it indicate 'autoincrement=True' or 'nullable=True', and no explicit value is passed. Primary key columns typically may not store NULL. Note that as of SQLAlchemy 1.1, 'autoincrement=True' must be indicated explicitly for composite (e.g. multicolumn) primary keys if AUTO_INCREMENT/SERIAL/IDENTITY behavior is expected for one of the columns in the primary key. CREATE TABLE statements are impacted by this change as well on most backends. | ||
10 | - util.warn(msg) | ||
11 | - | ||
12 | - quando a pergunta devolve comments, este é apresentado, mas fica persistente nas tentativas seguintes. devia ser limpo apos a segunda submissao. | 8 | - quando a pergunta devolve comments, este é apresentado, mas fica persistente nas tentativas seguintes. devia ser limpo apos a segunda submissao. |
13 | - a opcao max_tries na especificacao das perguntas é cumbersome... usar antes tries? | 9 | - a opcao max_tries na especificacao das perguntas é cumbersome... usar antes tries? |
14 | - tabelas nas perguntas radio/checkbox não ocupam todo o espaço como em question. | 10 | - tabelas nas perguntas radio/checkbox não ocupam todo o espaço como em question. |
demo/demo.yaml
1 | title: Example | 1 | title: Example |
2 | database: students.db | 2 | database: students.db |
3 | 3 | ||
4 | +# default global values | ||
5 | +file: questions.yaml | ||
6 | +shuffle: True | ||
7 | +choose: 6 | ||
8 | + | ||
4 | # path prefix applied to the topics | 9 | # path prefix applied to the topics |
5 | path: ./demo | 10 | path: ./demo |
6 | 11 | ||
@@ -16,6 +21,9 @@ topics: | @@ -16,6 +21,9 @@ topics: | ||
16 | # topic without dependencies | 21 | # topic without dependencies |
17 | math: | 22 | math: |
18 | name: Matemática | 23 | name: Matemática |
24 | + file: questions.yaml | ||
25 | + choose: 6 | ||
26 | + shuffle: True | ||
19 | 27 | ||
20 | # topic with one dependency | 28 | # topic with one dependency |
21 | solar_system: | 29 | solar_system: |
knowledge.py
@@ -32,8 +32,8 @@ class StudentKnowledge(object): | @@ -32,8 +32,8 @@ class StudentKnowledge(object): | ||
32 | self.topic_sequence = self.recommend_topic_sequence() # ['a', 'b', ...] | 32 | self.topic_sequence = self.recommend_topic_sequence() # ['a', 'b', ...] |
33 | self.unlock_topics() # whose dependencies have been done | 33 | self.unlock_topics() # whose dependencies have been done |
34 | self.current_topic = None | 34 | self.current_topic = None |
35 | - | ||
36 | - self.MAX_QUESTIONS = 6 # FIXME get from yaml configuration file?? | 35 | + print(deps.graph) |
36 | + self.MAX_QUESTIONS = deps.graph['config'].get('choose', 10) | ||
37 | 37 | ||
38 | # ------------------------------------------------------------------------ | 38 | # ------------------------------------------------------------------------ |
39 | # Updates the proficiency levels of the topics, with forgetting factor | 39 | # Updates the proficiency levels of the topics, with forgetting factor |
learnapp.py
@@ -29,11 +29,9 @@ class LearnAppException(Exception): | @@ -29,11 +29,9 @@ class LearnAppException(Exception): | ||
29 | # ============================================================================ | 29 | # ============================================================================ |
30 | # helper functions | 30 | # helper functions |
31 | # ============================================================================ | 31 | # ============================================================================ |
32 | -async def check_password(try_pw, password): | ||
33 | - try_pw = try_pw.encode('utf-8') | 32 | +async def check_password(try_pw, pw): |
34 | loop = asyncio.get_running_loop() | 33 | loop = asyncio.get_running_loop() |
35 | - hashed_pw = await loop.run_in_executor(None, bcrypt.hashpw, try_pw, password) | ||
36 | - return password == hashed_pw | 34 | + return pw == await loop.run_in_executor(None, bcrypt.hashpw, try_pw.encode('utf-8'), pw) |
37 | 35 | ||
38 | def bcrypt_hash_gen(pw): | 36 | def bcrypt_hash_gen(pw): |
39 | return bcrypt.hashpw(pw.encode('utf-8'), bcrypt.gensalt()) | 37 | return bcrypt.hashpw(pw.encode('utf-8'), bcrypt.gensalt()) |
@@ -62,16 +60,9 @@ class LearnApp(object): | @@ -62,16 +60,9 @@ class LearnApp(object): | ||
62 | def __init__(self, config_file): | 60 | def __init__(self, config_file): |
63 | # state of online students | 61 | # state of online students |
64 | self.online = {} | 62 | self.online = {} |
65 | - | ||
66 | - config = load_yaml(config_file) | ||
67 | - | ||
68 | - # connect to database and checks for registered students | ||
69 | - self.db_setup(config['database']) | ||
70 | - | ||
71 | - # dependency graph shared by all students | 63 | + config = load_yaml(config_file[0]) |
64 | + self.db_setup(config['database']) # setup and check students | ||
72 | self.deps = build_dependency_graph(config) | 65 | self.deps = build_dependency_graph(config) |
73 | - | ||
74 | - # add topics from dependency graph to the database, if missing | ||
75 | self.db_add_missing_topics(self.deps.nodes()) | 66 | self.db_add_missing_topics(self.deps.nodes()) |
76 | 67 | ||
77 | # ------------------------------------------------------------------------ | 68 | # ------------------------------------------------------------------------ |
@@ -98,8 +89,7 @@ class LearnApp(object): | @@ -98,8 +89,7 @@ class LearnApp(object): | ||
98 | with self.db_session() as s: | 89 | with self.db_session() as s: |
99 | tt = s.query(StudentTopic).filter_by(student_id=uid) | 90 | tt = s.query(StudentTopic).filter_by(student_id=uid) |
100 | 91 | ||
101 | - state = {t.topic_id: | ||
102 | - { | 92 | + state = {t.topic_id: { |
103 | 'level': t.level, | 93 | 'level': t.level, |
104 | 'date': datetime.strptime(t.date, "%Y-%m-%d %H:%M:%S.%f") | 94 | 'date': datetime.strptime(t.date, "%Y-%m-%d %H:%M:%S.%f") |
105 | } for t in tt} | 95 | } for t in tt} |
@@ -108,8 +98,7 @@ class LearnApp(object): | @@ -108,8 +98,7 @@ class LearnApp(object): | ||
108 | 'number': uid, | 98 | 'number': uid, |
109 | 'name': name, | 99 | 'name': name, |
110 | 'state': StudentKnowledge(self.deps, state=state), | 100 | 'state': StudentKnowledge(self.deps, state=state), |
111 | - # 'learning': None, # current topic learning | ||
112 | - } | 101 | + } |
113 | 102 | ||
114 | else: | 103 | else: |
115 | logger.info(f'User "{uid}" wrong password!') | 104 | logger.info(f'User "{uid}" wrong password!') |
@@ -209,23 +198,6 @@ class LearnApp(object): | @@ -209,23 +198,6 @@ class LearnApp(object): | ||
209 | logger.info(f'User "{uid}" started "{topic}"') | 198 | logger.info(f'User "{uid}" started "{topic}"') |
210 | 199 | ||
211 | # ------------------------------------------------------------------------ | 200 | # ------------------------------------------------------------------------ |
212 | - # Start new topic | ||
213 | - # ------------------------------------------------------------------------ | ||
214 | - # def start_learning(self, uid, topic): | ||
215 | - # try: | ||
216 | - # ok = self.online[uid]['state'].init_learning(topic) | ||
217 | - # except KeyError as e: | ||
218 | - # logger.warning( | ||
219 | - # f'User "{uid}" tried to open nonexistent topic: "{topic}"') | ||
220 | - # raise e | ||
221 | - # else: | ||
222 | - # if ok: | ||
223 | - # logger.info(f'User "{uid}" started "{topic}"') | ||
224 | - # else: | ||
225 | - # logger.warning(f'User "{uid}" denied locked "{topic}"') | ||
226 | - # return ok | ||
227 | - | ||
228 | - # ------------------------------------------------------------------------ | ||
229 | # Fill db table 'Topic' with topics from the graph if not already there. | 201 | # Fill db table 'Topic' with topics from the graph if not already there. |
230 | # ------------------------------------------------------------------------ | 202 | # ------------------------------------------------------------------------ |
231 | def db_add_missing_topics(self, nn): | 203 | def db_add_missing_topics(self, nn): |
@@ -330,7 +302,7 @@ def build_dependency_graph(config={}): | @@ -330,7 +302,7 @@ def build_dependency_graph(config={}): | ||
330 | prefix = config.get('path', '.') | 302 | prefix = config.get('path', '.') |
331 | title = config.get('title', '') | 303 | title = config.get('title', '') |
332 | database = config.get('database', 'students.db') | 304 | database = config.get('database', 'students.db') |
333 | - g = nx.DiGraph(path=prefix, title=title, database=database) | 305 | + g = nx.DiGraph(path=prefix, title=title, database=database, config=config) |
334 | 306 | ||
335 | # iterate over topics and build graph | 307 | # iterate over topics and build graph |
336 | topics = config.get('topics', {}) | 308 | topics = config.get('topics', {}) |
serve.py
@@ -356,7 +356,7 @@ def main(): | @@ -356,7 +356,7 @@ def main(): | ||
356 | # --- start application | 356 | # --- start application |
357 | logging.info('Starting App') | 357 | logging.info('Starting App') |
358 | try: | 358 | try: |
359 | - learnapp = LearnApp(arg.conffile[0]) | 359 | + learnapp = LearnApp(arg.conffile) |
360 | except Exception as e: | 360 | except Exception as e: |
361 | logging.critical('Failed to start backend application') | 361 | logging.critical('Failed to start backend application') |
362 | raise e | 362 | raise e |