nbgrader Pipeline

This page walks through the full instructor workflow: writing quiz source cells, generating the student release, and grading.

Prerequisites

  • nbgrader >= 0.9 is installed and a course directory is initialised (nbgrader quickstart or equivalent).

  • nbgrader-jupyterquiz is installed in the same environment.

  • The CreateQuiz preprocessor is registered in nbgrader_config.py (see Configuration).

Writing quiz cells

In your source notebook (under source/<assignment>/), add quiz content inside a Manually Graded Task cell. The cell type must be set to Manually Graded Task in the nbgrader cell toolbar — CreateQuiz will raise an error if a quiz region is found in a plain cell (unless enforce_metadata is disabled).

Inside the cell, wrap questions in #### Quiz / #### End Quiz delimiters. Any text outside the delimiters is preserved verbatim. See Quiz Syntax for the full authoring syntax.

Use the quiz below to check your understanding.

#### Quiz
* (SC) "Which statement about Python lists is true?"
  + "Lists are ordered and mutable."
  - "Lists are ordered and immutable."
  - "Lists are unordered and mutable."
#### End Quiz

Running nbgrader generate_assignment

Run the standard nbgrader assignment generation command:

nbgrader generate_assignment <assignment-name>

CreateQuiz runs as part of the GenerateAssignment preprocessor pipeline. For each quiz region it:

  1. Parses the Markdown quiz source into a list of question dictionaries.

  2. Validates each question against the JSON schema.

  3. In graded mode (the default for any quiz inside a Manually Graded Task cell), redacts the answer key from the question data — drops the correct flags and numeric value / range matchers. See Graded Quizzes for the two-track storage model that keeps the key on the autograder side.

  4. Base64-encodes the (possibly redacted) question data and injects it as a hidden <span> in the cell source. The span carries tex2jax_ignore / mathjax_ignore classes so MathJax leaves the embedded JSON untouched.

  5. Appends a code cell. In graded mode, that cell carries an nbgrader-tracked ### BEGIN HIDDEN TESTS block embedding the full answer key plus a call to grade_quiz(). In ungraded mode, it’s a plain display_quiz() invocation.

The released notebook contains no plaintext answer data in graded mode. Students see only the interactive widget.

Distributing to students

Distribute the release as usual (nbgrader release_assignment, nbgrader zip_collect, or your LMS). No additional steps are required.

Collecting and grading

Collect submissions as usual. Student responses are persisted by the display JS into a responses.json sidecar in the same directory as the notebook, keyed by grade_id. The sidecar is copied through every nbgrader pipeline stage alongside the notebook itself.

At nbgrader autograde time, the hidden-tests block on each graded cell is restored from the gradebook master and re-executed; it reads the sidecar, calls grade_quiz(), and the cell’s bare _result.score expression feeds nbgrader’s partial-credit machinery. See Graded Quizzes for the full workflow.

Configuration

Register CreateQuiz at the front of your GenerateAssignment preprocessor list in nbgrader_config.py:

c.GenerateAssignment.preprocessors.insert(0, "nbgrader_jupyterquiz.CreateQuiz")

It must run before SaveCells so the auto-generated autograder cells are registered in the gradebook, and before ClearHiddenTests so the grading body is properly stripped from the release. Appending to the end of the list (.append(...)) causes autograde to fail with checksum and grade_id validation errors.

When the host Manually Graded Task cell has an nbgrader grade_id, CreateQuiz promotes the quiz to graded mode: correctness feedback is hidden, responses are persisted to a sidecar file, and the cell is autograded at submission time. See Graded Quizzes for the full workflow.

The preprocessor exposes three configurable traitlets:

Option

Default

Description

begin_quiz_delimiter

"#### Quiz"

The string that opens a quiz region.

end_quiz_delimiter

"#### End Quiz"

The string that closes a quiz region.

enforce_metadata

True

Raise an error if a quiz region is found outside a Manually Graded Task cell. Disable only if you are using nbgrader generate_assignment without the full grading pipeline.

To override a traitlet, add it to nbgrader_config.py:

c.CreateQuiz.begin_quiz_delimiter = "### BEGIN QUIZ"
c.CreateQuiz.end_quiz_delimiter   = "### END QUIZ"
c.CreateQuiz.enforce_metadata     = False