From a0dc6c6411eb2dc04b98e18b74f2519c0053625e Mon Sep 17 00:00:00 2001 From: Ali Al Jufairi Date: Sat, 10 Feb 2024 00:28:23 +0300 Subject: [PATCH 1/2] Fixed some odd Casses in _Classes.py That I faced --- _classes.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/_classes.py b/_classes.py index 6930872..a767622 100644 --- a/_classes.py +++ b/_classes.py @@ -151,14 +151,17 @@ def __get_correct_answer(self, card_body) -> str: """ cabody = card_body.find("p", attrs={'class': "card-text question-answer bg-light white-text"}) # correct answers body - - comm_correct_answer = cabody.find("div", attrs={'class': "vote-bar progress-bar bg-primary"}) # the bar with community answer + if cabody is not None: + comm_correct_answer = cabody.find("div", attrs={'class': "vote-bar progress-bar bg-primary"}) + comm_correct_answer = cabody.find("div", attrs={'class': "vote-bar progress-bar bg-primary"}) # the bar with community answer # in the cases where the community agrees with ExamTopics, there is no community voting bar - if comm_correct_answer != None: - correct_answer = comm_correct_answer.text.split(" ")[0] # vote-bar progress-bar bg-primary + if comm_correct_answer != None: + correct_answer = comm_correct_answer.text.split(" ")[0] # vote-bar progress-bar bg-primary + else: + correct_answer = cabody.find("span",attrs={'class': "correct-answer"}).text else: - correct_answer = cabody.find("span",attrs={'class': "correct-answer"}).text + correct_answer = None return correct_answer @@ -167,3 +170,4 @@ def get_cards(self) -> list: Getter for the lsit of cards """ return self.cards_list + From fa1a064a86080c5a2ef397ef288f72486cb34545 Mon Sep 17 00:00:00 2001 From: Ali Al Jufairi Date: Sat, 10 Feb 2024 00:28:55 +0300 Subject: [PATCH 2/2] Added The ability for Quiz To export to JSON --- quiz.py | 146 ++++++++++++++++++++++++++------------------------------ 1 file changed, 67 insertions(+), 79 deletions(-) diff --git a/quiz.py b/quiz.py index c2c61e5..8d8d9df 100644 --- a/quiz.py +++ b/quiz.py @@ -1,67 +1,75 @@ from io import TextIOWrapper from _classes import CardList, os, re import random -from datetime import datetime +from datetime import datetime +import json import textwrap class Quiz: - def __init__(self, resources_dir = None) -> None: + def __init__(self, resources_dir=None) -> None: self.__cardlist = CardList(resources_dir) - self.__log_dirname = "wrong_answers" # the name of the directory where the .txt files with wrong answers will be stored + self.__log_dirname = "quiz_logs" # the name of the directory where the JSON files with quiz logs will be stored - self.__init_questions_per_quiz() - self.__init_show_answer_immediately() + self.__init_questions_per_quiz() + self.__init_show_answer_immediately() - self.__create_wrong_answers_directory() - - self.quiz_cards = self.__generate_quiz() + self.__create_logs_directory() + self.quiz_logs = self.__generate_quiz_logs() def __init_questions_per_quiz(self): """ - Initializez the varialbe that shows how many question should be shown in a quiz run + Initialize the variable that shows how many questions should be shown in a quiz run """ - try: - self.__questions_per_quiz = \ - int(input("How many questions do you want to have? (Max: " + str(len(self.__cardlist.cards_list)) + ") ")) + self.__questions_per_quiz = int(input("How many questions do you want to have? (Max: " + str( + len(self.__cardlist.cards_list)) + ") ")) - while type(self.__questions_per_quiz) != int or self.__questions_per_quiz > len(self.__cardlist.cards_list): - self.__questions_per_quiz = \ - int(input("Please pick a NUMBER. (Max: " + str(len(self.__cardlist.cards_list)) + ")")) + while type(self.__questions_per_quiz) != int or self.__questions_per_quiz > len( + self.__cardlist.cards_list): + self.__questions_per_quiz = int(input("Please pick a NUMBER. (Max: " + str( + len(self.__cardlist.cards_list)) + ")")) except: - print("Defaulted to max number of questions.") + print("Defaulted to the max number of questions.") self.__questions_per_quiz = len(self.__cardlist.cards_list) def __init_show_answer_immediately(self): """ - Initializes the variable that decides if you want the correct answer shown after you respond + Initializes the variable that decides if you want the correct answer shown after you respond """ - self.__show_answer_immediately = \ - input("Do you want to have the answer shown immediately after you respond?\n(If not, you will be shown a score at the end and a file will be generated with the wrong answers anyway.)[Y/n] ") + self.__show_answer_immediately = input( + "Do you want to have the answer shown immediately after you respond?\n" + "(If not, you will be shown a score at the end and a file will be generated with the wrong answers anyway.)[Y/n] ") if self.__show_answer_immediately == "": # if only Enter was pressed self.__show_answer_immediately = "y" # default to y self.__show_answer_immediately = self.__show_answer_immediately.lower() while self.__show_answer_immediately != "n" and self.__show_answer_immediately != "y": - self.__show_answer_immediately = \ - input("Please pick between 'y'(yes) or 'n'(no): ") + self.__show_answer_immediately = input("Please pick between 'y'(yes) or 'n'(no): ") self.__show_answer_immediately = self.__show_answer_immediately.lower() - - def __generate_quiz(self) -> list: + def __generate_quiz_logs(self) -> list: """ - Generate a random list of card objects that are limited by the size of how - many questions the player wants to have + Generate a list of dictionaries containing quiz data before the user answers the questions """ random.shuffle(self.__cardlist.cards_list) - return self.__cardlist.cards_list[:self.__questions_per_quiz] + quiz_logs = [] + for card in self.__cardlist.cards_list[:self.__questions_per_quiz]: + quiz_logs.append({ + 'question_number': card.question_number, + 'question': card.question, + 'answers': card.answers, + 'correct_answer': card.correct_answer, + 'user_response': None + }) + + return quiz_logs def __clear(self): """ - Clear the terminal window + Clear the terminal window """ print("") # get a new empty line # for windows @@ -69,84 +77,64 @@ def __clear(self): _ = os.system('cls') # for mac and linux(here, os.name is 'posix') else: - _ = os.system('clear') - + _ = os.system('clear') - def __create_wrong_answers_directory(self): + def __create_logs_directory(self): try: os.mkdir(self.__log_dirname) except: - print("Wrong answers directory already exists. Continuing..") - + print("Quiz logs directory already exists. Continuing..") + def __init_answers_file(self) -> TextIOWrapper: """ - Initialize the filename with the current datetime, while omitting spaces and colon + Initialize the filename with the current datetime, while omitting spaces and colon """ - filename = re.sub(" ", "_", str(datetime.now())).split(".")[0] # remove the miliseconds as they were delimited by '.' - filename = re.sub(":", "-", filename) # remove ':' as they are a special char on Windows.. - filename += ".txt" + filename = re.sub(" ", "_", str(datetime.now())).split(".")[0] # remove the milliseconds as they were delimited by '.' + filename = re.sub(":", "-", filename) # remove ':' as they are a special char on Windows.. + filename += ".json" filename = os.path.join(self.__log_dirname, filename) - wrong_answers_file = open(filename, "w") # file where the wrong answers will be written to - - return wrong_answers_file - - - def __write_to_file(self, wrong_answers_file, card, your_answer): - - wrapper = textwrap.TextWrapper() # wrap text so it looks better - - wrong_answers_file.write(card.question_number + " " + wrapper.fill(text= card.question) + "\n") - wrong_answers_file.write("-" * 40 + "\n") - for ans in card.answers: - try: - # ans = str(ans.encode('utf-8')) # some answers give a UnicodeEncodeError: 'charmap' codec can't encode character '\u05d2' in position 192: character maps to - wrong_answers_file.write(wrapper.fill(text= ans) + "\n") # one answer had a weird encoding - except: - wrong_answers_file.write(str(ans) + "\n") - - wrong_answers_file.write("Your answer: " + your_answer.upper() + "\n") - wrong_answers_file.write("Correct answer: " + card.correct_answer + "\n") - wrong_answers_file.write("-" * 40 + "\n\n") + quiz_log_file = open(filename, "w") # file where the quiz log will be written to + return quiz_log_file def start_quiz(self): - """ - The main logic function for the quiz to run + """ + The main logic function for the quiz to run """ self.__clear() - correct_answers = 0 # initialize correct answers - - wrong_answers_file = self.__init_answers_file() - wrapper = textwrap.TextWrapper() # wrap text so it looks better - - print("Your quiz starts now. Please enter one single character, coresponding to the answers (A,B,C or D). Answers are NOT case sensitive, so response 'b' is good if 'B' is the correct answer.\n") + print("Your quiz starts now. Please enter one single character, corresponding to the answers (A,B,C, or D). " + "Answers are NOT case sensitive, so response 'b' is good if 'B' is the correct answer.\n") input("Press Enter to continue..") - for index, card in enumerate(self.quiz_cards): + for index, quiz_log in enumerate(self.quiz_logs): print("") print(str(index + 1) + "/" + str(self.__questions_per_quiz)) - print(card.question_number + " " + wrapper.fill(text= card.question)) + print(quiz_log['question_number'] + " " + textwrap.fill(text=quiz_log['question'])) print("-" * 40) - for ans in card.answers: - print(wrapper.fill(text= ans)) + for ans in quiz_log['answers']: + print(textwrap.fill(text=ans)) print("-" * 40) + your_answer = "" while your_answer.upper() not in ['A', 'B', 'C', 'D']: your_answer = input("Your answer: ") - if your_answer.upper() == card.correct_answer: - correct_answers += 1 - else: - # write to the wrong answer to the file - self.__write_to_file(wrong_answers_file, card, your_answer) - + self.quiz_logs[index]['user_response'] = your_answer.upper() + if self.__show_answer_immediately == "y": - print("Correct answer: ", card.correct_answer) + print("Correct answer: ", quiz_log['correct_answer']) input("Press Enter to continue..") - wrong_answers_file.close() # writing is done so we close the file - + quiz_log_file = self.__init_answers_file() + json.dump(self.quiz_logs, quiz_log_file, indent=2) + quiz_log_file.close() + + correct_answers = sum(1 for quiz_log in self.quiz_logs if + quiz_log['user_response'] == quiz_log['correct_answer']) print("=^=" * 40) print("The quiz is DONE! Good job!") - print("Your score: " + str(correct_answers) + "/" + str(self.__questions_per_quiz)) \ No newline at end of file + print("Your score: " + str(correct_answers) + "/" + str(self.__questions_per_quiz)) + + +