Source code for questioned.questions.manual_multiple_choice_question

"""
This module defines the manual open question.
"""

import random

from questioned.utils import select_questions

from .question import Question


[docs]class ManualMultipleChoiceQuestion(Question): """ Defines a question that is input manually using the exam_spec file. This question type requires the student to select an answer from a given group of answers. Only one of these answers is correct. The question text is passed through the ``question`` parameter. The possible answers is provided as a list through the ``answers`` parameter. This list contains the answers, as well as whether or not they are correct. This list can arbitrarily long, but be aware that blackboard does not support more than 255 total answers, including the correct answer. Though, creating a list of options this long may have other practical implication. By default, the list is shuffled by the software, but the list can be ordered manually by setting the ``randomize_order`` parameter to ``False``. In that case, answers are stated in the order they are provided. Supports the inclusion of images above the question text, similar to :py:class:`ManualOpenQuestion <questioned.questions.manual_open_question.ManualOpenQuestion>`. The order of choices is randomized. Exam Spec example: :: manual_multiple_choice_questions: - question: "What is the Answer to the Ultimate Question of Life, the Universe, and Everything?" randomize_order: False answers: - "-1": False - "12": False - "24": False - "42": True """ # This is an accepted shortcoming of the design. # pylint: disable=super-init-not-called def __init__(self, exam_spec: dict, question: str, raw_answers: list, *, question_data: dict = {}, **kwargs): """ Constructor for this question object. Overrides the standard constructor to support the multiple answers scheme. """ self._exam_spec = exam_spec self.question = question self.question_data = question_data if 'randomize_order' not in self.question_data.keys(): self.randomize_order = True else: self.randomize_order = self.question_data['randomize_order'] for kwarg, value in kwargs.items(): setattr(self, kwarg, value) self._answers = self.process_answers(raw_answers) if len(self.correct_answers) > 1: raise ValueError(f"Multiple correct answers provided for multiple choice question:\n\t{raw_answers}")
[docs] def process_answers(self, raw_answers): """ Formats the raw answer input into something more usable. """ out = [] for raw_answer in raw_answers: item = list(raw_answer.items())[0] # Get first and only item. out.append(item) if self.randomize_order: random.shuffle(out) return out
@property def answer(self) -> str: """ Gives the string representation of the correct answer. """ for possible_answer, correct in self._answers: if correct: return possible_answer return None @property def correct_answers(self) -> list: """ Returns a list of all answers deemed correct by the question. """ out = [] for possible_answer, correct in self._answers: if correct: out.append(possible_answer) return out @property def incorrect_answers(self) -> list: """ Returns a list of all answers deemed incorrect by the question. """ out = [] for possible_answer, correct in self._answers: if not correct: out.append(possible_answer) return out
[docs] def render_markdown(self) -> str: """ Renders the markdown output for this question. """ out = "" if self.image is not None: out += self.image out += f"{self.question}\n" possible_answers = self._answers for possible_answer, _ in possible_answers: out += f" - {possible_answer}\n" return out
[docs] def render_blackboard(self) -> str: """ Renders the blackboard question. """ out_question = self.question.replace('\n', '<br />') if self.image is not None: out_question = self.image + out_question out = f"MC\t{out_question}\t" for answer, correct in self._answers: correct_text = 'incorrect' if correct: correct_text = 'correct' out += f'{answer}\t{correct_text}\t' out = out[:-1] # We drop the last tab here out += '\n' return out
[docs] @classmethod def generate(cls, exam_spec, count: int = 5, section_data=None) -> list: """ Generates an amount of manually input questions. """ # Pylint gets this wrong: # pylint: disable=unsubscriptable-object if section_data is None: section_data = {} out = [] selection = select_questions(cls, exam_spec, 'manual_multiple_choice_questions', count, section_data) for selected_question in selection: question_text = selected_question['question'] out.append( cls( exam_spec, question_text, selected_question['answers'], question_data=selected_question ) ) return out