From 9d176a206de910457a1b05e66aeb34628a23d027 Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Tue, 5 Nov 2013 17:16:21 +0100 Subject: [PATCH] Initial commit, questionhandling --- .gitignore | 6 +++ question.py | 96 +++++++++++++++++++++++++++++++++++++ questions/template.q | 110 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 .gitignore create mode 100644 question.py create mode 100644 questions/template.q diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb28f6a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.*.swp +.*.swo +*.pyc +*.pyo +*~ +*.o diff --git a/question.py b/question.py new file mode 100644 index 0000000..479389b --- /dev/null +++ b/question.py @@ -0,0 +1,96 @@ +import os +import yaml + +class QuestionException(Exception): + pass + +class Questions(object): + QUESTION_TYPES = ["Text", "Image", "Music"] + QUESTION_KEYS = ["Name", "Question", "Answer", "Type", "Double-Jeopardy"] + def __init__(self, qfile): + self.qfile = qfile + self._questions = None + self._read_questions() + + def get_sections(self): + return [s["Section"] for s in self._questions] + + def get_questions(self, section): + sec = filter(lambda s: s["Section"] == section, self._questions) + if len(sec) < 1: + raise ValueError("Section %s does not exist" % (section,)) + return sec[0]["Questions"] + + def get_question(self, section, question): + if type(question) != int or question < 1 or question > 5: + raise ValueError("question parameter needs to be an integer between 1 and 5") + return self.get_questions(section)[question-1] + + def _read_questions(self): + f = None + + # open file + try: + f = open(self.qfile) + except OSError as e: + raise QuestionException("Could not read question file: %s" % e) + + # load yaml + ysrc = None + try: + ysrc = yaml.load(f.read()) + except Exception as e: + raise QuestionException("Error parsing question file %s: %s" % (self.qfile, e)) + + # now to check the integrity of the question file + if type(ysrc) is not list: + raise QuestionException("The questionfile has to be a list of question") + + for i, sec in enumerate(ysrc, 1): + if not "Section" in sec.keys() or not "Questions" in sec.keys(): + raise QuestionException("Section %d needs to have the keys 'Section' and 'Question' (case-sensitive)" % i) + + for j, q in enumerate(sec["Questions"], 1): + # check for keys we need in each question + if any([x not in q.keys() for x in ["Question", "Answer", "Type"]]): + raise QuestionException("Question %d from section %d (%s) is missing one of the keywords Question, Answer or Type" % (j, i, sec["Section"])) + + # check for keys we do not know + for key in q.keys(): + if key not in self.QUESTION_KEYS: + raise QuestionException("Qestion %d from section %d (%s) has invalid keyword '%s'" % (j, i, sec["Section"], key)) + + # check Double-Jeopardy is a bool and is set to false it non-existant + if "Double-Jeopardy" not in q.keys(): + q["Double-Jeopardy"] = False + elif type(q["Double-Jeopardy"]) != bool: + raise QuestionException("The Double-Jeopardy key from question %d from section %d (%s) must be either true or false" % (j, i, sec["Section"])) + + # check for broken question types + if q["Type"] not in self.QUESTION_TYPES: + raise QuestionException("Question %d from Section %d (%s) has an invalid type '%s' (valid types are %s)" % (j, i, sec["Section"], q["Type"], ", ".join(self.VALID_TYPES))) + + # check if file for music/image questions exist + if q["Type"] in ("Music", "Image"): + if not os.path.isfile(q["Question"]): + raise QuestionException("File for question %d, section %d (%s) not found" % (j, i, sec["Section"])) + + # check if this section has enough questions + if j != 5: + raise QuestionException("Section %d (%s) needs to have exactly %d questions (has %d)" % (i, sec["Section"], 5, j)) + + # check for only having unique section names + sections = [s["Section"] for s in self._questions] + if len(sections) != len(set(sections)): + raise QuestionException("All section names must be unique") + + # done, save yaml src to _questions + self._questions = ysrc + + return True + +if __name__ == '__main__': + q = Questions("questions/template.q") + print(q.get_sections()) + print(q.get_questions("A")) + print(q.get_question("A", 1)) diff --git a/questions/template.q b/questions/template.q new file mode 100644 index 0000000..acca42a --- /dev/null +++ b/questions/template.q @@ -0,0 +1,110 @@ + - Section: A + Questions: + - Name: Question 1 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 2 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 3 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 4 + Question: Foo. + Answer: Bar? + Type: Text + Double-Jeopardy: true + + - Name: Question 5 + Question: Foo. + Answer: Bar? + Type: Text + + - Section: B + Questions: + - Name: Question 1 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 2 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 3 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 4 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 5 + Question: Foo. + Answer: Bar? + Type: Text + Double-Jeopardy: true + + - Section: C + Questions: + - Name: Question 1 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 2 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 3 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 4 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 5 + Question: Foo. + Answer: Bar? + Type: Text + + - Section: D + Questions: + - Name: Question 1 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 2 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 3 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 4 + Question: Foo. + Answer: Bar? + Type: Text + + - Name: Question 5 + Question: Foo. + Answer: Bar? + Type: Text +