Commit 7a51d4543fbf92340dbb0d5af1c9916fb054bf22
1 parent
027c621a
Exists in
master
and in
1 other branch
- fix check for nonexisting goals
- fix missing database
Showing
4 changed files
with
31 additions
and
34 deletions
Show diff stats
BUGS.md
1 | 1 | |
2 | 2 | # BUGS |
3 | 3 | |
4 | - | |
5 | -Traceback (most recent call last): | |
6 | - File "/home/mjsb/.local/lib/python3.7/site-packages/tornado/web.py", line 1697, in _execute | |
7 | - result = method(*self.path_args, **self.path_kwargs) | |
8 | - File "/home/mjsb/.local/lib/python3.7/site-packages/tornado/web.py", line 3174, in wrapper | |
9 | - return method(self, *args, **kwargs) | |
10 | - File "/usr/home/mjsb/Work/Projects/aprendizations/aprendizations/serve.py", line 213, in get | |
11 | - self.learn.start_course(uid, course) | |
12 | - File "/usr/home/mjsb/Work/Projects/aprendizations/aprendizations/learnapp.py", line 275, in start_course | |
13 | - student.start_course(course) | |
14 | - File "/usr/home/mjsb/Work/Projects/aprendizations/aprendizations/student.py", line 57, in start_course | |
15 | - self.topic_sequence = self.recommend_topic_sequence(topics) | |
16 | - File "/usr/home/mjsb/Work/Projects/aprendizations/aprendizations/student.py", line 216, in recommend_topic_sequence | |
17 | - ts.update(nx.ancestors(G, t)) | |
18 | - File "/home/mjsb/.local/lib/python3.7/site-packages/networkx/algorithms/dag.py", line 92, in ancestors | |
19 | - raise nx.NetworkXError("The node %s is not in the graph." % source) | |
20 | -networkx.exception.NetworkXError: The node programming/languages/pseudo-tcg/functions-produtorio is not in the graph. | |
21 | - | |
22 | -- detectar se em courses.yaml falta declarar ficheiro. Por exemplo se houver goals que não estao em lado nenhum. | |
4 | +- nao esta a seguir o max_tries definido no ficheiro de dependencias. | |
23 | 5 | - registar last_seen e remover os antigos de cada vez que houver um login. |
24 | 6 | - initdb da integrity error se no mesmo comando existirem alunos repetidos (p.ex em ficheiros csv diferentes ou entre csv e opcao -a) |
25 | -- permite definir goal, mas nao verifica se esta no grafo. rebenta no start_topic. | |
26 | 7 | - double click submits twice. |
27 | -- nao esta a seguir o max_tries definido no ficheiro de dependencias. | |
28 | -- impedir que quando students.db não é encontrado, crie um ficheiro vazio. | |
29 | 8 | - classificacoes so devia mostrar os que ja fizeram alguma coisa |
30 | 9 | - QFactory.generate() devia fazer run da gen_async, ou remover. |
31 | 10 | - marking all options right in a radio question breaks! |
... | ... | @@ -70,6 +49,8 @@ sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in |
70 | 49 | |
71 | 50 | # FIXED |
72 | 51 | |
52 | +- impedir que quando students.db não é encontrado, crie um ficheiro vazio. | |
53 | +- permite definir goal, mas nao verifica se esta no grafo. rebenta no start_topic. | |
73 | 54 | - se num topico, a ultima pergunta tem imagens, o servidor nao fornece as imagengs porque o current_topic passa a None antes de carregar no botao continuar. O caminho é prefix+None e dá erro. |
74 | 55 | - caixas com os cursos não se ajustam bem com ecran estreito. |
75 | 56 | - obter rankings por curso GET course=course_id | ... | ... |
aprendizations/learnapp.py
... | ... | @@ -69,28 +69,37 @@ class LearnApp(object): |
69 | 69 | |
70 | 70 | config: Dict[str, Any] = load_yaml(courses) |
71 | 71 | |
72 | - # --- courses dict | |
73 | - self.courses = config['courses'] | |
74 | - logger.info(f'Courses: {", ".join(self.courses.keys())}') | |
75 | - | |
76 | 72 | # --- topic dependencies are shared between all courses |
77 | 73 | self.deps = nx.DiGraph(prefix=prefix) |
78 | - logger.info('Populating graph:') | |
74 | + logger.info('Populating topic graph:') | |
79 | 75 | |
80 | 76 | t = config.get('topics', {}) # topics defined directly in courses file |
81 | 77 | self.populate_graph(t) |
82 | 78 | logger.info(f'{len(t):>6} topics in {courses}') |
83 | 79 | for f in config.get('topics_from', []): |
84 | 80 | c = load_yaml(f) # course configuration |
81 | + | |
82 | + # FIXME set defaults?? | |
85 | 83 | logger.info(f'{len(c["topics"]):>6} topics imported from {f}') |
86 | 84 | self.populate_graph(c) |
87 | 85 | logger.info(f'Graph has {len(self.deps)} topics') |
88 | 86 | |
87 | + # --- courses dict | |
88 | + self.courses = config['courses'] | |
89 | + logger.info(f'Courses: {", ".join(self.courses.keys())}') | |
90 | + for c, d in self.courses.items(): | |
91 | + for goal in d['goals']: | |
92 | + if goal not in self.deps.nodes(): | |
93 | + # logger.error(f'Goal "{goal}" of "{c}"" not in the graph') | |
94 | + raise LearnException(f'Goal "{goal}" from course "{c}" ' | |
95 | + ' does not exist') | |
96 | + | |
89 | 97 | # --- factory is a dict with question generators for all topics |
90 | 98 | self.factory: Dict[str, QFactory] = self.make_factory() |
91 | 99 | |
92 | 100 | # if graph has topics that are not in the database, add them |
93 | - self.db_add_missing_topics(self.deps.nodes()) | |
101 | + self.add_missing_topics(self.deps.nodes()) | |
102 | + | |
94 | 103 | |
95 | 104 | if check: |
96 | 105 | self.sanity_check_questions() |
... | ... | @@ -301,7 +310,7 @@ class LearnApp(object): |
301 | 310 | # ------------------------------------------------------------------------ |
302 | 311 | # Fill db table 'Topic' with topics from the graph if not already there. |
303 | 312 | # ------------------------------------------------------------------------ |
304 | - def db_add_missing_topics(self, topics: List[str]) -> None: | |
313 | + def add_missing_topics(self, topics: List[str]) -> None: | |
305 | 314 | with self.db_session() as s: |
306 | 315 | new_topics = [Topic(id=t) for t in topics |
307 | 316 | if (t,) not in s.query(Topic.id)] |
... | ... | @@ -317,6 +326,10 @@ class LearnApp(object): |
317 | 326 | def db_setup(self, db: str) -> None: |
318 | 327 | |
319 | 328 | logger.info(f'Checking database "{db}":') |
329 | + if not path.exists(db): | |
330 | + raise LearnException('Database does not exist. ' | |
331 | + 'Use "initdb-aprendizations" to create') | |
332 | + | |
320 | 333 | engine = sa.create_engine(f'sqlite:///{db}', echo=False) |
321 | 334 | self.Session = sa.orm.sessionmaker(bind=engine) |
322 | 335 | try: | ... | ... |
aprendizations/main.py
... | ... | @@ -9,7 +9,7 @@ import sys |
9 | 9 | from typing import Any, Dict |
10 | 10 | |
11 | 11 | # this project |
12 | -from .learnapp import LearnApp, DatabaseUnusableError | |
12 | +from .learnapp import LearnApp, DatabaseUnusableError, LearnException | |
13 | 13 | from .serve import run_webserver |
14 | 14 | from .tools import load_yaml |
15 | 15 | from . import APP_NAME, APP_VERSION |
... | ... | @@ -160,7 +160,7 @@ def main(): |
160 | 160 | else: |
161 | 161 | logging.info('SSL certificates loaded') |
162 | 162 | |
163 | - # --- start application | |
163 | + # --- start application -------------------------------------------------- | |
164 | 164 | try: |
165 | 165 | learnapp = LearnApp(courses=arg.courses, |
166 | 166 | prefix=arg.prefix, |
... | ... | @@ -178,13 +178,16 @@ def main(): |
178 | 178 | '--------------------------------------------------------------', |
179 | 179 | sep='\n') |
180 | 180 | sys.exit(1) |
181 | + except LearnException as e: | |
182 | + logging.critical(e) | |
183 | + sys.exit(1) | |
181 | 184 | except Exception: |
182 | 185 | logging.critical('Failed to start backend.') |
183 | 186 | sys.exit(1) |
184 | 187 | else: |
185 | 188 | logging.info('LearnApp started') |
186 | 189 | |
187 | - # --- run webserver forever | |
190 | + # --- run webserver forever ---------------------------------------------- | |
188 | 191 | run_webserver(app=learnapp, ssl=ssl_ctx, port=arg.port, debug=arg.debug) |
189 | 192 | |
190 | 193 | ... | ... |
demo/astronomy.yaml
... | ... | @@ -3,11 +3,11 @@ |
3 | 3 | # optional values applied to each topic, if undefined there |
4 | 4 | # ---------------------------------------------------------------------------- |
5 | 5 | |
6 | -# defaults: | |
6 | +# defaults: FIXME not working | |
7 | 7 | # file: questions.yaml |
8 | 8 | # shuffle_questions: true |
9 | 9 | # choose: 6 |
10 | -# max_tries: 2 | |
10 | +# max_tries: 200 | |
11 | 11 | # forgetting_factor: 0.97 |
12 | 12 | # min_level: 0.01 |
13 | 13 | # append_wrong: true | ... | ... |