A general framework to use automated pipelines to enter grades into the Canvas Gradebook according to the Canvas roster. Developed for Data Science Courses at University of California, San Diego.
Author: Yacun Wang, September 2023
- Python 3
- Jupyter Notebook with Python kernel
- Python Packages:
- Canvas API:
pip install canvasapi
numpy
pandas
- Canvas API:
- Canvas Administrative Access (TA or Instructor)
- Administrative Access to third-party sites, or files exported
- Setup:
- Canvas Setup: For accessing new course information from Canvas API
- Personnel Setup: Student/Staff Profiles, Email History
- Updates student roster file from Canvas
- Reads in staff roster
- Reads in mismatched email history
.json
file
- Assignment Cells: Cells designated to currently supported assignment types
- Student Search and Debug Results
- For manually inspecting undetected emails from student roster and gradebook
- Insert and preview current list of mismatched emails
- Save as mismatched email file for later use
- Note: This is a sample workspace only. Remember to change paths in the script if you prefer using a different workspace.
grades_dsc/
├── .info/ <- credentials
│ ├── canvas_credentials.json
│ ├── email_records.json
│ └── students.csv
├── archive/ <- raw files
├── processed/ <- processed gradebook
├── src/ <- source code
│ ├── gradebook.py <- general class
│ └── third_parties.py <- customized classes
├── enter_grades.ipynb <- main notebook
└── README.md
- Create the
.info
directory, thecanvas_credentials.json
andemail_records.json
as empty JSON files - Get Canvas course ID:
https://canvas.ucsd.edu/courses/<course_id>
- Get Canvas API Key (if you don't have an unexpired one):
- Log into Canvas, find
Account
on the left menu - Navigate to
Account > Settings
, scroll down to+ New Access Token
- Fill in
Purpose
andExpire Date
. The key could possibly last forever - Click
Generate
. You should be able to see the new API key underApproved Integrations
and receive an email from Canvas.
- Log into Canvas, find
- Create a new assignment group:
- Manually navigate to your course, select
Assignments
- Use the top right button
+ Group
to create a new assignment group. This will be theassignment_group
argument passed into the constructor of your desired assignment
- Manually navigate to your course, select
- Put course ID and API key into
.info/canvas_credentials.json
in the'COURSE_ID'
and'API_KEY'
keys, respectively. - Finally, obtain a CSV of staff information of the following format, and place the file path in the staff profiles cell. If staff mixed in gradebook is fine for you, define
STAFF = []
in place of theSTAFF
cell.
First Name | Last Name | PID (Optional) | |
---|---|---|---|
Roger | Roy | [email protected] | |
Roy | Roger | [email protected] | |
... | ... | ... |
- Slido:
- Log into
sli.do
using administrative credentials provided by instructor - Find the correct lecture poll title
- Under the
Analytics
pane, clickExport => Download Export => Poll Results per user => XLS => Save
to download the file to your default download directory - Move this file under the same directory as the
enter_grades.ipynb
notebook, change name if needed
- Log into
- Zybook:
- Log into Zybook using administrative credentials and select
Reporting
on the bottom-right corner - On the left pane, select the sections assigned
- On the right pane, select
Entire Class
and set the deadline - Click
Download Report
and move the file under the same directory as theenter_grades.ipynb
notebook, change name if needed
- Log into Zybook using administrative credentials and select
- Gradescope:
- For assignments that the gradescope assignment score is exactly the same as the Canvas assignment score, please use the
link assignment
feature; for other assignments such as those having lateness or checkpoints, follow along. - Log into Gradescope using administrative credentials and select the main assignment page from the course
- Find
Download Grades
and selectDownload CSV
(could be inMore
) - If lateness is needed, create a question with 1 rubric item per deduction level; download the graded rubric by
Export Evaluations
and find the csv file for the question - If other sections such as checkpoint are needed, do
Download Grades > Download CSV
from the other assignment - For all downloaded files, move them under the same directory as the
enter_grades.ipynb
notebook, change names if needed. This includes moving the lateness file outside of the original evaluation folder
- For assignments that the gradescope assignment score is exactly the same as the Canvas assignment score, please use the
-
Gradebook
General Class: Defined ingradebook.py
- Constructor Arguments:
course
:Canvas.course
object, obtained from setupstudents
:pd.DataFrame
, obtained from personnel setupstaff
:pd.DataFrame
, obtained from personnel setupemail_records
:dict
, obtained from personnel setupfile_name
:str
, the main assignment file nameassignment_name
:str
, the assignment name showed on Canvas, and the name of the score column on gradebookdir_name
:str
, the name of the sub-directory underprocessed
assignment_group
:str
, the name of the assignment group on Canvas; must be exact string matchassignment_points
:int
, the total points possible for the assignmentdue_time
:str
, the due datetime string in the format of'yyyy-mm-dd hh:mm'
, in 24-hour format;None
if no due date is needed
- Main Methods to implement:
convert_raw(self, **kwargs)
: Reads the raw file and cleans the dataframecompute_grade(self, **kwargs)
: Computes the assignment grade according to the cleaned filecreate_gradebook(self, **kwargs)
: Use the two functions above and creates apd.DataFrame
as the gradebook output, with information such as email, name, assignment grade, etc. Also creates a file underprocessed
directory for records. Could be overridden to use the above 2 functions differently. This method also creates a record in theprocessed
folderenter_grades(self)
: Use the produced gradebook, create a Canvas assignment and input grades for each student. Could be overridden.
- Constructor Arguments:
-
Slido
class: Defined inthird_parties.py
- Default Behaviors:
dir_name
:'slido'
assignment_group
:'Lecture Participation'
assignment_points
:1
due_time
:None
(no change)
- Grading Rubric: Gets 1 point if answered at least
min_poll
(default 0.75) of the polls, otherwise 0 points. Pass in other values ofmin_poll
to thecreate_gradebook
(or more specificallycompute_grade
) function
- Default Behaviors:
-
WebClicker
class: Defined inthird_parties.py
- Default Behaviors:
dir_name
:'webclicker'
assignment_group
:'Participation'
assignment_points
:1
due_time
:None
(no change)
- Required Configuration:
session
, pass in session number for the lecture you're processing - Grading Rubric: Gets 1 point if answered at least
min_poll
(default 0.75) of the polls, otherwise 0 points. Pass in other values ofmin_poll
to thecreate_gradebook
(or more specificallycompute_grade
) function
- Default Behaviors:
-
Zybook
class: Defined inthird_parties.py
- Default Behaviors:
dir_name
:'readings'
assignment_group
:'Readings'
assignment_points
:5
due_time
:None
- Required Configuration:
dict
, where keys are sections in strings and values are lists of activities assigned for the sections. Pass inconfig=config
.- Example:
config = { '1.2': ['Participation'], '1.3': ['Participation', 'Challenge'], '1.4': ['Challenge'] }
- Note: Discussion Zylabs should also use this class, with suggested
dir_name='zylab'
andassignment_group='Discussion Zylab'
- Default Behaviors:
-
Gradescope
Class: Defined inthird_parties.py
- Additional Constructor Arguments:
lateness_policy
:penalty
orslip_day
- If
slip_day
, specifytotal_slip_days
in the constructor
- If
lateness_file
:str
, file name of the lateness question; set toNone
if no lateness needed; defaultNone
redemption_file
:str
, file name of the redemption assignment; set toNone
if no redemption needed; defaultNone
redemption_rate
:float
, the portion of lost point that could be redeemed; must be between 0 and 1 (right inclusive) ifredemption_file
is notNone
other_section_files
:dict
, where keys will be used as column names and values are corresponding section file names; defaultNone
- Default Behaviors:
dir_name
:'homework'
assignment_group
:'Homework'
assignment_points
:100
due_time
:None
- Important: Lateness Management
- Option 1: Lateness Penalty
- Constructor: Specify
lateness_policy='penalty'
- Required parameter
late_policy
increate_gradebook
: A dictionary where keys are keywords that are part of the rubric item strings and values are deduct percentages - Example:
late_policy = { 'no late': 1.0, # no deduction '1 day': 0.8, # take 20% off '2 days': 0.5 # take 50% off }
- Constructor: Specify
- Option 2: Slip Days
- Constructor: Specify
lateness_policy='slip_day'
andtotal_slip_days
. The latter is required for the first time only, but is recommended to keep it throughout the quarter; - Call the method
process_slip_day
afterenter_grades
. This will create a separate slip day assignment in thehomework
section if it doesn't exist yet, updates slip days in the assignment accordingly, leaving comments to students. - Special: If
assignment_group
is'Project'
, then the slip day assignment will be found inHomework
group for consistency - Special: If a student only submits redemption but no regular assignment, a slip day will be applied for fairness to other students
- Constructor: Specify
- Option 1: Lateness Penalty
- Important: Redemption Management
- Redemption applies to autograded parts only; please define manual deductions or addition parts to include either of the keywords, case sensitive:
'Manual Check'
'Extra Credit'
- Contact the author if more keywords are needed
- Redemption applies to autograded parts only; please define manual deductions or addition parts to include either of the keywords, case sensitive:
- Additional Constructor Arguments:
- General Procedure
- Run all cells in
Setup
- Find the assignment type to transfer, change the parameters defined in the cell, and possibly other parameters listed above
- Run the cell containing
create_gradebook
and inspect the produced gradebook dataframe, usepandas
commands if needed - If the gradebook looks good, run the cell below to
enter_grades
- If slip day exists, run
process_slip_day
afterenter_grades
- After everything is done, move the raw file under the
archive
directory for records
- Run all cells in
- Notes:
- The
enter_grades
process will take a while as Canvas calls REST API under the hood for each operation - If the assignment is created successfully, you will receive Gmail and Canvas notifications if they are turned on
- If the cell raises a
RuntimeError
about having no access to Canvas, go to Canvas to manually delete the new assignment created, and rerun the cell
- The
- Resolve undetected emails
- The pipeline will print all mismatched emails to the console, mostly because students are following the class but have no access to Canvas (ignore) or made typos to their email
- Use the
Student Search
section to find the student name, processed results- Check for
@ucsd.edu
vs.@gmail.com
or others - Check for mistyped names
- Use your Gmail and type the email in recepients to check for possible matches
- Use some creativity
- Note: If you are really unable to find the student, ignore the mismatched email
- Check for
- Navigate to Canvas, select
Grades
, find the student and the assignement, and manually change the grade by clicking on that cell and type the new grade - Record the new mismatched email into
EMAIL_RECORDS
in theDebug Results
section- The dictionary has where key is the mismatched email and value is the correct email
- Run the
json.dump
cell to update the local file
- Sometimes students will ask why they missed a lecture on the forum or via email
- Locate their information from both the raw file and the processed file in
archive
andprocessed
directories respectively - Remind them that 6 (or 3) total grades will be dropped, and participation only worth 2%, so missing a few lectures is not affecting the grade by a lot (also applicable to late-enrolled students)
- From the instructor:
These grades end up not affecting anyone after the final grade is posted if students miss a few lectures. Students could request checking final grade after the quarter ends, but none find participation grade essential.
- Sample Respond Format:
Hi! I have checked the sli.do record for you, and it seemed like you were missing Question X, leading to ?/? questions answered. Note that you need to answer at least 75% of the questions to get the credit. Please make sure that you click submit for every question, and then later actions such as changing answers should not affect the existence of your answers. But no worries since you have 6 lectures to drop throughout the quarter. Hope this helps!!
The entire pipeline could be customized in the following ways:
- Change the default behaviors to the desired
- Change the source code to change the behavior
- Add new assignment types (e.g. Google Forms, Stepik, etc.) by inheriting the
Gradebook
class and implement the__init__
,convert_raw
,compute_grades
,create_gradebook
, andenter_grades
methods.
- Gradescope: Link Canvas course and push grades
- Canvas API: Python Documentation
- Canvas API: Full REST API