Skip to content

Instantly share code, notes, and snippets.

@zeimusu
Last active December 23, 2015 15:59
Show Gist options
  • Save zeimusu/6659089 to your computer and use it in GitHub Desktop.
Save zeimusu/6659089 to your computer and use it in GitHub Desktop.
Simple python framework for multiple choice quizzes. It has interfaces for running the quiz on the console or as a cgi script. The cgi interface can be used with jqmath.
#!/usr/bin/env python3
## Example of using the jqmath library.
import cgi
from multipletest import Quiz
mathsq= Quiz("Trig quiz")
mathsq.add_question("Solve $\sin(x) = 0.5$ in range $0<x<2π$.",
"$π/6$ and ${5π}/6$","$π/6$",
"$\π/6$, ${5π}/6$, ${7π}/6$, ${11π}/6$",
helptext="""
There are two solutions. Since $\sin(x)$ is positive, they are found
in the first and second quadrants.""")
form = cgi.FieldStorage()
print("Content-type: text/html\n")
print("""
<!DOCTYPE html>
<html lang="en" xmlns:m="http://www.w3.org/1998/Math/MathML">
<head>
<meta charset="utf-8">
<!--
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=UnifrakturMaguntia">
-->
<link rel="stylesheet" href="/mathscribe/jqmath-0.4.0.css">
<script src="/mathscribe/jquery-1.4.3.min.js"></script>
<script src="/mathscribe/jqmath-etc-0.4.0.min.js"></script>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>""".format(title=mathsq.title))
answered = form.getfirst("answered")
if answered:
mathsq.check_form(form)
else:
mathsq.show_html()
import random
class Question():
def __init__(self,qnum,q,answers,correct=0,helptext=None,shuffle=True):
self.qnum = qnum
self.question = q
self.answers = answers
self.correct = correct
self.helptext = helptext
self.shuffle = shuffle
def make_correction(self):
print("Sorry, the correct answers is:")
print(" ",self.answers[self.correct])
if self.helptext:
print(self.helptext)
def ask_question_html(self):
frame = """
<p class="question">
<span class="qnumber">{qnumber}</span>
{question}
</p>
<p class="answers">
{answerlist}
</p>"""
answerlist = ""
numquest=len(self.answers)
numbers = list(range(numquest))
if self.shuffle : random.shuffle(numbers)
for i in range(numquest):
answerlist += """
<label class="option">
<input type="radio"
id="answer{qnum}.{ansnum}" name="question.{qnum}"
value="{ansnum}"/>&nbsp;{answer}</label><br />""".format(
qnum=self.qnum,
ansnum=numbers[i],
answer=self.answers[numbers[i]])
print(frame.format(qnumber=self.qnum,
question=self.question,
answerlist=answerlist))
def ask_question(self):
""" Asks a question on the console. Checks the answer and returns true
or false."""
print(self.qnum,self.question)
numquest=len(self.answers)
numbers = list(range(numquest))
if self.shuffle : random.shuffle(numbers)
for i in range(numquest):
print (i+1,":", self.answers[numbers[i]])
while True:
try:
ans = int(input(
"Enter an answer from 1 to {}. ".format(numquest)))
except ValueError:
print("I don't understand that answer.")
continue
if ans < 1 or ans > numquest:
print("Must be in range 1 to {}.".format(numquest))
continue
break
return numbers[ans - 1] == self.correct
class Quiz():
def __init__(self,title):
self.quiz = []
self.qcount = 0
self.title=title
def add_question(self,q,*answers,correct=0,helptext=None,shuffle=True):
""" Add a question to the quiz. add_question would normally be called multiple
times at the start of the quiz.
the first argument is the question. Include a question mark.
after that there is a sequence of potential answers.
correct is the index of the correct answer
helptext is usually a longer string that explains the correct answer.
It is normally only seen after an incorrect answer has been given.
shuffle can be set to false to prevent the answers being listed in a
random order. It is useful for true/false quizzes."""
self.qcount += 1
question = Question(
"Q"+str(self.qcount)+".",
q,
answers,
correct,
helptext,
shuffle)
self.quiz.append(question)
def ask_q_number(self,n):
"""Ask and check a single question, given its index in the list"""
q=self.quiz[n]
result = self.ask_question(q)
if result:
print("That's right!")
else:
make_correction(q)
def run_quiz(self):
"""
Run a quiz in text mode. Each question is asked, an answer is sought, and feedback is given.
"""
import os
os.system('cls' if os.name=='nt' else 'clear')
score = 0
for q in self.quiz:
result = q.ask_question()
if result:
print("That's right!")
score += 1
else:
q.make_correction()
print("")
print("You scored {} out of {}.".format(score,len(self.quiz)))
def show_html(self):
"""Run a quiz in html mode.
All the questions are shown with radio buttons.
This can be incorperated into cgi type applications
"""
print('<form id="quiz">')
for q in self.quiz:
q.ask_question_html()
print('<input type="hidden" name="answered" value="True"/>')
print('<button type="submit">Check answers</button></form>')
def check_form(self,fieldstore):
"""
Check and give feedback on a quiz. Fieldstore is the list of key values that a cgi script returns.
fieldstore must include a getfirst method.
A summary of the questions, and correct answers is given, and helptexts are shown for
incorrect answers if available
"""
score = 0
for q in self.quiz:
answerframe = """
<p>I asked "{question}" <br>
You replied "{answer}".<br>
{assessment}</p>
{correction}"""
name = "question."+q.qnum
answernum = int(fieldstore.getfirst(name,"-1"))
answer = q.answers[answernum]
if q.correct == int(answernum):
assessment="That's correct!"
correction =""
score +=1
else:
assessment = "Sorry that's not correct."
correction = """
<p>The correct answer is <strong>{correct}</strong></p>""".format(
correct = q.answers[q.correct])
if q.helptext:
correction += "<p><em>{helptext}</em></p>".format(
helptext=q.helptext)
print(answerframe.format(question=q.question,
answer = answer,
assessment = assessment,
correction = correction))
print("<p>You scored {} out of {} ({}%)<p>".format(score,self.qcount,
100*score//self.qcount))
def main():
"""Silly sample quiz"""
bod= Quiz("test quiz")
bod.add_question("What is your name?", "Arthur", "Kevin", "Robin",
helptext="I only speak to kings")
bod.add_question("What is your quest?", "To resuce the princess",
"To seek the holy grail",correct=1)
bod.add_question("What is your favourite colour?",
"red", "blue", "purple", "green",correct=1)
bod.add_question("It is an african swallow.", "True", "False", shuffle=False)
bod.run_quiz()
if __name__ == "__main__":
main()
#!/usr/bin/env python3
## Text mode quiz.
## The questions are set one by one and immediate feedback given.
from multipletest import Quiz
scienceq= Quiz("Micro-organisms")
scienceq.add_question("Which one is a micro-organism?",
"Bacteria","Ant","Computer","Crab","Atom",
helptext="""
Micro-organisms are creatures which are smaller than mini-beasts.
They are too small to see without a powerful microscope. Examples include
bacteria, viruses and some fungi.""")
scienceq.add_question("All micro-organisms are bad",
"True","False",correct=1,shuffle=False)
scienceq.add_question("Which type of food do micro-organisms NOT make",
"Chocolate","Yogurt","Cheese","Wine","Bread")
scienceq.add_question("What do antibiotics do?",
"Kill bacteria","Cure a fever","Help viruses to grow")
scienceq.run_quiz()
#!/usr/bin/env python3
## CGI mode. The
import cgi
from multipletest import Quiz
scienceq= Quiz("Micro-organisms")
scienceq.add_question("Which one is a micro-organism?",
"Bacteria","Ant","Computer","Crab","Atom",
helptext="""
Micro-organisms are creatures which are smaller than mini-beasts.
They are too small to see without a powerful microscope. Examples include
bacteria, viruses and some fungi.""")
scienceq.add_question("All micro-organisms are bad",
"True","False",correct=1,shuffle=False)
scienceq.add_question("Which type of food do micro-organisms NOT make",
"Chocolate","Yogurt","Cheese","Wine","Bread")
scienceq.add_question("What do antibiotics do?",
"Kill bacteria","Cure a fever","Help viruses to grow")
form = cgi.FieldStorage()
print("Content-type: text/html\n")
print("""
<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>""".format(title=scienceq.title))
answered = form.getfirst("answered")
if answered:
scienceq.check_form(form)
else:
scienceq.show_html()
print("</body></html>")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment