from canvasapi import Canvas
API_URL = 'https://canvas.sydney.edu.au'
API_KEY = '' # Your access token here as a string
# Initialize a Canvas object
canvas = Canvas(API_URL, API_KEY)
# Get your course
course_id = # Your course code here as an int
course = canvas.get_course(course_id)canvasapi
This is a collection of some scripts and components I have used to interact with Canvas, the LMS used at the University of Sydney.
You can find a set of accompanying slides here.
Introduction
Infrastructure, the developers of the Canvas LMS, provide an API that allows users to interact programmatically with Canvas. Documentation here.
canvasapi is a Python wrapper for the Canvas API that was initally developed by a team at the University of Central Florida. Documentation here.
Getting started
canvasapi can be downloaded from pip:
pip install canvasapi
To use the API, you need to obtain an access token. This can be obtained at https://canvas.sydney.edu.au/profile/settings.
Basic commands
Getting a course
Getting student information
students = course.get_users(enrollment_type=['student'])
for student in range(len(list(students))):
# Student ID
sid = students[student].sis_user_id
# Canvas name
name = students[student].name
# Canvas ID
cid = students[student].id
# unikey
email = students[student].login_id
# Email
unikey = students[student].emailGetting assignment information
# Getting all assignments
for a in course.get_assignments():
print(a)
# Get the assignment
assignment = course.get_assignment(123450)
print(assignment)Getting submission details
# Get the assignment using canvasid
submission = assignment.get_submission(cid)
# Get mark
mark = submission.score
# Get lateness
lateness = submission.seconds_late
# Number of submissions
submissions = sub.attempt
# If submission missing
missing = sub.missingEditing submission information
# Mark changes
submission.edit(submission={'posted_grade': new_mark})
# Make a text comment
submission.edit(comment={'text_comment': comment, 'attempt': submission.attempt})
# Upload a feedback file
submission.edit(comment={'file_ids': path_to_file, 'attempt': submission.attempt})Example use cases
External marks and feedback files
import pandas as pd
marks_df = pd.DataFrame([[123456780, 95, 'Great work!'],
[123456781, 55, 'You need to put in more effort!'],
[123456782, 75, 'Keep going!']],
columns=['SID', 'mark', 'comment'])
marks_df.set_index('SID', inplace=True)
for student in range(len(list(students))):
sid = str(students[student].sis_user_id)
cid = int(students[student].id)
submission = assignment.get_submission(cid)
if sid in marks_df.index:
mark = marks_df.loc[sid, 'mark']
submission.edit(submission={'posted_grade': mark})
msg = marks_df.loc[sid, 'comment']
submission.edit(comment={'text_comment': msg,
'attempt': submission.attempt})
submission.edit(comment={'file_ids': f'Assignment1-feedback-{sid}.pdf',
'attempt': submission.attempt})This also makes it possible to mass release individualised assignments by releasing them as feedback files. You can create a release assignment with no submissions required to release an assignment through the feedback section and a separate assignment to collect assignment submissions from students.
Applying late penalties
import math
max_score = 100
for student in range(len(list(students))):
sid = str(students[student].sis_user_id)
cid = int(students[student].id)
submission = assignment.get_submission(cid)
mark = submission.score
lateness = submission.seconds_late
penalty_multiplier = max((math.ceil(lateness / 3600) - 5), 0)
penalty = penalty_multiplier * 0.05 * max_score
submission.edit(submission={'posted_grade': max(0, mark - penalty)})
msg = f'Late penalty applied: {penalty_multiplier} day(s) late'
submission.edit(comment={'text_comment': msg,
'attempt': submission.attempt})Updating lateness
The lateness duration can be updated to account for a grace period so that Canvas automatically compute late penalties.
# grace period
grace = 60 * 10 # 10 minutes
for student in trange(len(list(students))):
cid = int(students[student].id)
sub = assignment.get_submission(cid)
late = sub.late
new_late = (sub.seconds_late - grace)
if late and (new_late <= 0):
sub.edit(submission={'late_policy_status': 'none'})
elif late and (new_late > 0):
sub.edit(submission={'late_policy_status': 'late',
'seconds_late_override': new_late})
if sub.missing:
sub.edit(submission={'late_policy_status': 'missing'})