or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

account-administration.mdassignments-grading.mdcommunication.mdcontent-management.mdcourse-management.mdindex.mdmain-client.mdquizzes-assessments.mduser-management.md

quizzes-assessments.mddocs/

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

```