def read_quiz_file(self, filename): """Read a .quiz file, return a list of dictionaries.""" return QuizMaker.read_quiz_file(self.path + filename)
def read_quiz_file(self, filename): """Read a .quiz file, return a list of dictionaries.""" return QuizMaker.read_quiz_file(self.path+filename)
def make_quiz(self, questions, quiz_format='modern', shuffle_answers=True, default_time=60000, **quizargs): """ Take a list of dictionaries, return kahoot quiz dictionary. Arguments: questions - Dictionary of questions, such as made by make_quiz shuffle_answers - shuffles the order the answers are shown default_time - The default time of each question quizformat - Choose 'classic' for normal Kahoot-formatting, 'modern' for code/math quizargs - Changes the quiz parameters, such as title, visibility, etc. """ logging.info("Turning questions into a Kahoot quiz object.") if quiz_format != 'modern' and quiz_format != 'classic': logging.warning( "Value of quiz_format not understood. Valid values are 'modern'/'classic', using modern." ) modern = True # Parse over all questions for q_nr, q in enumerate(questions): # Remove keys not relevant for Kahoot q.pop("no", None) q.pop("choice prefix", None) q.pop("question prefix", None) # Check number of answers if len(q["choices"]) > 4: logging.warning("Warning: Kahoot only supports up to 4 answers"\ ", %i of the answers of question %i have been truncated." \ % (len(q["choices"])-4, q_nr+1)) # Make sure we don't truncate all the correct answers # Choose at least 1 correct answer and fill up with wrong ones if shuffle_answers: random.shuffle(q["choices"]) q["choices"].sort(key=lambda c: c[0] == u'wrong') choices = q["choices"][:3] choices.append(q["choices"][-1]) random.shuffle(choices) else: choices = q["choices"] if shuffle_answers: random.shuffle(choices) # Check answers for images and mark-up answers_markup = False for c in choices: image = QuizMaker.find_images(c[1]) if image: logging.warning( "Question %i has an image in one" / "of the answers, this is not supported by Kahoot. The" / " image will be ignored." % (q_nr + 1)) c[1] = re.sub('<.*?>', '', q["question"]) math = QuizMaker.find_math(c[1]) code = QuizMaker.find_code(c[1]) if math or code: answers_markup = True if quiz_format == 'classic': q["choices"] = [] for c in choices: q["choices"].append({ "answer": c[1], "correct": c[0] == u"right" }) q["numberOfAnswers"] = len(choices) elif quiz_format == 'modern': # Use empty choices-fields as answers are moved into iframe letters = ['a)', 'b)', 'c)', 'd)'] q["choices"] = [] for j, c in enumerate(choices): q["choices"].append({ "answer": letters[j], "correct": c[0] == u'right' }) q["numberOfAnswers"] = len(choices) # Check question for images and mark-up images = QuizMaker.find_images(q["question"]) math = QuizMaker.find_math(q["question"]) code = QuizMaker.find_code(q["question"]) question_markup = math or code markup = question_markup or answers_markup if quiz_format == 'classic': logging.info("Generating a 'classic'-style quiz.") # Check for incompatibility if markup: logging.error( "The given quiz contains code and/or math markup" / " but uses the classic quiz_format, which does not support markup." ) raise AssertionError # Check for too many images if len(images) > 1: logging.warning( "Warning: Question %i contains several" / "images, but Kahoot only supports up to one image per " / "question. The additional images will be ignored." % (q_nr + 1)) images = [images[0]] q["question"] = re.sub('<.*?>', '', q["question"]) q["image"] = self.upload_image(images[0]) q["questionFormat"] = 0 # Image format elif quiz_format == 'modern': logging.info("Generating a 'modern'-style quiz.") # Check for incompatibility if images: logging.warning( "The quiz format chosen is 'modern', which" / "does not support images. All images in the quiz will be ignored." ) q["question"] = re.sub('<.*?>', '', q["question"]) images = [] iframe_str = self.iframe_str(q["question"], choices) q["iframe"] = {"content": iframe_str} q["question"] = "" q["questionFormat"] = 2 # iframe format q["image"] = "" # Additional question parameters q["time"] = default_time q["video"] = { "id": "", "startTime": 0, "endTime": 0, "service": "youtube" } q["points"] = True # Add additional parameters # Default parameters quiz = { "title": "Quiz", "questions": questions, "quizType": "quiz", "visibility": 0, # 0: private, 1: public "type": "quiz", "difficulty": 500, "audience": "University", "language": "English", "description": "Made using quiztools." } # User-given parameters for key in quizargs: if key == "cover": url = self.upload_image(quizargs["cover"]) quiz["cover"] = url else: quiz[key] = quizargs[key] logging.info("Quiz-object successfully made.") return quiz
def make_quiz(self, questions, quiz_format='modern', shuffle_answers=True, default_time=60000, **quizargs): """ Take a list of dictionaries, return kahoot quiz dictionary. Arguments: questions - Dictionary of questions, such as made by make_quiz shuffle_answers - shuffles the order the answers are shown default_time - The default time of each question quizformat - Choose 'classic' for normal Kahoot-formatting, 'modern' for code/math quizargs - Changes the quiz parameters, such as title, visibility, etc. """ logging.info("Turning questions into a Kahoot quiz object.") if quiz_format != 'modern' and quiz_format != 'classic': logging.warning("Value of quiz_format not understood. Valid values are 'modern'/'classic', using modern.") modern = True # Parse over all questions for q_nr, q in enumerate(questions): # Remove keys not relevant for Kahoot q.pop("no", None) q.pop("choice prefix", None) q.pop("question prefix", None) # Check number of answers if len(q["choices"]) > 4: logging.warning("Warning: Kahoot only supports up to 4 answers"\ ", %i of the answers of question %i have been truncated." \ % (len(q["choices"])-4, q_nr+1)) # Make sure we don't truncate all the correct answers # Choose at least 1 correct answer and fill up with wrong ones if shuffle_answers: random.shuffle(q["choices"]) q["choices"].sort(key=lambda c: c[0]==u'wrong') choices = q["choices"][:3] choices.append(q["choices"][-1]) random.shuffle(choices) else: choices = q["choices"] if shuffle_answers: random.shuffle(choices) # Check answers for images and mark-up answers_markup = False for c in choices: image = QuizMaker.find_images(c[1]) if image: logging.warning("Question %i has an image in one" / "of the answers, this is not supported by Kahoot. The"/ " image will be ignored." % (q_nr+1)) c[1] = re.sub('<.*?>', '', q["question"]) math = QuizMaker.find_math(c[1]) code = QuizMaker.find_code(c[1]) if math or code: answers_markup = True if quiz_format == 'classic': q["choices"] = [] for c in choices: q["choices"].append({"answer" : c[1], "correct" : c[0] == u"right"}) q["numberOfAnswers"] = len(choices) elif quiz_format == 'modern': # Use empty choices-fields as answers are moved into iframe letters = ['a)', 'b)', 'c)', 'd)'] q["choices"] = [] for j, c in enumerate(choices): q["choices"].append({"answer" : letters[j], "correct" : c[0] == u'right'}) q["numberOfAnswers"] = len(choices) # Check question for images and mark-up images = QuizMaker.find_images(q["question"]) math = QuizMaker.find_math(q["question"]) code = QuizMaker.find_code(q["question"]) question_markup = math or code markup = question_markup or answers_markup if quiz_format == 'classic': logging.info("Generating a 'classic'-style quiz.") # Check for incompatibility if markup: logging.error("The given quiz contains code and/or math markup"/ " but uses the classic quiz_format, which does not support markup.") raise AssertionError # Check for too many images if len(images) > 1: logging.warning("Warning: Question %i contains several"/ "images, but Kahoot only supports up to one image per "/ "question. The additional images will be ignored." % (q_nr+1)) images = [images[0]] q["question"] = re.sub('<.*?>', '', q["question"]) q["image"] = self.upload_image(images[0]) q["questionFormat"] = 0 # Image format elif quiz_format == 'modern': logging.info("Generating a 'modern'-style quiz.") # Check for incompatibility if images: logging.warning("The quiz format chosen is 'modern', which"/ "does not support images. All images in the quiz will be ignored.") q["question"] = re.sub('<.*?>', '', q["question"]) images = [] iframe_str = self.iframe_str(q["question"], choices) q["iframe"] = {"content" : iframe_str} q["question"] = "" q["questionFormat"] = 2 # iframe format q["image"] = "" # Additional question parameters q["time"] = default_time q["video"] = {"id" : "", "startTime" : 0, "endTime" : 0, "service" : "youtube"} q["points"] = True # Add additional parameters # Default parameters quiz = { "title" : "Quiz", "questions" : questions, "quizType": "quiz", "visibility": 0, # 0: private, 1: public "type": "quiz", "difficulty": 500, "audience": "University", "language": "English", "description": "Made using quiztools." } # User-given parameters for key in quizargs: if key == "cover": url = self.upload_image(quizargs["cover"]) quiz["cover"] = url else: quiz[key] = quizargs[key] logging.info("Quiz-object successfully made.") return quiz