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 | 5 | "file: questions.yaml" (default questions.yaml) |
| 6 | 6 | "shuffle: True/False" (default False) |
| 7 | 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 | 8 | - quando a pergunta devolve comments, este é apresentado, mas fica persistente nas tentativas seguintes. devia ser limpo apos a segunda submissao. |
| 13 | 9 | - a opcao max_tries na especificacao das perguntas é cumbersome... usar antes tries? |
| 14 | 10 | - tabelas nas perguntas radio/checkbox não ocupam todo o espaço como em question. | ... | ... |
demo/demo.yaml
| 1 | 1 | title: Example |
| 2 | 2 | database: students.db |
| 3 | 3 | |
| 4 | +# default global values | |
| 5 | +file: questions.yaml | |
| 6 | +shuffle: True | |
| 7 | +choose: 6 | |
| 8 | + | |
| 4 | 9 | # path prefix applied to the topics |
| 5 | 10 | path: ./demo |
| 6 | 11 | |
| ... | ... | @@ -16,6 +21,9 @@ topics: |
| 16 | 21 | # topic without dependencies |
| 17 | 22 | math: |
| 18 | 23 | name: Matemática |
| 24 | + file: questions.yaml | |
| 25 | + choose: 6 | |
| 26 | + shuffle: True | |
| 19 | 27 | |
| 20 | 28 | # topic with one dependency |
| 21 | 29 | solar_system: | ... | ... |
knowledge.py
| ... | ... | @@ -32,8 +32,8 @@ class StudentKnowledge(object): |
| 32 | 32 | self.topic_sequence = self.recommend_topic_sequence() # ['a', 'b', ...] |
| 33 | 33 | self.unlock_topics() # whose dependencies have been done |
| 34 | 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 | 39 | # Updates the proficiency levels of the topics, with forgetting factor | ... | ... |
learnapp.py
| ... | ... | @@ -29,11 +29,9 @@ class LearnAppException(Exception): |
| 29 | 29 | # ============================================================================ |
| 30 | 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 | 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 | 36 | def bcrypt_hash_gen(pw): |
| 39 | 37 | return bcrypt.hashpw(pw.encode('utf-8'), bcrypt.gensalt()) |
| ... | ... | @@ -62,16 +60,9 @@ class LearnApp(object): |
| 62 | 60 | def __init__(self, config_file): |
| 63 | 61 | # state of online students |
| 64 | 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 | 65 | self.deps = build_dependency_graph(config) |
| 73 | - | |
| 74 | - # add topics from dependency graph to the database, if missing | |
| 75 | 66 | self.db_add_missing_topics(self.deps.nodes()) |
| 76 | 67 | |
| 77 | 68 | # ------------------------------------------------------------------------ |
| ... | ... | @@ -98,8 +89,7 @@ class LearnApp(object): |
| 98 | 89 | with self.db_session() as s: |
| 99 | 90 | tt = s.query(StudentTopic).filter_by(student_id=uid) |
| 100 | 91 | |
| 101 | - state = {t.topic_id: | |
| 102 | - { | |
| 92 | + state = {t.topic_id: { | |
| 103 | 93 | 'level': t.level, |
| 104 | 94 | 'date': datetime.strptime(t.date, "%Y-%m-%d %H:%M:%S.%f") |
| 105 | 95 | } for t in tt} |
| ... | ... | @@ -108,8 +98,7 @@ class LearnApp(object): |
| 108 | 98 | 'number': uid, |
| 109 | 99 | 'name': name, |
| 110 | 100 | 'state': StudentKnowledge(self.deps, state=state), |
| 111 | - # 'learning': None, # current topic learning | |
| 112 | - } | |
| 101 | + } | |
| 113 | 102 | |
| 114 | 103 | else: |
| 115 | 104 | logger.info(f'User "{uid}" wrong password!') |
| ... | ... | @@ -209,23 +198,6 @@ class LearnApp(object): |
| 209 | 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 | 201 | # Fill db table 'Topic' with topics from the graph if not already there. |
| 230 | 202 | # ------------------------------------------------------------------------ |
| 231 | 203 | def db_add_missing_topics(self, nn): |
| ... | ... | @@ -330,7 +302,7 @@ def build_dependency_graph(config={}): |
| 330 | 302 | prefix = config.get('path', '.') |
| 331 | 303 | title = config.get('title', '') |
| 332 | 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 | 307 | # iterate over topics and build graph |
| 336 | 308 | topics = config.get('topics', {}) | ... | ... |
serve.py
| ... | ... | @@ -356,7 +356,7 @@ def main(): |
| 356 | 356 | # --- start application |
| 357 | 357 | logging.info('Starting App') |
| 358 | 358 | try: |
| 359 | - learnapp = LearnApp(arg.conffile[0]) | |
| 359 | + learnapp = LearnApp(arg.conffile) | |
| 360 | 360 | except Exception as e: |
| 361 | 361 | logging.critical('Failed to start backend application') |
| 362 | 362 | raise e | ... | ... |