Passed
Push — main ( a49b9a...ae3f1b )
by Máté
01:25 queued 13s
created

quiz.Quiz.import_questions()   F

Complexity

Conditions 21

Size

Total Lines 62
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 51
dl 0
loc 62
rs 0
c 0
b 0
f 0
cc 21
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like quiz.Quiz.import_questions() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import contextlib
2
import os
3
import re
4
5
from bs4 import BeautifulSoup
6
7
from grading_types import GradingType
8
from question import Question
9
from question_types import QuestionType
10
11
12
class Quiz:
13
    def __init__(self, parent_article: str, title: str, grading: GradingType | None = None):
14
        self.parent_article = parent_article
15
        self.title = title
16
        self.grading = grading
17
        
18
        self.questions: set[Question] = set()
19
    
20
    def __str__(self) -> str:
21
        text = f"{{{{Vissza | {self.parent_article}}}}}"
22
        text += f"""
23
24
{{{{Kvízoldal
25
|cím={self.title}"""
26
        if self.grading:
27
            text += f"\n|pontozás={self.grading.value}"
28
        text += "\n}}"
29
        for question in self.questions:
30
            text += f"\n\n\n{question}"
31
        text += "\n"
32
        return text
33
    
34
    def import_questions(self, directory: str) -> None:
35
        for subdir, dirs, files in os.walk(directory):
36
            for file in files:
37
                file_path = os.path.join(subdir, file)
38
                with open(file_path, "rb") as source_file:
39
                    webpage = BeautifulSoup(source_file, "html.parser")
40
                    
41
                    multichoice_questions = webpage.find_all("div", class_="multichoice")
42
                    for question in multichoice_questions:
43
                        correctly_answered: bool
44
                        grading_text = question.find("div", class_="grade").text
45
                        numbers = re.findall(r"\d+\.\d+", grading_text)
46
                        grade = float(numbers[0])
47
                        maximum_points = float(numbers[1])
48
                        if grade == maximum_points:
49
                            correctly_answered = True
50
                        else:
51
                            correctly_answered = False
52
                        
53
                        question_text = question.find("div", class_="qtext").text
54
                        answers = question.find("div", class_="answer")
55
                        answer_texts: list[str] = []
56
                        correct_answers: list[int] = []
57
                        i = 1
58
                        for answer in answers:
59
                            with contextlib.suppress(TypeError):
60
                                answer_texts.append(answer.find("div", class_="ml-1").text.rstrip("."))
61
                                if "correct" in answer["class"]:
62
                                    correct_answers.append(i)
63
                                i += 1
64
                        if not correctly_answered:
65
                            print(f"""
66
67
Question: '{question_text}'
68
69
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}.
70
71
The answers are:""")
72
                            for j, answer in enumerate(answer_texts):
73
                                print(f"#{j + 1}\t{answer}")
74
                            print()
75
                            while True:
76
                                additional_correct_answer = input(
77
                                    f"Please enter a missing correct answer (if there is any remaining) then press Enter: ")
78
                                if additional_correct_answer == "" or len(correct_answers) == len(answer_texts) - 1:
79
                                    break
80
                                correct_answers.append(int(additional_correct_answer))
81
                        illustration = True if question.find("img", class_="img-responsive") else False
82
                        
83
                        for existing_question in self.questions:
84
                            if existing_question.text == question_text:
85
                                for k, answer in enumerate(answer_texts):
86
                                    if answer not in existing_question.answers:
87
                                        existing_question.answers.append(answer)
88
                                        if k + 1 in correct_answers:
89
                                            existing_question.correct_answers.append(len(existing_question.answers))
90
                                break
91
                        else:
92
                            self.questions.add(
93
                                Question(q_type=QuestionType.MultipleChoice, text=question_text, illustration=illustration,
94
                                         answers=answer_texts,
95
                                         correct_answers=correct_answers))
96