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 numpypandas
- 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
.jsonfile
- 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
.infodirectory, thecanvas_credentials.jsonandemail_records.jsonas 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
Accounton the left menu - Navigate to
Account > Settings, scroll down to+ New Access Token - Fill in
PurposeandExpire Date. The key could possibly last forever - Click
Generate. You should be able to see the new API key underApproved Integrationsand 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
+ Groupto create a new assignment group. This will be theassignment_groupargument passed into the constructor of your desired assignment
- Manually navigate to your course, select
- Put course ID and API key into
.info/canvas_credentials.jsonin 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 theSTAFFcell.
| First Name | Last Name | PID (Optional) | |
|---|---|---|---|
| Roger | Roy | abc@ucsd.edu | |
| Roy | Roger | def@ucsd.edu | |
| ... | ... | ... |
- Slido:
- Log into
sli.dousing administrative credentials provided by instructor - Find the correct lecture poll title
- Under the
Analyticspane, clickExport => Download Export => Poll Results per user => XLS => Saveto download the file to your default download directory - Move this file under the same directory as the
enter_grades.ipynbnotebook, change name if needed
- Log into
- Zybook:
- Log into Zybook using administrative credentials and select
Reportingon the bottom-right corner - On the left pane, select the sections assigned
- On the right pane, select
Entire Classand set the deadline - Click
Download Reportand move the file under the same directory as theenter_grades.ipynbnotebook, 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 assignmentfeature; 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 Gradesand 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 Evaluationsand find the csv file for the question - If other sections such as checkpoint are needed, do
Download Grades > Download CSVfrom the other assignment - For all downloaded files, move them under the same directory as the
enter_grades.ipynbnotebook, 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
-
GradebookGeneral Class: Defined ingradebook.py- Constructor Arguments:
course:Canvas.courseobject, 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 underprocessedassignment_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;Noneif 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.DataFrameas the gradebook output, with information such as email, name, assignment grade, etc. Also creates a file underprocesseddirectory for records. Could be overridden to use the above 2 functions differently. This method also creates a record in theprocessedfolderenter_grades(self): Use the produced gradebook, create a Canvas assignment and input grades for each student. Could be overridden.
- Constructor Arguments:
-
Slidoclass: Defined inthird_parties.py- Default Behaviors:
dir_name:'slido'assignment_group:'Lecture Participation'assignment_points:1due_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_pollto thecreate_gradebook(or more specificallycompute_grade) function
- Default Behaviors:
-
WebClickerclass: Defined inthird_parties.py- Default Behaviors:
dir_name:'webclicker'assignment_group:'Participation'assignment_points:1due_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_pollto thecreate_gradebook(or more specificallycompute_grade) function
- Default Behaviors:
-
Zybookclass: Defined inthird_parties.py- Default Behaviors:
dir_name:'readings'assignment_group:'Readings'assignment_points:5due_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:
-
GradescopeClass: Defined inthird_parties.py- Additional Constructor Arguments:
lateness_policy:penaltyorslip_day- If
slip_day, specifytotal_slip_daysin the constructor
- If
lateness_file:str, file name of the lateness question; set toNoneif no lateness needed; defaultNoneredemption_file:str, file name of the redemption assignment; set toNoneif no redemption needed; defaultNoneredemption_rate:float, the portion of lost point that could be redeemed; must be between 0 and 1 (right inclusive) ifredemption_fileis notNoneother_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:100due_time:None
- Important: Lateness Management
- Option 1: Lateness Penalty
- Constructor: Specify
lateness_policy='penalty' - Required parameter
late_policyincreate_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_dayafterenter_grades. This will create a separate slip day assignment in thehomeworksection if it doesn't exist yet, updates slip days in the assignment accordingly, leaving comments to students. - Special: If
assignment_groupis'Project', then the slip day assignment will be found inHomeworkgroup 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_gradebookand inspect the produced gradebook dataframe, usepandascommands if needed - If the gradebook looks good, run the cell below to
enter_grades - If slip day exists, run
process_slip_dayafterenter_grades - After everything is done, move the raw file under the
archivedirectory for records
- Run all cells in
- Notes:
- The
enter_gradesprocess 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
RuntimeErrorabout 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 Searchsection to find the student name, processed results- Check for
@ucsd.eduvs.@gmail.comor 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_RECORDSin theDebug Resultssection- The dictionary has where key is the mismatched email and value is the correct email
- Run the
json.dumpcell 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
archiveandprocesseddirectories 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
Gradebookclass and implement the__init__,convert_raw,compute_grades,create_gradebook, andenter_gradesmethods.
- Gradescope: Link Canvas course and push grades
- Canvas API: Python Documentation
- Canvas API: Full REST API