0
# Quizzes & Assessments
1
2
Quiz creation, question management, submissions, and both Classic Quizzes and New Quizzes support. Comprehensive assessment tools for measuring student learning and progress.
3
4
## Capabilities
5
6
### Quiz Management
7
8
Create and manage quizzes with comprehensive configuration options.
9
10
```python { .api }
11
class Course(CanvasObject):
12
def get_quizzes(self, **kwargs) -> PaginatedList[Quiz]:
13
"""
14
List quizzes in the course.
15
16
Parameters:
17
- search_term: Search term to filter quizzes
18
- include: Additional data ('assignment', 'overrides', 'all_dates', 'quiz_reports', 'submission_questions', 'html_url', 'mobile_url')
19
20
Returns:
21
Paginated list of Quiz objects
22
"""
23
24
def create_quiz(self, quiz: dict, **kwargs) -> Quiz:
25
"""
26
Create a new quiz.
27
28
Parameters:
29
- quiz: Dictionary with quiz attributes:
30
- title: Quiz title (required)
31
- description: Quiz description (HTML)
32
- quiz_type: Quiz type ('practice_quiz', 'assignment', 'graded_survey', 'survey')
33
- assignment_group_id: Assignment group ID
34
- time_limit: Time limit in minutes
35
- shuffle_answers: Shuffle answer choices
36
- hide_results: Hide results ('always', 'until_after_last_attempt', None)
37
- show_correct_answers: Show correct answers after submission
38
- show_correct_answers_last_attempt: Show correct answers only after last attempt
39
- show_correct_answers_at: Date to show correct answers
40
- hide_correct_answers_at: Date to hide correct answers
41
- allowed_attempts: Number of allowed attempts (-1 for unlimited)
42
- scoring_policy: Scoring policy ('keep_highest', 'keep_latest')
43
- one_question_at_a_time: Show one question at a time
44
- cant_go_back: Prevent going back to previous questions
45
- access_code: Access code required to take quiz
46
- ip_filter: IP address filter
47
- due_at: Due date
48
- lock_at: Lock date
49
- unlock_at: Unlock date
50
- published: Whether quiz is published
51
- one_time_results: Show results only once
52
- only_visible_to_overrides: Only visible to override recipients
53
54
Returns:
55
Quiz object
56
"""
57
58
def get_quiz(self, quiz, **kwargs) -> Quiz:
59
"""
60
Get a single quiz by ID.
61
62
Parameters:
63
- quiz: Quiz object or quiz ID
64
- include: Additional data to include
65
66
Returns:
67
Quiz object
68
"""
69
70
class Quiz(CanvasObject):
71
def edit(self, **kwargs) -> Quiz:
72
"""
73
Edit quiz properties.
74
75
Parameters:
76
- quiz: Dictionary with quiz updates (same structure as create_quiz)
77
78
Returns:
79
Updated Quiz object
80
"""
81
82
def delete(self, **kwargs) -> Quiz:
83
"""Delete the quiz."""
84
```
85
86
### Question Management
87
88
Create and manage quiz questions with various question types.
89
90
```python { .api }
91
def get_questions(self, **kwargs) -> PaginatedList[QuizQuestion]:
92
"""
93
List questions for the quiz.
94
95
Parameters:
96
- quiz_submission_id: Filter by specific submission
97
- quiz_submission_attempt: Filter by submission attempt
98
99
Returns:
100
Paginated list of QuizQuestion objects
101
"""
102
103
def create_question(self, question: dict, **kwargs) -> QuizQuestion:
104
"""
105
Create a quiz question.
106
107
Parameters:
108
- question: Dictionary with question attributes:
109
- question_name: Question name
110
- question_text: Question text (HTML)
111
- question_type: Question type ('multiple_choice_question', 'true_false_question',
112
'short_answer_question', 'fill_in_multiple_blanks_question',
113
'multiple_answers_question', 'multiple_dropdowns_question',
114
'matching_question', 'numerical_question', 'calculated_question',
115
'essay_question', 'uploaded_data_question', 'file_upload_question',
116
'text_only_question')
117
- points_possible: Points for the question
118
- correct_comments: Comments for correct answers
119
- incorrect_comments: Comments for incorrect answers
120
- neutral_comments: General comments
121
- text_after_answers: Text to display after answers
122
- answers: List of answer choices (structure varies by question type)
123
- variables: Variables for calculated questions
124
- formulas: Formulas for calculated questions
125
- answer_tolerance: Tolerance for numerical questions
126
- formula_decimal_places: Decimal places for calculated questions
127
- matches: Matches for matching questions
128
- matching_answer_incorrect_matches: Incorrect matches for matching questions
129
130
Returns:
131
QuizQuestion object
132
"""
133
134
def get_question(self, question_id, **kwargs) -> QuizQuestion:
135
"""Get a single quiz question by ID."""
136
137
class QuizQuestion(CanvasObject):
138
def edit(self, **kwargs) -> QuizQuestion:
139
"""
140
Edit quiz question.
141
142
Parameters:
143
- question: Dictionary with question updates
144
145
Returns:
146
Updated QuizQuestion object
147
"""
148
149
def delete(self, **kwargs) -> QuizQuestion:
150
"""Delete the quiz question."""
151
```
152
153
### Quiz Submissions
154
155
Handle student quiz attempts and submissions.
156
157
```python { .api }
158
def get_submissions(self, **kwargs) -> PaginatedList[QuizSubmission]:
159
"""
160
Get quiz submissions.
161
162
Parameters:
163
- include: Additional data ('submission', 'quiz', 'user')
164
165
Returns:
166
Paginated list of QuizSubmission objects
167
"""
168
169
def get_submission(self, quiz_submission_id, **kwargs) -> QuizSubmission:
170
"""
171
Get a single quiz submission.
172
173
Parameters:
174
- quiz_submission_id: Quiz submission ID
175
- include: Additional data to include
176
177
Returns:
178
QuizSubmission object
179
"""
180
181
def create_submission(self, **kwargs) -> QuizSubmission:
182
"""
183
Start a quiz attempt.
184
185
Parameters:
186
- access_code: Access code if required
187
- preview: Whether this is a preview
188
189
Returns:
190
QuizSubmission object
191
"""
192
193
class QuizSubmission(CanvasObject):
194
def complete(self, **kwargs) -> QuizSubmission:
195
"""
196
Complete/submit the quiz attempt.
197
198
Parameters:
199
- attempt: Attempt number
200
- validation_token: Validation token
201
- access_code: Access code if required
202
203
Returns:
204
Completed QuizSubmission object
205
"""
206
207
def get_questions(self, **kwargs) -> PaginatedList[QuizSubmissionQuestion]:
208
"""
209
Get questions for this submission.
210
211
Parameters:
212
- include: Additional data ('quiz_question')
213
214
Returns:
215
Paginated list of QuizSubmissionQuestion objects
216
"""
217
218
def answer_submission_questions(self, **kwargs) -> QuizSubmissionQuestion:
219
"""
220
Answer quiz questions.
221
222
Parameters:
223
- attempt: Attempt number
224
- validation_token: Validation token
225
- access_code: Access code if required
226
- quiz_questions: List of question answers:
227
- id: Question ID
228
- answer: Answer value (format depends on question type)
229
230
Returns:
231
QuizSubmissionQuestion object
232
"""
233
234
def get_times(self, **kwargs) -> dict:
235
"""Get timing data for the quiz submission."""
236
237
def update_score_and_comments(self, **kwargs) -> QuizSubmission:
238
"""
239
Update submission score and comments (for manually graded questions).
240
241
Parameters:
242
- quiz_submissions: List of submission updates:
243
- attempt: Attempt number
244
- fudge_points: Fudge points to add/subtract
245
- questions: Dictionary of question updates with comments and scores
246
247
Returns:
248
Updated QuizSubmission object
249
"""
250
```
251
252
### Quiz Statistics and Analytics
253
254
Access quiz performance data and analytics.
255
256
```python { .api }
257
def get_statistics(self, **kwargs) -> QuizStatistic:
258
"""
259
Get quiz statistics.
260
261
Parameters:
262
- all_versions: Include all quiz versions
263
264
Returns:
265
QuizStatistic object with performance data
266
"""
267
268
def get_reports(self, **kwargs) -> PaginatedList[QuizReport]:
269
"""
270
Get available quiz reports.
271
272
Returns:
273
Paginated list of QuizReport objects
274
"""
275
276
def create_report(self, report_type: str, **kwargs) -> QuizReport:
277
"""
278
Create a quiz report.
279
280
Parameters:
281
- report_type: Type of report ('student_analysis', 'item_analysis')
282
- quiz_report: Dictionary with report settings:
283
- includes_all_versions: Include all quiz versions
284
285
Returns:
286
QuizReport object
287
"""
288
289
class QuizReport(CanvasObject):
290
def get_file(self, **kwargs) -> File:
291
"""Get the report file once generation is complete."""
292
```
293
294
### New Quizzes Integration
295
296
Support for Canvas New Quizzes (Quizzes.Next) platform.
297
298
```python { .api }
299
def create_new_quiz(self, **kwargs) -> NewQuiz:
300
"""
301
Create a new quiz using New Quizzes platform.
302
303
Parameters:
304
- title: Quiz title
305
- instructions: Quiz instructions
306
- quiz_type: Quiz type
307
- allowed_attempts: Number of allowed attempts
308
- time_limit: Time limit in minutes
309
- due_at: Due date
310
- points_possible: Total points
311
312
Returns:
313
NewQuiz object
314
"""
315
316
class NewQuiz(CanvasObject):
317
"""
318
Represents a New Quiz (Quizzes.Next) assessment.
319
Limited API functionality compared to Classic Quizzes.
320
"""
321
def edit(self, **kwargs) -> NewQuiz:
322
"""Edit new quiz properties."""
323
324
def delete(self, **kwargs) -> NewQuiz:
325
"""Delete the new quiz."""
326
```
327
328
### Question Groups and Banks
329
330
Organize questions into groups and banks for reuse.
331
332
```python { .api }
333
def get_groups(self, **kwargs) -> PaginatedList[QuizGroup]:
334
"""
335
Get question groups for the quiz.
336
337
Returns:
338
Paginated list of QuizGroup objects
339
"""
340
341
def create_group(self, quiz_groups: list, **kwargs) -> QuizGroup:
342
"""
343
Create a question group.
344
345
Parameters:
346
- quiz_groups: List of group dictionaries:
347
- name: Group name
348
- pick_count: Number of questions to pick from group
349
- question_points: Points per question
350
- assessment_question_bank_id: Question bank to draw from
351
352
Returns:
353
QuizGroup object
354
"""
355
356
class QuizGroup(CanvasObject):
357
def edit(self, **kwargs) -> QuizGroup:
358
"""Edit question group properties."""
359
360
def delete(self, **kwargs) -> QuizGroup:
361
"""Delete the question group."""
362
```
363
364
## Usage Examples
365
366
### Creating Comprehensive Quizzes
367
368
```python
369
from canvasapi import Canvas
370
371
canvas = Canvas("https://canvas.example.com", "your-token")
372
course = canvas.get_course(12345)
373
374
# Create a quiz with comprehensive settings
375
quiz = course.create_quiz({
376
'title': 'Midterm Examination',
377
'description': '<p>This exam covers chapters 1-5. You have 90 minutes to complete it.</p>',
378
'quiz_type': 'assignment',
379
'assignment_group_id': exam_group.id,
380
'time_limit': 90,
381
'allowed_attempts': 1,
382
'scoring_policy': 'keep_highest',
383
'shuffle_answers': True,
384
'show_correct_answers': False, # Don't show answers immediately
385
'show_correct_answers_at': '2024-12-01T09:00:00Z', # Show after exam period
386
'one_question_at_a_time': True,
387
'cant_go_back': True, # Prevent students from going back
388
'due_at': '2024-11-15T23:59:59Z',
389
'unlock_at': '2024-11-15T08:00:00Z',
390
'lock_at': '2024-11-15T23:59:59Z',
391
'points_possible': 100,
392
'published': False # Keep unpublished until ready
393
})
394
395
print(f"Created quiz: {quiz.title} (ID: {quiz.id})")
396
```
397
398
### Adding Different Question Types
399
400
```python
401
# Multiple choice question
402
mc_question = quiz.create_question({
403
'question_name': 'Python Data Types',
404
'question_text': 'Which of the following is a mutable data type in Python?',
405
'question_type': 'multiple_choice_question',
406
'points_possible': 5,
407
'answers': [
408
{
409
'answer_text': 'String',
410
'answer_weight': 0,
411
'answer_comments': 'Strings are immutable in Python.'
412
},
413
{
414
'answer_text': 'Tuple',
415
'answer_weight': 0,
416
'answer_comments': 'Tuples are immutable in Python.'
417
},
418
{
419
'answer_text': 'List',
420
'answer_weight': 100, # Correct answer
421
'answer_comments': 'Correct! Lists are mutable in Python.'
422
},
423
{
424
'answer_text': 'Integer',
425
'answer_weight': 0,
426
'answer_comments': 'Integers are immutable in Python.'
427
}
428
],
429
'correct_comments': 'Well done! Lists can be modified after creation.',
430
'incorrect_comments': 'Review the differences between mutable and immutable data types.'
431
})
432
433
# True/False question
434
tf_question = quiz.create_question({
435
'question_name': 'Python Syntax',
436
'question_text': 'Python uses curly braces {} to define code blocks.',
437
'question_type': 'true_false_question',
438
'points_possible': 3,
439
'answers': [
440
{
441
'answer_text': 'True',
442
'answer_weight': 0,
443
'answer_comments': 'Python uses indentation, not curly braces.'
444
},
445
{
446
'answer_text': 'False',
447
'answer_weight': 100,
448
'answer_comments': 'Correct! Python uses indentation to define code blocks.'
449
}
450
]
451
})
452
453
# Short answer question
454
sa_question = quiz.create_question({
455
'question_name': 'Function Definition',
456
'question_text': 'What keyword is used to define a function in Python?',
457
'question_type': 'short_answer_question',
458
'points_possible': 2,
459
'answers': [
460
{
461
'answer_text': 'def',
462
'answer_weight': 100
463
},
464
{
465
'answer_text': 'define',
466
'answer_weight': 0
467
}
468
]
469
})
470
471
# Essay question
472
essay_question = quiz.create_question({
473
'question_name': 'Algorithm Analysis',
474
'question_text': 'Explain the difference between O(n) and O(log n) time complexity. Provide an example of each.',
475
'question_type': 'essay_question',
476
'points_possible': 15,
477
'correct_comments': 'Review your answer for completeness and accuracy.'
478
})
479
480
# Numerical question
481
num_question = quiz.create_question({
482
'question_name': 'Calculation',
483
'question_text': 'What is the result of 2^10?',
484
'question_type': 'numerical_question',
485
'points_possible': 3,
486
'answers': [
487
{
488
'answer_exact': 1024,
489
'answer_error_margin': 0,
490
'answer_weight': 100
491
}
492
],
493
'answer_tolerance': 0
494
})
495
```
496
497
### Managing Quiz Submissions
498
499
```python
500
# Get all submissions for grading
501
submissions = quiz.get_submissions(include=['submission', 'user'])
502
503
print(f"Found {len(submissions)} submissions")
504
505
for submission in submissions:
506
user = submission.user
507
print(f"Student: {user['name']}")
508
print(f"Score: {submission.score}/{quiz.points_possible}")
509
print(f"Attempt: {submission.attempt}")
510
print(f"Time taken: {submission.time_spent} seconds")
511
print(f"Submitted: {submission.submitted_at}")
512
513
# Get submission questions for detailed analysis
514
questions = submission.get_questions(include=['quiz_question'])
515
516
for question in questions:
517
print(f" Q: {question.question_text[:50]}...")
518
print(f" Answer: {question.answer}")
519
print(f" Correct: {question.correct}")
520
print(f" Points: {question.points_awarded}/{question.points_possible}")
521
522
# Grade essay questions manually
523
for submission in submissions:
524
if submission.workflow_state == 'pending_review':
525
# Update scores for manually graded questions
526
submission.update_score_and_comments(
527
quiz_submissions=[{
528
'attempt': submission.attempt,
529
'fudge_points': 2, # Add 2 bonus points
530
'questions': {
531
essay_question.id: {
532
'score': 12, # Out of 15 points
533
'comment': 'Good explanation of time complexity. Could provide more detailed examples.'
534
}
535
}
536
}]
537
)
538
```
539
540
### Creating Question Groups
541
542
```python
543
# Create a question group that randomly selects from a question bank
544
question_group = quiz.create_group([{
545
'name': 'Random Multiple Choice',
546
'pick_count': 5, # Pick 5 questions randomly
547
'question_points': 4, # Each question worth 4 points
548
'assessment_question_bank_id': question_bank.id
549
}])
550
551
# Create a group with specific questions
552
specific_group = quiz.create_group([{
553
'name': 'Required Questions',
554
'pick_count': 3,
555
'question_points': 5
556
}])
557
558
# Add specific questions to the group
559
important_questions = [mc_question.id, tf_question.id, sa_question.id]
560
for question_id in important_questions:
561
# Move existing questions to the group
562
question = quiz.get_question(question_id)
563
question.edit(quiz_group_id=specific_group.id)
564
```
565
566
### Quiz Analytics and Reports
567
568
```python
569
# Get quiz statistics
570
stats = quiz.get_statistics(all_versions=True)
571
572
print(f"Quiz Statistics:")
573
print(f"Submissions: {stats.submission_statistics['scores']['count']}")
574
print(f"Average Score: {stats.submission_statistics['scores']['mean']:.2f}")
575
print(f"High Score: {stats.submission_statistics['scores']['max']}")
576
print(f"Low Score: {stats.submission_statistics['scores']['min']}")
577
578
# Analyze question performance
579
for question_stat in stats.question_statistics:
580
question_id = question_stat['id']
581
correct_percent = question_stat['responses'] / question_stat['answered_student_count'] * 100 if question_stat['answered_student_count'] > 0 else 0
582
583
print(f"Question {question_id}:")
584
print(f" Answered by: {question_stat['answered_student_count']} students")
585
print(f" Average time: {question_stat['time_spent']} seconds")
586
print(f" Difficulty: {question_stat['difficulty_index']:.2f}")
587
588
# Generate detailed reports
589
student_report = quiz.create_report(
590
report_type='student_analysis',
591
quiz_report={'includes_all_versions': True}
592
)
593
594
item_report = quiz.create_report(
595
report_type='item_analysis',
596
quiz_report={'includes_all_versions': True}
597
)
598
599
# Check report status and download when ready
600
import time
601
while student_report.workflow_state == 'generatiing':
602
time.sleep(10)
603
student_report = quiz.get_report(student_report.id)
604
605
if student_report.workflow_state == 'complete':
606
report_file = student_report.get_file()
607
print(f"Student analysis report: {report_file.url}")
608
```
609
610
### Working with New Quizzes
611
612
```python
613
# Create a New Quiz (Quizzes.Next)
614
new_quiz = course.create_new_quiz(
615
title='Interactive Assessment',
616
instructions='Complete all sections of this assessment.',
617
quiz_type='graded',
618
allowed_attempts=2,
619
time_limit=60,
620
due_at='2024-12-01T23:59:59Z',
621
points_possible=50
622
)
623
624
print(f"Created New Quiz: {new_quiz.title}")
625
print(f"Edit URL: {new_quiz.html_url}")
626
627
# Note: New Quizzes have limited API functionality
628
# Most question creation and detailed management happens through the UI
629
```
630
631
### Advanced Quiz Configuration
632
633
```python
634
# Create a practice quiz with immediate feedback
635
practice_quiz = course.create_quiz({
636
'title': 'Chapter 3 Practice Quiz',
637
'description': 'Practice quiz with immediate feedback',
638
'quiz_type': 'practice_quiz',
639
'time_limit': 30,
640
'allowed_attempts': -1, # Unlimited attempts
641
'scoring_policy': 'keep_highest',
642
'show_correct_answers': True,
643
'show_correct_answers_last_attempt': False,
644
'one_question_at_a_time': False,
645
'cant_go_back': False,
646
'shuffle_answers': True,
647
'hide_results': None, # Show results immediately
648
'published': True
649
})
650
651
# Create a secure exam with access restrictions
652
secure_exam = course.create_quiz({
653
'title': 'Final Examination',
654
'quiz_type': 'assignment',
655
'time_limit': 120,
656
'allowed_attempts': 1,
657
'access_code': 'EXAM2024',
658
'ip_filter': '192.168.1.0/24', # Restrict to specific IP range
659
'one_question_at_a_time': True,
660
'cant_go_back': True,
661
'show_correct_answers': False,
662
'lock_at': '2024-12-15T17:00:00Z',
663
'due_at': '2024-12-15T16:00:00Z',
664
'published': False
665
})
666
667
# Create quiz with date overrides for different sections
668
override = secure_exam.create_override({
669
'course_section_id': section_a.id,
670
'title': 'Section A Extended Time',
671
'due_at': '2024-12-15T17:30:00Z', # 30 minutes extra
672
'lock_at': '2024-12-15T17:30:00Z'
673
})
674
```