Detailed usage¶
Here’s a detailed page on what happens to the files when you use these scripts.
Structure¶
Important
The script should only be run on a fresh directory of submission files from Canvas. In other words, don’t run the script more than once on the same set of data. If you want to redo the script again for the same homework submissions, start over from the beginning with the initial set of submission files untouched.
For help and more options for running the script, run
python grade.py --help
$ python grade.py --help
usage: grade.py [-h] [-v] [-n NUMBER_PARTS] [--no-verify] [--no-checks] [-r]
assignment_name directory
positional arguments:
assignment_name The assignment name. Must match an assignment found on
Canvas.
directory the directory containing subdirectories of student
submissions.
optional arguments:
-h, --help show this help message and exit
-v, --verbose print verbose output to stdout.
-n NUMBER_PARTS, --number-parts NUMBER_PARTS
provide the number of parts for this assignment
--no-verify skip jarsigner verification and unarchive all
submission files
--no-checks Don't check for warnings/cheating submissions (checks
by default)
-r, --remove-existing
removes grading files from the directory from a
previous run
The grading script requires a directory of submissions from Canvas.
To grade an assignment, download the .zip file from Canvas and extract its contents to a directory. The directory structure may look something like
directory_with_submissions
|
|--studentname1_studentid1_submissionid1_filename1.ext
|--studentname1_studentid1_submissionid2_filename2.ext
|--studentname1_studentid1_submissionid3_filename3.ext
|--studentname2_studentid2_submissionid4_filename4.ext
|--studentname2_studentid2_submissionid5_filename5.ext
|--studentname3_studentid3_submissionid3_filename.ext
+--...
where ext
is either signed.zip
, zip
, or jar
. (Note:
There were three possible extensions with codecheck because it first
gave out jar
files, and then zip
files. Now, codecheck only
provides students with a signed.zip
file).
To run the script on the directory, the command will be something like
python grade.py "Assignment Name" directory_with_submissions
Where "Assignment Name"
matches the name of the assignment on
Canvas. Don’t forget to enclose the name in quotation marks if it
contains spaces.
When the script runs on a submissions directory, it organizes the directory by separating each student’s submissions to an individual directory. So the directory tree above will become
directory_with_submissions
|
|--studentname1_studentid1
| |
| |--studentname1_studentid1_submissionid1_filename1.ext
| |--studentname1_studentid1_submissionid2_filename2.ext
| +--studentname1_studentid1_submissionid3_filename3.ext
|
|--studentname2_studentid2
| |
| |--studentname2_studentid2_submissionid4_filename4.ext
| |--studentname2_studentid2_submissionid5_filename5.ext
|
|--studentname3_studentid3
| |
| +--studentname3_studentid3_submissionid3_filename.ext
|
+--...
Then, the script will extract the files to their own directory (with the
same name as the .ext file). If the --no-verify
option is specified,
then all files will be extracted. Otherwise, only those that are
verified by jarsigner
will be extracted.
Once all the files are extracted and in their own directories, the
script will begin totaling the codecheck scores from the report.html
files and writing the scores to a file called total_grade.txt
. Then,
the script will walk through the directory tree and aggregate the scores
from the total_grade.txt
files in each student directory into a file
called grades.txt
, which will be found at the root of
directory_with_submissions
.
Summary of the structure¶
Each student’s submissions are moved to his or her own directory named
lastname--firstname-miscname_canvasid
. Then, each codecheck file is
unarchived to its own directory. Each student will have a
total_grade.txt
file found in his or her own directory, and a
grades.txt
file will be found in the directory_of_submissions
(the directory you ran the script with).
Aggregate Java files¶
Also, the script aggregates the java files and the report files. The
script will aggregate all of the java submission files into one file
called aggregate_java_files.txt
in each student directory for
easier viewing of the source files that a student as submitted. Here’s
an example of an aggregated file for a student:
public class StringDemo
{
public static void main(String[] args)
{
String word = "surprise"; //do not change this line
System.out.println(word.length());
}
}
/**************************************************/
public class TextDemo
{
public static void main(String[] args)
{
Text message = new Text(10, 50, "Hello, World!");
message.draw();
}
}
/**************************************************/
public class Rainbow
{
public static void main(String[] args)
{
Rectangle box = new Rectangle(0, 0, 100, 20);
box.setColor(Color.RED);
box.fill();
}
}
A /**************************************************/
is the
separator between different files.
Aggregate report files¶
The report.html
files will be aggregated into one
aggregate_report.html
file per student. These aggregated files are
useful to see the reports of one student’s homework on one page instead
of a page for each part of the homework.
After the above steps, the directory structure will become
directory_with_submissions
|
|--grades.txt
|
|--studentname1_studentid1
| |
| |--studentname1_studentid1_submissionid1_filename1
| | |
| | +--(codecheck files)
| |
| |--studentname1_studentid1_submissionid2_filename2
| | |
| | +--(codecheck files)
| |
| |--studentname1_studentid1_submissionid3_filename3
| | |
| | +--(codecheck files)
| |
| |--studentname1_studentid1_submissionid1_filename1.ext
| |--studentname1_studentid1_submissionid2_filename2.ext
| |--studentname1_studentid1_submissionid3_filename3.ext
| |--aggregate_java_submissions.txt
| |--aggregate_report.html
| +--total_grade.txt
|
+--...
Open reports in the browser¶
With all of these “aggregate_*” files created to help with looking at the
grades, it sure would be helpful to have a fast way to open all of these files
at once. The script open_reports_in_browser.py
will do that for you.
The script opens the aggregate_report.html
files for a given
directory with the default application for html files (probably your
browser).
There are optional arguments (documented below) to provide the script if you only want to open reports for a certain alphabetical range for students’ last names. This is helpful if you’re taking a break for grading and you don’t want to open all the report files, but just the student you left off with and the rest.
To open all the report files, you can run
python open_reports_in_browser.py path/to/directory
Opening all of the report files at once is probably not what you want to do though, because that’s 100+ tabs in your browser at once.
There are -s
and -e
options that are optional. They’re shorthand
for --start-letter
and --end-letter
. (Run
python open_reports_in_browser.py --help
for clarification).
For example, to open report files starting with students whose last names start with ‘G’ and the rest of the students, run
python open_reports_in_browser.py path/to/directory -s G
which will open the reports from the ‘G’ students to the last students (‘Z’ students, implicitly).
To open report files from the beginning of the list until the ‘N’ students, run
python open_reports_in_browser.py path/to/directory -e N
which will open the reports from the beginning of the alphabet (‘A’ students) to the ‘N’ students.
To open reports in a range, say, from ‘G’ to ‘N’, just combine the
options -s
and -e
python open_reports_in_browser.py path/to/directory -s G -e N
There’s a shortcut option, -se
, that can be used if you just want to
start and end with the same letter, which will only open reports within
that single letter’s range.
python open_reports_in_browser.py path/to/directory -se A
which is equivalent to the call
python open_reports_in_browser.py path/to/directory -s A -e A
(Note: the last-name letters are case-insensitive. so -s G
and
-s g
are the same)
And if you would rather open the aggregate_java_files.txt
files
instead of the report files, then supply the -j
option to the
script. They’ll probably open up in your text editor (because the script
opens the files with the default application depending on the file
extension. “txt” usually opens in text editors). The java files take up
less vertical space overall compared to the report files, but the report
files have colors like red that indicate test cases that failed and the
test results of the program (including graphical results for graphics
programs, so the report files are probably the way to go, but aggregate
java files are also an option.
Checking for duplicate submissions¶
Usage:
python check_duplicate_submission_ids.py <directory>
check_duplicate_submission_ids.py
is a script that will check the
submissions directory (that you will pass as an argument to the
script) for any duplicate submission ids in the directory. If any
duplicates are found, then the script will display them like so:
Here are the students who have the same submission id:
Submission id: xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Students:
lastname1--firstname1
lastname2--firstname2
Submission id: yyyyyyyyyyyyyyyyyyyyyyyyyyyy
Students:
lastname3--firstname3
lastname4--firstname4
[... and so on]
If there are no duplicate submission ids, the script will output:
There are no duplicate submission ids.
Grading structure¶
Each student’s submissions are moved to his or her own directory named
lastname--firstname-miscname_canvasid
. Then, each codecheck file is
unarchived to its own directory. Each student will have a
total_grade.txt
file found in his or her own directory, and a
grades.txt
file will be found in the directory_of_submissions
(the directory you ran the script with).
At the top of grades.txt
there are two fields that are used to
identify the assignment:
_canvas_assignment_name
: The name of this assignment._canvas_assignment_id
: The ID of this assignment.
These are used for uploading grades to the correct assignment later when
you use grade_upload.py
.
For each student, grades.txt
file has several fields:
_dir
shows the name of the directory of the student’s submissions_name
shows the name of the student_canvas_id
shows the Canvas ID of the student_total_score
shows the score that the student received for the assignment_comment
holds the comments that you put in for a student’s submission. This will be sent to Canvas and appear as a comment on the student’s assignment. It will only be treated as text, with the beginning and ending whitespace stripped out. This field does not affect the score in any way._notes_and_score_changes
holds the options to mutate the score. If you want to change the score, the first token of a line must be an integer, and that integer must be followed by a single space. You can also write your own personal notes here which will not sent to Canvas.
Both the _comment
and _notes_and_score_changes
fields can be
empty, but you should comment on something with each student. Give some
good feedback :). All other fields should be treated as read-only.
You should only need to write in the _comment
and
_notes_and_score_changes
fields.
Students who’ve received full credit for the assignment will automatically have a comment complimenting them for their good work, including their first name (and middle name, if any. Sometimes including the middle name is appropriate for a name such as “Yin Yan”, but not as much for names such as “Chris Joseph”). Examples include “Good job, Joe.” “Good work, Sally.”, and “Well done, Jessica.”
Example¶
Here’s an example student submission in grades.txt
:
_dir: last_first_0123456
_name: last_first
_canvas_id: 0123456
_total_score: 18/18
_comment:
Good job, but remember to make your instance variables private.
_notes_and_score_changes:
-1 didn't make instance variables private
-2 let's deduct more points for this example
+1 we can add points too
Here's a note. This line won't change the score at all.
--------
The student last_first
with the ID 0123456
would receive 16 (=
18 - 1 - 2 + 1) and see the above comment on Canvas. The
_notes_and_score_changes
field doesn’t get published. It is only
used to modify the score (or write notes), and only the numerical value
at the beginning of a line matters. The label is optional; its only
purpose is to give the score change context. For instance, the above
_notes_and_score_changes
field would function exactly the same as
_notes_and_score_changes:
-1
-2
+1
--------
Uploading the grades¶
Uploading the grades to Canvas will publish the grades automatically
with the grades given by the grades.txt
file for students who
submitted the grades. For students who did not do the homework (i.e.,
they did not submit anything), they will receive a “No submission.”
comment along with a score of 0
automatically when the grades are
submitted.
Run grades_upload.py
to upload the grades to Canvas.
python grades_upload.py path/to/grades.txt
path/to/grades.txt
is the filepath to the grades.txt file you
edited with your grades and comments.
Script Optional Arguments¶
Here’s some detailed description for the optional arguments you can pass to the scripts.
grade.py
¶
- Indicate the number of parts with
-n NUMBER
(or--number-parts NUMBER
)- If you don’t want to deal with the prompt and provide the number
of parts to the assignment at runtime, you can provide the
number of parts as an option when you run the script with
this option, with
NUMBER
being the number of parts for this assignment. (e.g.,3
)
- If you don’t want to deal with the prompt and provide the number
of parts to the assignment at runtime, you can provide the
number of parts as an option when you run the script with
this option, with
- Skip verifying the submission files with
--no-verify
- Instead of checking if the codecheck file is verified before extracting it, the script will skip verifying any files and just extract it. If you want the script to extract all the submission files, regardless of whether or not the codecheck file is actually signed, then use this option. Beware that the script will grade any codecheck file that’s structured correctly even if it’s not signed.
grade_upload.py
¶
- Don’t upload comments with
--no-comments
- By default the upload script will upload both scores and comments.
If you only want to upload the grades, you can use the
--no-comments
option when running the script. Say, you want to reupload all the grades again due to a correction after already submitting grades. If you upload the grades again with comments, the comments will be duplicated. This options avoids duplication.
- By default the upload script will upload both scores and comments.
If you only want to upload the grades, you can use the
- Verbose output with
--verbose
- Use this option to have the script print out the grades before
confirming the upload and print out more information with the URLs
during the upload process. For more information on the possible
options, run
python grade_upload.py --help
.
- Use this option to have the script print out the grades before
confirming the upload and print out more information with the URLs
during the upload process. For more information on the possible
options, run