Commit 94b0dd76345d616bd319a464778ad836923185ec
1 parent
f23c0e87
Exists in
master
and in
1 other branch
fixes error in checkbox questions when shuffle=false.
Showing
3 changed files
with
20 additions
and
15 deletions
Show diff stats
aprendizations/learnapp.py
| @@ -44,8 +44,8 @@ class LearnApp(object): | @@ -44,8 +44,8 @@ class LearnApp(object): | ||
| 44 | yield session | 44 | yield session |
| 45 | session.commit() | 45 | session.commit() |
| 46 | except Exception: | 46 | except Exception: |
| 47 | - session.rollback() | ||
| 48 | logger.error('DB rollback!!!') | 47 | logger.error('DB rollback!!!') |
| 48 | + session.rollback() | ||
| 49 | finally: | 49 | finally: |
| 50 | session.close() | 50 | session.close() |
| 51 | 51 |
aprendizations/questions.py
| @@ -50,8 +50,6 @@ class Question(dict): | @@ -50,8 +50,6 @@ class Question(dict): | ||
| 50 | 50 | ||
| 51 | async def correct_async(self) -> None: | 51 | async def correct_async(self) -> None: |
| 52 | self.correct() | 52 | self.correct() |
| 53 | - # loop = asyncio.get_running_loop() | ||
| 54 | - # await loop.run_in_executor(None, self.correct) | ||
| 55 | 53 | ||
| 56 | def set_defaults(self, d: QDict) -> None: | 54 | def set_defaults(self, d: QDict) -> None: |
| 57 | 'Add k:v pairs from default dict d for nonexistent keys' | 55 | 'Add k:v pairs from default dict d for nonexistent keys' |
| @@ -94,7 +92,9 @@ class QuestionRadio(Question): | @@ -94,7 +92,9 @@ class QuestionRadio(Question): | ||
| 94 | for x in range(n)] | 92 | for x in range(n)] |
| 95 | 93 | ||
| 96 | if len(self['correct']) != n: | 94 | if len(self['correct']) != n: |
| 97 | - msg = f'Options and correct mismatch in "{self["ref"]}"' | 95 | + msg = (f'Options and correct mismatch in ' |
| 96 | + f'"{self["ref"]}", file "{self["filename"]}".') | ||
| 97 | + logger.error(msg) | ||
| 98 | raise QuestionException(msg) | 98 | raise QuestionException(msg) |
| 99 | 99 | ||
| 100 | if self['shuffle']: | 100 | if self['shuffle']: |
| @@ -168,18 +168,20 @@ class QuestionCheckbox(Question): | @@ -168,18 +168,20 @@ class QuestionCheckbox(Question): | ||
| 168 | })) | 168 | })) |
| 169 | 169 | ||
| 170 | if len(self['correct']) != n: | 170 | if len(self['correct']) != n: |
| 171 | - msg = f'Options and correct mismatch in "{self["ref"]}"' | 171 | + msg = (f'Options and correct size mismatch in ' |
| 172 | + f'"{self["ref"]}", file "{self["filename"]}".') | ||
| 173 | + logger.error(msg) | ||
| 172 | raise QuestionException(msg) | 174 | raise QuestionException(msg) |
| 173 | 175 | ||
| 174 | # if an option is a list of (right, wrong), pick one | 176 | # if an option is a list of (right, wrong), pick one |
| 175 | - # FIXME it's possible that all options are chosen wrong | ||
| 176 | options = [] | 177 | options = [] |
| 177 | correct = [] | 178 | correct = [] |
| 178 | for o, c in zip(self['options'], self['correct']): | 179 | for o, c in zip(self['options'], self['correct']): |
| 179 | if isinstance(o, list): | 180 | if isinstance(o, list): |
| 180 | r = random.randint(0, 1) | 181 | r = random.randint(0, 1) |
| 181 | o = o[r] | 182 | o = o[r] |
| 182 | - c = c if r == 0 else -c | 183 | + if r == 1: |
| 184 | + c = -c | ||
| 183 | options.append(str(o)) | 185 | options.append(str(o)) |
| 184 | correct.append(float(c)) | 186 | correct.append(float(c)) |
| 185 | 187 | ||
| @@ -187,8 +189,11 @@ class QuestionCheckbox(Question): | @@ -187,8 +189,11 @@ class QuestionCheckbox(Question): | ||
| 187 | # and apply to `options` and `correct` | 189 | # and apply to `options` and `correct` |
| 188 | if self['shuffle']: | 190 | if self['shuffle']: |
| 189 | perm = random.sample(range(n), k=self['choose']) | 191 | perm = random.sample(range(n), k=self['choose']) |
| 190 | - self['options'] = [str(options[i]) for i in perm] | ||
| 191 | - self['correct'] = [float(correct[i]) for i in perm] | 192 | + self['options'] = [options[i] for i in perm] |
| 193 | + self['correct'] = [correct[i] for i in perm] | ||
| 194 | + else: | ||
| 195 | + self['options'] = options[:self['choose']] | ||
| 196 | + self['correct'] = correct[:self['choose']] | ||
| 192 | 197 | ||
| 193 | # ------------------------------------------------------------------------ | 198 | # ------------------------------------------------------------------------ |
| 194 | # can return negative values for wrong answers | 199 | # can return negative values for wrong answers |
| @@ -443,20 +448,20 @@ class QFactory(object): | @@ -443,20 +448,20 @@ class QFactory(object): | ||
| 443 | 'textarea': QuestionTextArea, | 448 | 'textarea': QuestionTextArea, |
| 444 | # -- informative panels -- | 449 | # -- informative panels -- |
| 445 | 'information': QuestionInformation, | 450 | 'information': QuestionInformation, |
| 451 | + 'success': QuestionInformation, | ||
| 446 | 'warning': QuestionInformation, | 452 | 'warning': QuestionInformation, |
| 447 | 'alert': QuestionInformation, | 453 | 'alert': QuestionInformation, |
| 448 | - 'success': QuestionInformation, | ||
| 449 | } | 454 | } |
| 450 | 455 | ||
| 451 | - def __init__(self, question_dict: QDict = QDict({})) -> None: | ||
| 452 | - self.question = question_dict | 456 | + def __init__(self, qdict: QDict = QDict({})) -> None: |
| 457 | + self.question = qdict | ||
| 453 | 458 | ||
| 454 | # ----------------------------------------------------------------------- | 459 | # ----------------------------------------------------------------------- |
| 455 | # Given a ref returns an instance of a descendent of Question(), | 460 | # Given a ref returns an instance of a descendent of Question(), |
| 456 | # i.e. a question object (radio, checkbox, ...). | 461 | # i.e. a question object (radio, checkbox, ...). |
| 457 | # ----------------------------------------------------------------------- | 462 | # ----------------------------------------------------------------------- |
| 458 | def generate(self) -> Question: | 463 | def generate(self) -> Question: |
| 459 | - logger.debug(f'[generate] "{self.question["ref"]}"...') | 464 | + logger.debug(f'[QFactory.generate] "{self.question["ref"]}"...') |
| 460 | # Shallow copy so that script generated questions will not replace | 465 | # Shallow copy so that script generated questions will not replace |
| 461 | # the original generators | 466 | # the original generators |
| 462 | q = self.question.copy() | 467 | q = self.question.copy() |
| @@ -487,7 +492,7 @@ class QFactory(object): | @@ -487,7 +492,7 @@ class QFactory(object): | ||
| 487 | 492 | ||
| 488 | # ----------------------------------------------------------------------- | 493 | # ----------------------------------------------------------------------- |
| 489 | async def generate_async(self) -> Question: | 494 | async def generate_async(self) -> Question: |
| 490 | - logger.debug(f'[generate_async] "{self.question["ref"]}"...') | 495 | + logger.debug(f'[QFactory.generate_async] "{self.question["ref"]}"...') |
| 491 | # Shallow copy so that script generated questions will not replace | 496 | # Shallow copy so that script generated questions will not replace |
| 492 | # the original generators | 497 | # the original generators |
| 493 | q = self.question.copy() | 498 | q = self.question.copy() |
aprendizations/tools.py
| @@ -145,7 +145,7 @@ def load_yaml(filename: str, default: Any = None) -> Any: | @@ -145,7 +145,7 @@ def load_yaml(filename: str, default: Any = None) -> Any: | ||
| 145 | logger.error(f'Cannot open "{filename}": not found') | 145 | logger.error(f'Cannot open "{filename}": not found') |
| 146 | except PermissionError: | 146 | except PermissionError: |
| 147 | logger.error(f'Cannot open "{filename}": no permission') | 147 | logger.error(f'Cannot open "{filename}": no permission') |
| 148 | - except IOError: | 148 | + except OSError: |
| 149 | logger.error(f'Cannot open file "{filename}"') | 149 | logger.error(f'Cannot open file "{filename}"') |
| 150 | else: | 150 | else: |
| 151 | with f: | 151 | with f: |