Commit 667f624a3b3efd564c06865f48e02f3186efb60c

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

- question type text now has a transformed option that is applied to

the answers before the correction.
aprendizations/learnapp.py
@@ -370,7 +370,6 @@ class LearnApp(object): @@ -370,7 +370,6 @@ class LearnApp(object):
370 370
371 t['path'] = path.join(g.graph['prefix'], tref) # prefix/topic 371 t['path'] = path.join(g.graph['prefix'], tref) # prefix/topic
372 372
373 -  
374 # ======================================================================== 373 # ========================================================================
375 # methods that do not change state (pure functions) 374 # methods that do not change state (pure functions)
376 # ======================================================================== 375 # ========================================================================
@@ -379,6 +378,7 @@ class LearnApp(object): @@ -379,6 +378,7 @@ class LearnApp(object):
379 # Buils dictionary of question factories 378 # Buils dictionary of question factories
380 # ------------------------------------------------------------------------ 379 # ------------------------------------------------------------------------
381 def make_factory(self) -> Dict[str, QFactory]: 380 def make_factory(self) -> Dict[str, QFactory]:
  381 +
382 logger.info('Building questions factory:') 382 logger.info('Building questions factory:')
383 factory: Dict[str, QFactory] = {} 383 factory: Dict[str, QFactory] = {}
384 g = self.deps 384 g = self.deps
aprendizations/questions.py
@@ -234,7 +234,8 @@ class QuestionText(Question): @@ -234,7 +234,8 @@ class QuestionText(Question):
234 234
235 self.set_defaults(QDict({ 235 self.set_defaults(QDict({
236 'text': '', 236 'text': '',
237 - 'correct': [], 237 + 'correct': [], # no correct answers, always wrong
  238 + 'transform': [], # transformations applied to the answer, in order
238 })) 239 }))
239 240
240 # make sure its always a list of possible correct answers 241 # make sure its always a list of possible correct answers
@@ -244,12 +245,36 @@ class QuestionText(Question): @@ -244,12 +245,36 @@ class QuestionText(Question):
244 # make sure all elements of the list are strings 245 # make sure all elements of the list are strings
245 self['correct'] = [str(a) for a in self['correct']] 246 self['correct'] = [str(a) for a in self['correct']]
246 247
  248 + # make sure that the answers are invariant with respect to the filters
  249 + if any(c != self.transform(c) for c in self['correct']):
  250 + logger.warning(f'in "{self["ref"]}", correct answers are not '
  251 + 'invariant wrt transformations')
  252 +
  253 + # ------------------------------------------------------------------------
  254 + # apply optional filters to the answer
  255 + def transform(self, ans):
  256 + for f in self['transform']:
  257 + if f == 'remove_space':
  258 + ans = ans.replace(' ', '')
  259 + elif f == 'trim':
  260 + ans = ans.strip()
  261 + elif f == 'normalize_space':
  262 + ans = re.sub(r'\s+', ' ', ans.strip())
  263 + elif f == 'lower':
  264 + ans = ans.lower()
  265 + elif f == 'upper':
  266 + ans = ans.upper()
  267 + else:
  268 + logger.warning(f'in "{self["ref"]}", unknown transform "{f}"')
  269 + return ans
  270 +
247 # ------------------------------------------------------------------------ 271 # ------------------------------------------------------------------------
248 def correct(self) -> None: 272 def correct(self) -> None:
249 super().correct() 273 super().correct()
250 274
251 if self['answer'] is not None: 275 if self['answer'] is not None:
252 - self['grade'] = 1.0 if self['answer'] in self['correct'] else 0.0 276 + answer = self.transform(self['answer']) # apply transformations
  277 + self['grade'] = 1.0 if answer in self['correct'] else 0.0
253 278
254 279
255 # ============================================================================ 280 # ============================================================================
aprendizations/student.py
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 from datetime import datetime 3 from datetime import datetime
4 import logging 4 import logging
5 import random 5 import random
6 -from typing import Dict, List, Optional, Tuple 6 +from typing import List, Optional, Tuple
7 7
8 # third party libraries 8 # third party libraries
9 import networkx as nx 9 import networkx as nx
@@ -176,7 +176,7 @@ class StudentState(object): @@ -176,7 +176,7 @@ class StudentState(object):
176 dt = now - s['date'] 176 dt = now - s['date']
177 try: 177 try:
178 forgetting_factor = self.deps.nodes[tref]['forgetting_factor'] 178 forgetting_factor = self.deps.nodes[tref]['forgetting_factor']
179 - s['level'] *= forgetting_factor ** dt.days # forgetting factor 179 + s['level'] *= forgetting_factor ** dt.days # forgetting factor
180 except KeyError: 180 except KeyError:
181 logger.warning(f'Topic {tref} is not on the graph!') 181 logger.warning(f'Topic {tref} is not on the graph!')
182 182