Skip to content

Commit

Permalink
demo quizzes
Browse files Browse the repository at this point in the history
  • Loading branch information
parmentelat committed Mar 28, 2020
1 parent 2409f4a commit 479bb57
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 53 deletions.
16 changes: 3 additions & 13 deletions demo-notebooks/demo08-quiz.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
# ---

# %% [markdown]
# # some quizzes
# # one sample quiz

# %% {"scrolled": true}
# mostly for using under binder or in a devel tree
Expand All @@ -41,17 +41,7 @@
# %autoreload 2

# %% [markdown]
# ## a quizz is made of questions

# %% [markdown]
# a Quiz object contains one or several questions; here is an example with a single question

# %% {"scrolled": false}
from exercises.quizsample import single_quiz
single_quiz.widget()

# %% [markdown]
# ## more questions
# ## a quiz is made of questions
#
# in this notebook the correct answers are always the one starting with 'a'

Expand All @@ -65,5 +55,5 @@
# %% [markdown]
# Here's the code that defines the above quizz

# %% {"scrolled": true}
# %% {"scrolled": false}
# !cat ../exercises/quizsample.py
60 changes: 60 additions & 0 deletions demo-notebooks/demo09-quiz2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# ---
# jupyter:
# jupytext:
# cell_metadata_filter: all
# cell_metadata_json: true
# formats: py:percent
# notebook_metadata_filter: all,-language_info,-jupytext.text_representation.jupytext_version
# text_representation:
# extension: .py
# format_name: percent
# format_version: '1.3'
# kernelspec:
# display_name: Python 3
# language: python
# name: python3
# toc:
# base_numbering: 1
# nav_menu: {}
# number_sections: true
# sideBar: true
# skip_h1_title: false
# title_cell: Table of Contents
# title_sidebar: Contents
# toc_cell: false
# toc_position: {}
# toc_section_display: true
# toc_window_display: false
# ---

# %% [markdown]
# # another quiz

# %% {"scrolled": true}
# mostly for using under binder or in a devel tree
import sys
sys.path.append('..')

# %% {"scrolled": true}
# for convenience in development
# %load_ext autoreload
# %autoreload 2

# %% [markdown]
# ## a quizz is made of questions

# %% [markdown]
# a Quiz object contains one or several questions; here is an example with a single question

# %% {"scrolled": false}
from exercises.quizsample2 import quiz2
quiz2.widget()

# %% [markdown]
# ## under the hood

# %% [markdown]
# Here's the code that defines the above quizz

# %% {"scrolled": false}
# !cat ../exercises/quizsample2.py
28 changes: 6 additions & 22 deletions exercises/quizsample.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,5 @@
from nbautoeval import Quiz, QuizQuestion, Option, CodeOption, MathOption

###
# most basic single-answer

question_basic_single = QuizQuestion(
"Pick the right fruit\n(one correct option)",
options=[
Option("banana"),
Option("pear"),
Option("apple", correct=True),
],
horizontal=True,
)
single_quiz = Quiz(
"quizsample-single",
[question_basic_single])


questions = []
###
question_basic_multiple = QuizQuestion(
Expand All @@ -30,7 +13,7 @@
Option("pineapple"),
],
score = 1,
horizontal=True,
horizontal_layout=True,
)
questions.append(question_basic_multiple)

Expand All @@ -46,7 +29,7 @@
],
shuffle=False,
score = 2,
horizontal=True,
horizontal_layout=True,
)
questions.append(question_unshuffle)

Expand All @@ -65,7 +48,7 @@
MathOption(r"multiple double dollars $$\forall x\in\mathbb{R}$$ $$\forall x\in\mathbb{R}$$ $$\forall x\in\mathbb{R}$$"),
],
score = 3,
horizontal=True,
horizontal_layout=True,
)
questions.append(question_math)

Expand All @@ -78,7 +61,8 @@
Option("pear"),
],
score = 4,
horizontal=True,
horizontal_layout=True,
horizontal_options=True,
)
questions.append(question_none)

Expand All @@ -93,7 +77,7 @@
CodeOption("b = sort(x for x in list if x.is_valid())"),
],
score = 5,
horizontal=True,
horizontal_options=True,
)
questions.append(question_code)

Expand Down
58 changes: 58 additions & 0 deletions exercises/quizsample2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from nbautoeval import Quiz, QuizQuestion, Option, CodeOption, MathOption


############
quiz2 = Quiz(

# needs a unique name for storing progress and marks
"quizsample-horizontal",

[
QuizQuestion("""
horizontal_layout means to have
<br>the questions and the options
<br>in a horizontal box""",
options=[
Option('<img src="../media/image1.png">', correct=True),
Option('<img src="../media/image2.png" width="250px">'),
],
horizontal_layout=True,
),


QuizQuestion("""
horizontal_options means the options appear side by side like here,
because horizontal_layout is False the question spans 100% of page width
""",
options=[
Option('<img src="../media/image1.png">', correct=True),
Option('<img src="../media/image2.png" width="250px">'),
],
horizontal_options=True,
),


QuizQuestion("""
the default is to have none of these 2 horizontal flags
""",
options=[
Option('<img src="../media/image1.png">', correct=True),
Option('<img src="../media/image2.png" width="250px">'),
],
),

QuizQuestion("""
of course they can be used together as well""",
options=[
Option('<img src="../media/image1.png">', correct=True),
Option('<img src="../media/image2.png" width="250px">'),
],
horizontal_layout=True,
horizontal_options=True,
),


],
max_attempts = 5,
)

Binary file added media/image1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added media/image2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 22 additions & 18 deletions nbautoeval/quiz.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def __iter__(self):

# usually options are displayed in some random order
class _DisplayedOptionsList:
def __init__(self, options: List[GenericBooleanOption], shuffle=True):
def __init__(self, options: List[GenericBooleanOption], shuffle):
self.displayed = options[:]
if shuffle:
random.shuffle(self.displayed)
Expand Down Expand Up @@ -126,6 +126,11 @@ def __iter__(self):
}
"""

def points(score):
return f"{score} {'pt' if score<=1 else 'pts'}"



class QuizQuestion:
"""
question may include html tags and/or math content between '$$'
Expand All @@ -144,12 +149,15 @@ class QuizQuestion:
def __init__(self, question: str, options: List,
*,
score = 1,
shuffle=True, horizontal=False):
shuffle=True,
horizontal_layout=False,
horizontal_options=False):
self.question = question
self.options_list = _OptionsList(options)
self.displayed = _DisplayedOptionsList(options)
self.displayed = _DisplayedOptionsList(options, shuffle)
self.score = score
self.horizontal = horizontal
self.horizontal_layout = horizontal_layout
self.horizontal_options = horizontal_options
self.feedback_area = None
self._widget_instance = None

Expand All @@ -159,29 +167,25 @@ def widget(self):
if self._widget_instance:
return self._widget_instance

points = f"{self.score} {'pt' if self.score<=1 else 'pts'}"
points_question = f'<div class="score">{points}</div>{self.question}'
points_question = f'<div class="score">{points(self.score)}</div>{self.question}'

question = HTMLMath(points_question)
question.add_class('question')

self.checkboxes = [Checkbox(value=option.selected, disabled=False, description='', indent=False)
for option in self.displayed]
labels = [option.render().widget() for option in self.displayed]
answers = VBox([HBox([checkbox, label])
for (checkbox, label) in zip(self.checkboxes, labels)])
options_box = HBox if self.horizontal_options else VBox
answers = options_box(
[HBox([checkbox, label])
for (checkbox, label) in zip(self.checkboxes, labels)])
answers.add_class("answers")

css_widget = CssContent(CSS).widget()

if not self.horizontal:
self._widget_instance = VBox([question,
answers,
css_widget])
else:
self._widget_instance = HBox([question,
answers,
css_widget])
layout_box = HBox if self.horizontal_layout else VBox
self._widget_instance = layout_box(
[question, answers, css_widget])
self._widget_instance.add_class("nbae-question")
self.feedback_area = self._widget_instance
self.feedback(None)
Expand Down Expand Up @@ -293,8 +297,8 @@ def update(self):
self.submit_button.description = "quiz over"
current_score, max_score = self.score()
self.submit_summary.value = (
f"final score {current_score} / {max_score}"
f" -- after {self.current_attempts} attempts / {self.max_attempts}"
f"final score {current_score} / {points(max_score)} "
f" -- after {self.current_attempts} / {self.max_attempts} attempts"
)
if all(self.answers):
self.submit_summary.add_class("ok")
Expand Down

0 comments on commit 479bb57

Please sign in to comment.