Commit 2b30310aa1ed2ecbeadddb8d279177df120d5f0b

Authored by Miguel Barão
1 parent 1ecfefbf
Exists in master and in 1 other branch dev

- 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
demo/demo.yaml
1 1 title: Example
2 2 database: students.db
3   -path: ./demo
  3 +# path: ./demo
4 4  
5 5 # values applie to each topic, if undefined there
6 6 # default values are: file=question.yaml, shuffle=True, choose: all
... ... @@ -17,7 +17,6 @@ forgetting_factor: 0.99
17 17 # - B
18 18 # - C
19 19 topics:
20   -
21 20 # topic without dependencies
22 21 math:
23 22 name: Matemática
... ...
demo/solar_system/questions.yaml
... ... @@ -38,13 +38,13 @@
38 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 70 # questions: list of generated questions to do in the topic
71 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 74 logger.debug(f'StudentKnowledge.init_topic({topic})')
75 75  
76 76 # do not allow locked topics
... ... @@ -88,7 +88,7 @@ class StudentKnowledge(object):
88 88 self.wrong_answers = 0
89 89  
90 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 92 questionlist = random.sample(questionlist, k=size)
93 93 logger.debug(f'Questions: {", ".join(questionlist)}')
94 94  
... ...
learnapp.py
... ... @@ -22,8 +22,8 @@ from tools import load_yaml
22 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 61 session.close()
62 62  
63 63 # ------------------------------------------------------------------------
64   - def __init__(self, config_files):
  64 + def __init__(self, config_files, prefix):
65 65 self.db_setup() # setup database and check students
66 66 self.online = dict() # online students
67 67  
68   - self.deps = nx.DiGraph()
  68 + self.deps = nx.DiGraph(prefix=prefix)
69 69 for c in config_files:
70 70 self.populate_graph(c)
71 71  
... ... @@ -192,9 +192,9 @@ class LearnApp(object):
192 192 # Start new topic
193 193 # ------------------------------------------------------------------------
194 194 async def start_topic(self, uid, topic):
195   - loop = asyncio.get_running_loop()
  195 + student = self.online[uid]['state']
196 196 try:
197   - await loop.run_in_executor(None, self.online[uid]['state'].init_topic, topic)
  197 + await student.init_topic(topic)
198 198 except KeyError as e:
199 199 logger.warning(f'User "{uid}" tried to open nonexistent topic: "{topic}"')
200 200 raise e
... ... @@ -277,9 +277,9 @@ class LearnApp(object):
277 277 # ------------------------------------------------------------------------
278 278 def get_current_public_dir(self, uid):
279 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 304 g = self.deps # the graph
305 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 307 # default attributes that apply to the topics
313 308 default_file = config.get('file', 'questions.yaml')
314 309 default_shuffle = config.get('shuffle', True)
315 310 default_choose = config.get('choose', 9999)
316 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 313 # iterate over topics and populate graph
323 314 topics = config.get('topics', {})
324 315 tcount = qcount = 0 # topic and question counters
... ... @@ -331,12 +322,12 @@ class LearnApp(object):
331 322 g.add_node(tref)
332 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 327 t['type'] = attr.get('type', 'topic')
337 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 331 t['shuffle'] = attr.get('shuffle', default_shuffle)
341 332 t['forgetting_factor'] = attr.get('forgetting_factor', default_forgetting_factor)
342 333 g.add_edges_from((d,tref) for d in attr.get('deps', []))
... ...
questions.py
... ... @@ -154,7 +154,7 @@ class QuestionCheckbox(Question):
154 154 # set defaults if missing
155 155 self.set_defaults({
156 156 'text': '',
157   - 'correct': [0.0] * n, # useful for questionaries
  157 + 'correct': [1.0] * n, # Using 0.0 breaks the (right, wrong) options
158 158 'shuffle': True,
159 159 'discount': True,
160 160 'choose': n, # number of options
... ...
serve.py
... ... @@ -304,9 +304,11 @@ def main():
304 304 # --- Commandline argument parsing
305 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 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 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 312 argparser.add_argument('--debug', action='store_true',
311 313 help='Enable debug messages')
312 314 arg = argparser.parse_args()
... ... @@ -327,7 +329,7 @@ def main():
327 329 # --- start application
328 330 logging.info('Starting App')
329 331 try:
330   - learnapp = LearnApp(arg.conffile)
  332 + learnapp = LearnApp(arg.conffile, prefix=arg.prefix)
331 333 except Exception as e:
332 334 logging.critical('Failed to start backend application')
333 335 raise e
... ...