diff --git a/Formula/moodle-to-vikwikiquiz.rb b/Formula/moodle-to-vikwikiquiz.rb index 826b556..e9d68fb 100644 --- a/Formula/moodle-to-vikwikiquiz.rb +++ b/Formula/moodle-to-vikwikiquiz.rb @@ -5,7 +5,7 @@ class MoodleToVikwikiquiz < Formula desc "A CLI for converting a graded Moodle quiz HTML to a vik.wiki quiz wikitext." homepage "https://github.com/gy-mate/homebrew-moodle-to-vikwikiquiz" - url "https://github.com/gy-mate/homebrew-moodle-to-vikwikiquiz/archive/1.0.14.tar.gz" + url "https://github.com/gy-mate/homebrew-moodle-to-vikwikiquiz/archive/1.0.15.tar.gz" license "GPl-3.0" sha256 "" head "https://github.com/gy-mate/homebrew-moodle-to-vikwikiquiz.git" diff --git a/setup.py b/setup.py index 7a85a36..39d0f70 100644 --- a/setup.py +++ b/setup.py @@ -1,16 +1,16 @@ -from setuptools import find_namespace_packages, setup # type: ignore +from setuptools import find_packages, setup # type: ignore setup( name="moodle-to-vikwikiquiz", description="A CLI for converting a graded Moodle quiz HTML to a vik.wiki quiz wikitext.", author="Máté Gyöngyösi", url="https://github.com/gy-mate/homebrew-moodle-to-vikwikiquiz", - version="1.0.14", - packages=find_namespace_packages("src"), + version="1.0.15", + packages=find_packages(where="src"), package_dir={"": "src"}, entry_points={ "console_scripts": [ - "moodle-to-vikwikiquiz=src.main:main", + "moodle-to-vikwikiquiz=moodle_to_vikwikiquiz.main:main", ], }, python_requires=">=3.9", diff --git a/src/moodle_to_vikwikiquiz/__init__.py b/src/moodle_to_vikwikiquiz/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/grading_types.py b/src/moodle_to_vikwikiquiz/grading_types.py similarity index 100% rename from src/grading_types.py rename to src/moodle_to_vikwikiquiz/grading_types.py diff --git a/src/main.py b/src/moodle_to_vikwikiquiz/main.py similarity index 84% rename from src/main.py rename to src/moodle_to_vikwikiquiz/main.py index 52886a3..53187a1 100644 --- a/src/main.py +++ b/src/moodle_to_vikwikiquiz/main.py @@ -3,23 +3,27 @@ import os.path import sys -from src.grading_types import GradingType -from src.quiz import Quiz +from src.moodle_to_vikwikiquiz.grading_types import GradingType +from src.moodle_to_vikwikiquiz.quiz import Quiz def main() -> None: parser = ArgumentParser() - parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity") - parser.add_argument("source_directory", help="the directory to import questions from") + parser.add_argument( + "-v", "--verbose", action="store_true", help="increase output verbosity" + ) + parser.add_argument( + "source_directory", help="the directory to import questions from" + ) parser.add_argument("parent_article", help="the parent article of the quiz") parser.add_argument("title", help="the title of the quiz") parser.add_argument("-g", "--grading", help="the grading type of the quiz") parser.add_argument("-o", "--output", help="the output file") args = parser.parse_args() - + configure_logging(args.verbose) logging.getLogger(__name__).info("Program started...") - + full_source_directory = os.path.basename(args.source_directory) if args.grading == "+": grading = GradingType.Kind @@ -29,14 +33,14 @@ def main() -> None: grading = None quiz = Quiz(parent_article=args.parent_article, title=args.title, grading=grading) quiz.import_files(full_source_directory) - + export_file = f"{full_source_directory}/quiz.txt" if requested_export_file := args.output: if os.path.exists(requested_export_file): export_file = os.path.basename(requested_export_file) with open(export_file, "w") as file: file.write(str(quiz)) - + logging.getLogger(__name__).info("...program finished!") diff --git a/src/question.py b/src/moodle_to_vikwikiquiz/question.py similarity index 54% rename from src/question.py rename to src/moodle_to_vikwikiquiz/question.py index 31a014b..ee31879 100644 --- a/src/question.py +++ b/src/moodle_to_vikwikiquiz/question.py @@ -1,16 +1,16 @@ -from src.grading_types import GradingType -from src.question_types import QuestionType +from src.moodle_to_vikwikiquiz.grading_types import GradingType +from src.moodle_to_vikwikiquiz.question_types import QuestionType class Question: def __init__( - self, - q_type: QuestionType, - text: str, - illustration: bool, - answers: list[str], - correct_answers: list[int], - grading: GradingType | None = None, + self, + q_type: QuestionType, + text: str, + illustration: bool, + answers: list[str], + correct_answers: list[int], + grading: GradingType | None = None, ): self.q_type = q_type self.text = text @@ -18,7 +18,7 @@ def __init__( self.grading = grading self.answers = answers self.correct_answers = correct_answers - + def __str__(self) -> str: text = f"== {self.text} ==" if self.illustration: @@ -30,6 +30,16 @@ def __str__(self) -> str: for answer in self.answers: text += f"\n# {answer}" return text - + def __hash__(self) -> int: - return hash(frozenset((self.q_type, self.text, self.answers.sort(), self.correct_answers.sort(), self.grading))) + return hash( + frozenset( + ( + self.q_type, + self.text, + self.answers.sort(), + self.correct_answers.sort(), + self.grading, + ) + ) + ) diff --git a/src/question_types.py b/src/moodle_to_vikwikiquiz/question_types.py similarity index 100% rename from src/question_types.py rename to src/moodle_to_vikwikiquiz/question_types.py diff --git a/src/quiz.py b/src/moodle_to_vikwikiquiz/quiz.py similarity index 53% rename from src/quiz.py rename to src/moodle_to_vikwikiquiz/quiz.py index dea7cf6..e6b6b03 100644 --- a/src/quiz.py +++ b/src/moodle_to_vikwikiquiz/quiz.py @@ -1,23 +1,23 @@ import os -from bs4 import BeautifulSoup, Tag +from bs4 import BeautifulSoup -from src.grading_types import GradingType -from src.question import Question -from src.question_types import QuestionType -from src.quiz_helpers import add_answers_to_existing_question, complete_correct_answers, get_answers, \ - get_grading_of_question, get_question_text, \ - question_already_exists +from src.moodle_to_vikwikiquiz.grading_types import GradingType +from src.moodle_to_vikwikiquiz.question import Question +from src.moodle_to_vikwikiquiz.question_types import QuestionType +from src.moodle_to_vikwikiquiz.quiz_helpers import * class Quiz: - def __init__(self, parent_article: str, title: str, grading: GradingType | None = None): + def __init__( + self, parent_article: str, title: str, grading: GradingType | None = None + ): self.parent_article = parent_article self.title = title self.grading = grading - + self.questions: set[Question] = set() - + def __str__(self) -> str: text = f"{{{{Vissza | {self.parent_article}}}}}" text += f""" @@ -31,39 +31,56 @@ def __str__(self) -> str: text += f"\n\n\n{question}" text += "\n" return text - + def import_files(self, directory: str) -> None: for subdir, dirs, files in os.walk(directory): for file in files: self.import_questions(file, subdir) - + def import_questions(self, file: str, subdir: str) -> None: file_path = os.path.join(subdir, file) with open(file_path, "rb") as source_file: webpage = BeautifulSoup(source_file, "html.parser") - + multichoice_questions = webpage.find_all("div", class_="multichoice") for question in multichoice_questions: self.import_question(question) - + def import_question(self, question: Tag) -> None: correctly_answered, grade, maximum_points = get_grading_of_question(question) question_text = get_question_text(question) answer_texts, correct_answers = get_answers(question) if not correctly_answered: - complete_correct_answers(answer_texts, correct_answers, grade, maximum_points, question_text) - has_illustration = True if question.find("img", class_="img-responsive") else False - self.add_question_no_duplicates(answer_texts, correct_answers, has_illustration, question_text) - - def add_question_no_duplicates(self, answer_texts: list[str], correct_answers: list[int], has_illustration: bool, - question_text: str) -> None: + complete_correct_answers( + answer_texts, correct_answers, grade, maximum_points, question_text + ) + has_illustration = ( + True if question.find("img", class_="img-responsive") else False + ) + self.add_question_no_duplicates( + answer_texts, correct_answers, has_illustration, question_text + ) + + def add_question_no_duplicates( + self, + answer_texts: list[str], + correct_answers: list[int], + has_illustration: bool, + question_text: str, + ) -> None: for existing_question in self.questions: if question_already_exists(existing_question, question_text): - add_answers_to_existing_question(answer_texts, correct_answers, existing_question) + add_answers_to_existing_question( + answer_texts, correct_answers, existing_question + ) break else: self.questions.add( - Question(q_type=QuestionType.MultipleChoice, text=question_text, - illustration=has_illustration, - answers=answer_texts, - correct_answers=correct_answers)) + Question( + q_type=QuestionType.MultipleChoice, + text=question_text, + illustration=has_illustration, + answers=answer_texts, + correct_answers=correct_answers, + ) + ) diff --git a/src/quiz_helpers.py b/src/moodle_to_vikwikiquiz/quiz_helpers.py similarity index 81% rename from src/quiz_helpers.py rename to src/moodle_to_vikwikiquiz/quiz_helpers.py index bcf76b1..216c068 100644 --- a/src/quiz_helpers.py +++ b/src/moodle_to_vikwikiquiz/quiz_helpers.py @@ -2,15 +2,15 @@ from bs4 import Tag -from src.question import Question +from src.moodle_to_vikwikiquiz.question import Question def get_grading_of_question(question: Tag) -> tuple[bool, float, float]: correctly_answered: bool - + found_tag = question.find("div", class_="grade") assert isinstance(found_tag, Tag) - + grading_text = found_tag.text numbers = re.findall(r"\d+\.\d+", grading_text) grade = float(numbers[0]) @@ -22,15 +22,22 @@ def get_grading_of_question(question: Tag) -> tuple[bool, float, float]: return correctly_answered, grade, maximum_points -def complete_correct_answers(answer_texts: list[str], correct_answers: list[int], grade: float, - maximum_points: float, question_text: str) -> None: - print(f""" +def complete_correct_answers( + answer_texts: list[str], + correct_answers: list[int], + grade: float, + maximum_points: float, + question_text: str, +) -> None: + print( + f""" Question: '{question_text}' I see that answers {correct_answers} are correct, but this list may be incomplete because you only got {grade:g} points out of {maximum_points:g}. -The answers are:""") +The answers are:""" + ) assert isinstance(answer_texts, list) # report false positive to mypy developers for j, answer in enumerate(answer_texts): # type: ignore @@ -38,8 +45,12 @@ def complete_correct_answers(answer_texts: list[str], correct_answers: list[int] print() while True: additional_correct_answer = input( - f"Please enter a missing correct answer (if there is any remaining) then press Enter: ") - if additional_correct_answer == "" or len(correct_answers) == len(answer_texts) - 1: + f"Please enter a missing correct answer (if there is any remaining) then press Enter: " + ) + if ( + additional_correct_answer == "" + or len(correct_answers) == len(answer_texts) - 1 + ): break correct_answers.append(int(additional_correct_answer)) @@ -75,8 +86,9 @@ def question_already_exists(existing_question: Question, question_text: str) -> return existing_question.text == question_text -def add_answers_to_existing_question(answer_texts: list[str], correct_answers: list[int], - existing_question: Question) -> None: +def add_answers_to_existing_question( + answer_texts: list[str], correct_answers: list[int], existing_question: Question +) -> None: # report false positive to mypy developers for k, answer in enumerate(answer_texts): # type: ignore if answer not in existing_question.answers: