QuestionBankToolkit
QuestionBankToolkit validates question banks written in YAML, builds QTI 1.2 ZIP packages for Canvas, and extracts supported QTI 1.2 questions into YAML. The current scope is single-answer multiple-choice questions. QTI imports and structural checks reject XML document type declarations (DTDs), entity declarations, and external entity references. Python 3.14 or newer is required.
Install the released package from PyPI:
python -m pip install QuestionBankToolkit
See the YAML schema and the sample bank for the source format.
The documentation site provides the complete user guide, schema, command reference, and Python API reference.
The optional bank field default_shuffle_choices controls answer-choice shuffling in generated QTI, and a question-level shuffle_choices boolean can override it.
If both fields are omitted, shuffling defaults to false.
Start here
The beginner workflow explains Python installation on Windows, macOS, and Linux; provides a complete copyable bank; and walks through validation, build review, and Canvas upload.
The generated COURSE_BANK_ID_QTI12.zip file is the file uploaded to Canvas.
After installation, validate a YAML bank with:
coursebanks validate examples/sample_course/questions.yaml
The command reports invalid fields and rejects malformed YAML, duplicate mapping keys, and nonfinite grading points or time estimates. See the validation rules for supported values and diagnostics. See the command reference and troubleshooting guide for every command's output, exit status, file policy, and common errors.
Optional: importing QTI
Import a supported QTI 1.2 ZIP package into a new YAML bank with:
coursebanks import-qti questions.zip --course COURSE123 --bank-id ImportedBank --title "Imported bank" --out imported.yaml
The importer supports a strict single-answer multiple-choice subset, including Canvas Common Cartridge item-bank exports, and rejects unsupported or ambiguous structures. See the QTI import guide for required package structure, defaults, choice-label normalization, metadata CSV overrides, and the field-by-field compatibility table.
Optional: selecting and recording questions
Assessment names can describe exams, weekly quizzes, or homework.
A question's optional assessments list restricts where it can be used; an empty or omitted list allows any assessment.
coursebanks select questions.yaml --assessment "Homework 1" --count 5
coursebanks record questions.yaml --term 2027-Fall --assessment "Homework 1" --ids Q01 Q02
coursebanks plan questions.yaml --terms 2027-Fall 2028-Spring --assessment "Quiz 1" 3 --assessment "Homework 1" 2 --out plan.csv
Selection and planning only propose questions; record the IDs actually administered.
Counts are nonnegative integers and plan counts apply in each term.
Repeat --assessment NAME COUNT for each planned assessment; this replaces the former --midterm and --final plan options.
Selection and recording still accept --exam as an alias for --assessment.
All three commands accept --history PATH (default usage.csv), and selection and planning accept --seed for reproducible proposals.
Recorded questions cannot be reused within the same course and bank, even for a different assessment.
New history and plan CSVs use the column assessment; legacy histories with an exam column remain readable and keep that header when appended.
Existing YAML banks are converted on load without changing their files or schema version. See migration details for the legacy-value mapping and QTI metadata behavior.
For contributors
Check that python --version reports Python 3.14 or newer.
From the repository root, use that interpreter to create and activate a virtual environment, then install the package and development tools:
python -m venv .venv
On Linux or macOS, activate it with source .venv/bin/activate.
On Windows PowerShell, use .venv\Scripts\Activate.ps1.
python -m pip install -e . --group dev
python -m pytest
Tests use synthetic questions and do not require private course content or Canvas access.
With the environment activated, run all development checks using:
./scripts/run_checks.sh
The script runs pytest, Ruff lint and formatting, strict mypy, strict BasedPyright, and pydoclint.
See the developer guide for individual commands, environment configuration, and the typed Python API.
For Python callers, load_bank returns a validated bank; use load_yaml to edit incomplete drafts and parse_bank to validate and construct a bank from draft data.
Metadata
Release files for QuestionBankToolkit 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| questionbanktoolkit-0.1.1.tar.gz | 129.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| questionbanktoolkit-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 185.6 kB
Release files / questionbanktoolkit-0.1.1.tar.gz
| Download URL | questionbanktoolkit-0.1.1.tar.gz |
|---|---|
| Size | 129.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
11e18730562e5d4865d2d5434ed7c793e62b86001b5ce009a8571663eeb6129f
|
|
BLAKE2b-256 checksum How to use checksums |
10a201a14ab327ad669a6d255b33f57c2d8dbaecc4618ded942d17f8fde1ffe0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.8
|
Release files / questionbanktoolkit-0.1.1-py3-none-any.whl
| Download URL | questionbanktoolkit-0.1.1-py3-none-any.whl |
|---|---|
| Size | 56.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1e75bc5cf74db1c81190c2273a4c9c6bd2a95ca721757be4fb1f99192363a73d
|
|
BLAKE2b-256 checksum How to use checksums |
fe5b096c1bd35e11ca44fa4863ec65451207c2587500a7c41256649bb26546f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.8
|
Security for QuestionBankToolkit 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.