Commit 2b30310aa1ed2ecbeadddb8d279177df120d5f0b
1 parent
1ecfefbf
Exists in
master
and in
1 other branch
- path prefix is now given on commandline instead of configuration file. The ide…
…a is to avoid incompatible prefixes on multiple yaml files. - some changes in async functions
Showing
6 changed files
with
30 additions
and
38 deletions
Show diff stats
demo/demo.yaml
| 1 | title: Example | 1 | title: Example |
| 2 | database: students.db | 2 | database: students.db |
| 3 | -path: ./demo | 3 | +# path: ./demo |
| 4 | 4 | ||
| 5 | # values applie to each topic, if undefined there | 5 | # values applie to each topic, if undefined there |
| 6 | # default values are: file=question.yaml, shuffle=True, choose: all | 6 | # default values are: file=question.yaml, shuffle=True, choose: all |
| @@ -17,7 +17,6 @@ forgetting_factor: 0.99 | @@ -17,7 +17,6 @@ forgetting_factor: 0.99 | ||
| 17 | # - B | 17 | # - B |
| 18 | # - C | 18 | # - C |
| 19 | topics: | 19 | topics: |
| 20 | - | ||
| 21 | # topic without dependencies | 20 | # topic without dependencies |
| 22 | math: | 21 | math: |
| 23 | name: Matemática | 22 | name: Matemática |
demo/solar_system/questions.yaml
| @@ -38,13 +38,13 @@ | @@ -38,13 +38,13 @@ | ||
| 38 | # correct: !regex '[Ss]aturno' | 38 | # correct: !regex '[Ss]aturno' |
| 39 | 39 | ||
| 40 | # --------------------------------------------------------------------------- | 40 | # --------------------------------------------------------------------------- |
| 41 | -- ref: first_3_planets | ||
| 42 | - type: textarea | ||
| 43 | - title: Sistema solar | ||
| 44 | - text: Escreva o nome dos três planetas mais próximos do Sol. (Exemplo `A, B e C`) | ||
| 45 | - correct: correct-first_3_planets.py | ||
| 46 | - # correct: correct-timeout.py | ||
| 47 | - # opcional | ||
| 48 | - answer: Vulcano, Krypton, Plutão | ||
| 49 | - lines: 3 | ||
| 50 | - timeout: 50 | 41 | +# - ref: first_3_planets |
| 42 | +# type: textarea | ||
| 43 | +# title: Sistema solar | ||
| 44 | +# text: Escreva o nome dos três planetas mais próximos do Sol. (Exemplo `A, B e C`) | ||
| 45 | +# correct: correct-first_3_planets.py | ||
| 46 | +# # correct: correct-timeout.py | ||
| 47 | +# # opcional | ||
| 48 | +# answer: Vulcano, Krypton, Plutão | ||
| 49 | +# lines: 3 | ||
| 50 | +# timeout: 50 |
knowledge.py
| @@ -70,7 +70,7 @@ class StudentKnowledge(object): | @@ -70,7 +70,7 @@ class StudentKnowledge(object): | ||
| 70 | # questions: list of generated questions to do in the topic | 70 | # questions: list of generated questions to do in the topic |
| 71 | # current_question: the current question to be presented | 71 | # current_question: the current question to be presented |
| 72 | # ------------------------------------------------------------------------ | 72 | # ------------------------------------------------------------------------ |
| 73 | - def init_topic(self, topic): | 73 | + async def init_topic(self, topic): |
| 74 | logger.debug(f'StudentKnowledge.init_topic({topic})') | 74 | logger.debug(f'StudentKnowledge.init_topic({topic})') |
| 75 | 75 | ||
| 76 | # do not allow locked topics | 76 | # do not allow locked topics |
| @@ -88,7 +88,7 @@ class StudentKnowledge(object): | @@ -88,7 +88,7 @@ class StudentKnowledge(object): | ||
| 88 | self.wrong_answers = 0 | 88 | self.wrong_answers = 0 |
| 89 | 89 | ||
| 90 | # select a random set of questions for this topic | 90 | # select a random set of questions for this topic |
| 91 | - size = min(self.MAX_QUESTIONS, len(questionlist)) # number of questions | 91 | + size = len(questionlist) # number of questions FIXME get from topic config |
| 92 | questionlist = random.sample(questionlist, k=size) | 92 | questionlist = random.sample(questionlist, k=size) |
| 93 | logger.debug(f'Questions: {", ".join(questionlist)}') | 93 | logger.debug(f'Questions: {", ".join(questionlist)}') |
| 94 | 94 |
learnapp.py
| @@ -22,8 +22,8 @@ from tools import load_yaml | @@ -22,8 +22,8 @@ from tools import load_yaml | ||
| 22 | logger = logging.getLogger(__name__) | 22 | logger = logging.getLogger(__name__) |
| 23 | 23 | ||
| 24 | # ============================================================================ | 24 | # ============================================================================ |
| 25 | -class LearnAppException(Exception): | ||
| 26 | - pass | 25 | +# class LearnAppException(Exception): |
| 26 | +# pass | ||
| 27 | 27 | ||
| 28 | 28 | ||
| 29 | # ============================================================================ | 29 | # ============================================================================ |
| @@ -61,11 +61,11 @@ class LearnApp(object): | @@ -61,11 +61,11 @@ class LearnApp(object): | ||
| 61 | session.close() | 61 | session.close() |
| 62 | 62 | ||
| 63 | # ------------------------------------------------------------------------ | 63 | # ------------------------------------------------------------------------ |
| 64 | - def __init__(self, config_files): | 64 | + def __init__(self, config_files, prefix): |
| 65 | self.db_setup() # setup database and check students | 65 | self.db_setup() # setup database and check students |
| 66 | self.online = dict() # online students | 66 | self.online = dict() # online students |
| 67 | 67 | ||
| 68 | - self.deps = nx.DiGraph() | 68 | + self.deps = nx.DiGraph(prefix=prefix) |
| 69 | for c in config_files: | 69 | for c in config_files: |
| 70 | self.populate_graph(c) | 70 | self.populate_graph(c) |
| 71 | 71 | ||
| @@ -192,9 +192,9 @@ class LearnApp(object): | @@ -192,9 +192,9 @@ class LearnApp(object): | ||
| 192 | # Start new topic | 192 | # Start new topic |
| 193 | # ------------------------------------------------------------------------ | 193 | # ------------------------------------------------------------------------ |
| 194 | async def start_topic(self, uid, topic): | 194 | async def start_topic(self, uid, topic): |
| 195 | - loop = asyncio.get_running_loop() | 195 | + student = self.online[uid]['state'] |
| 196 | try: | 196 | try: |
| 197 | - await loop.run_in_executor(None, self.online[uid]['state'].init_topic, topic) | 197 | + await student.init_topic(topic) |
| 198 | except KeyError as e: | 198 | except KeyError as e: |
| 199 | logger.warning(f'User "{uid}" tried to open nonexistent topic: "{topic}"') | 199 | logger.warning(f'User "{uid}" tried to open nonexistent topic: "{topic}"') |
| 200 | raise e | 200 | raise e |
| @@ -277,9 +277,9 @@ class LearnApp(object): | @@ -277,9 +277,9 @@ class LearnApp(object): | ||
| 277 | # ------------------------------------------------------------------------ | 277 | # ------------------------------------------------------------------------ |
| 278 | def get_current_public_dir(self, uid): | 278 | def get_current_public_dir(self, uid): |
| 279 | topic = self.online[uid]['state'].get_current_topic() | 279 | topic = self.online[uid]['state'].get_current_topic() |
| 280 | - p = self.deps.graph['path'] | ||
| 281 | - return path.join(p, topic, 'public') | 280 | + p = self.deps.graph['prefix'] # FIXME not defined!!! |
| 282 | 281 | ||
| 282 | + return path.join(p, topic, 'public') | ||
| 283 | 283 | ||
| 284 | 284 | ||
| 285 | # ============================================================================ | 285 | # ============================================================================ |
| @@ -304,21 +304,12 @@ class LearnApp(object): | @@ -304,21 +304,12 @@ class LearnApp(object): | ||
| 304 | g = self.deps # the graph | 304 | g = self.deps # the graph |
| 305 | config = load_yaml(conffile) # course configuration | 305 | config = load_yaml(conffile) # course configuration |
| 306 | 306 | ||
| 307 | - # set attributes of the graph | ||
| 308 | - prefix = path.expanduser(config.get('path', '.')) | ||
| 309 | - # title = config.get('title', '') | ||
| 310 | - # database = config.get('database', 'students.db') | ||
| 311 | - | ||
| 312 | # default attributes that apply to the topics | 307 | # default attributes that apply to the topics |
| 313 | default_file = config.get('file', 'questions.yaml') | 308 | default_file = config.get('file', 'questions.yaml') |
| 314 | default_shuffle = config.get('shuffle', True) | 309 | default_shuffle = config.get('shuffle', True) |
| 315 | default_choose = config.get('choose', 9999) | 310 | default_choose = config.get('choose', 9999) |
| 316 | default_forgetting_factor = config.get('forgetting_factor', 1.0) | 311 | default_forgetting_factor = config.get('forgetting_factor', 1.0) |
| 317 | 312 | ||
| 318 | - # create graph | ||
| 319 | - # g = nx.DiGraph(path=prefix, title=title, database=database, config=config) | ||
| 320 | - | ||
| 321 | - | ||
| 322 | # iterate over topics and populate graph | 313 | # iterate over topics and populate graph |
| 323 | topics = config.get('topics', {}) | 314 | topics = config.get('topics', {}) |
| 324 | tcount = qcount = 0 # topic and question counters | 315 | tcount = qcount = 0 # topic and question counters |
| @@ -331,12 +322,12 @@ class LearnApp(object): | @@ -331,12 +322,12 @@ class LearnApp(object): | ||
| 331 | g.add_node(tref) | 322 | g.add_node(tref) |
| 332 | t = g.node[tref] # current topic node | 323 | t = g.node[tref] # current topic node |
| 333 | 324 | ||
| 334 | - topicpath = path.join(prefix, tref) | 325 | + topicpath = path.join(g.graph['prefix'], tref) |
| 335 | 326 | ||
| 336 | t['type'] = attr.get('type', 'topic') | 327 | t['type'] = attr.get('type', 'topic') |
| 337 | t['name'] = attr.get('name', tref) | 328 | t['name'] = attr.get('name', tref) |
| 338 | - t['path'] = topicpath | ||
| 339 | - t['file'] = attr.get('file', default_file) | 329 | + t['path'] = topicpath # prefix/topic |
| 330 | + t['file'] = attr.get('file', default_file) # questions.yaml | ||
| 340 | t['shuffle'] = attr.get('shuffle', default_shuffle) | 331 | t['shuffle'] = attr.get('shuffle', default_shuffle) |
| 341 | t['forgetting_factor'] = attr.get('forgetting_factor', default_forgetting_factor) | 332 | t['forgetting_factor'] = attr.get('forgetting_factor', default_forgetting_factor) |
| 342 | g.add_edges_from((d,tref) for d in attr.get('deps', [])) | 333 | g.add_edges_from((d,tref) for d in attr.get('deps', [])) |
questions.py
| @@ -154,7 +154,7 @@ class QuestionCheckbox(Question): | @@ -154,7 +154,7 @@ class QuestionCheckbox(Question): | ||
| 154 | # set defaults if missing | 154 | # set defaults if missing |
| 155 | self.set_defaults({ | 155 | self.set_defaults({ |
| 156 | 'text': '', | 156 | 'text': '', |
| 157 | - 'correct': [0.0] * n, # useful for questionaries | 157 | + 'correct': [1.0] * n, # Using 0.0 breaks the (right, wrong) options |
| 158 | 'shuffle': True, | 158 | 'shuffle': True, |
| 159 | 'discount': True, | 159 | 'discount': True, |
| 160 | 'choose': n, # number of options | 160 | 'choose': n, # number of options |
serve.py
| @@ -304,9 +304,11 @@ def main(): | @@ -304,9 +304,11 @@ def main(): | ||
| 304 | # --- Commandline argument parsing | 304 | # --- Commandline argument parsing |
| 305 | argparser = argparse.ArgumentParser(description='Server for online learning. Enrolled students and topics have to be previously configured. Please read the documentation included with this software before running the server.') | 305 | argparser = argparse.ArgumentParser(description='Server for online learning. Enrolled students and topics have to be previously configured. Please read the documentation included with this software before running the server.') |
| 306 | argparser.add_argument('conffile', type=str, nargs='+', | 306 | argparser.add_argument('conffile', type=str, nargs='+', |
| 307 | - help='Topics configuration file in YAML format.') # FIXME only one | 307 | + help='Topics configuration file in YAML format.') |
| 308 | + argparser.add_argument('--prefix', type=str, default='demo', | ||
| 309 | + help='Path prefix under which the topic directories can be found, e.g. ~/topics') | ||
| 308 | argparser.add_argument('--port', type=int, default=8443, | 310 | argparser.add_argument('--port', type=int, default=8443, |
| 309 | - help='Port to be used by the HTTPS server') | 311 | + help='Port to be used by the HTTPS server, e.g. 8443') |
| 310 | argparser.add_argument('--debug', action='store_true', | 312 | argparser.add_argument('--debug', action='store_true', |
| 311 | help='Enable debug messages') | 313 | help='Enable debug messages') |
| 312 | arg = argparser.parse_args() | 314 | arg = argparser.parse_args() |
| @@ -327,7 +329,7 @@ def main(): | @@ -327,7 +329,7 @@ def main(): | ||
| 327 | # --- start application | 329 | # --- start application |
| 328 | logging.info('Starting App') | 330 | logging.info('Starting App') |
| 329 | try: | 331 | try: |
| 330 | - learnapp = LearnApp(arg.conffile) | 332 | + learnapp = LearnApp(arg.conffile, prefix=arg.prefix) |
| 331 | except Exception as e: | 333 | except Exception as e: |
| 332 | logging.critical('Failed to start backend application') | 334 | logging.critical('Failed to start backend application') |
| 333 | raise e | 335 | raise e |