diff --git a/README.md b/README.md index 7c2f957..0df938a 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,13 @@ This is a shortcut for [`autograder.cli.courses.assignments.submissions.submit`] python3 -m autograder.run.submit my_file.py ``` +To submit an assignment late, use the following command. +For more information and examples, see the [late submission section](#submitting-an-assignment-late) of this document. + +```sh +python3 -m autograder.run.submit --allow-late my_file.py +``` + ### `autograder.run.history` This command gets a summary of all your past submissions for an assignment. @@ -223,6 +230,31 @@ The autograder failed to grade your assignment. Message from the autograder: Request could not be authenticated. Ensure that your username, password, and course are properly set. ``` +##### Submitting an Assignment Late + +If you are submitting an assignment late, the autograder requires confirmation in order to grade your submission. +This helps users avoid situations where they accidentally submit an assignment late or submit to the wrong assignment. +Users must add the `--allow-late` flag to the normal submission command when they want to submit an assignment past the due date. + +For example, your output when submitting a late assignment may look like: +``` +--- Message from Autograder --- +Attempting to submit assignment (HO0) late without the 'allow late' option. +It was due on 2024-12-13 16:00 (which was 48h34m57.178s ago). +Use the 'allow late' option to submit an assignment late. +See your interface's documentation for more information. +------------------------------- +Submission was rejected by the autograder. +``` + +When you see this message, be sure to double check the assignment name and due date. +If those details look correct and you want to submit that assignment late, then run the following command: +```sh +python3 -m autograder.run.submit --allow-late my_file.py +``` + +Now, the server will grade your late submission like normal! + #### Checking Your Last Submission You can ask the autograder to show you the grade report for your last submission using the diff --git a/autograder/api/courses/assignments/submissions/submit.py b/autograder/api/courses/assignments/submissions/submit.py index 58302bd..e725b57 100644 --- a/autograder/api/courses/assignments/submissions/submit.py +++ b/autograder/api/courses/assignments/submissions/submit.py @@ -10,7 +10,12 @@ autograder.api.config.APIParam('message', 'An optional message to attatch to the submission.', - required = False) + required = False), + + autograder.api.config.APIParam('allow-late', + 'Allow this submission to be graded, even if it is late (default: %(default)s).', + required = False, + parser_options = {'action': 'store_true', 'default': False}) ] DESCRIPTION = 'Submit an assignment submission to the autograder.' diff --git a/tests/api/test_api.py b/tests/api/test_api.py index 34a4397..a5bf880 100644 --- a/tests/api/test_api.py +++ b/tests/api/test_api.py @@ -16,6 +16,12 @@ TIMESTAMP_PATTERN = r'\b\d{10,13}\b' TIMESTAMP_REPLACEMENT = '1234567890123' +TIME_DELTA_PATTERN = r'(\d+h)?(\d+m)?(\d+\.)?(\d+[mun]?s)' +TIME_DELTA_REPLACEMENT = '' + +TIME_MESSAGE_PATTERN = r'' +TIME_MESSAGE_REPLACEMENT = '' + class APITest(tests.server.base.ServerBaseTest): """ Test API calls by mocking a server. @@ -110,6 +116,8 @@ def clean_output_timestamps(output): # Convert the output to JSON so we can do a simple find/replace for all timestamps-like things. text_output = json.dumps(output) text_output = re.sub(TIMESTAMP_PATTERN, TIMESTAMP_REPLACEMENT, text_output) + text_output = re.sub(TIME_DELTA_PATTERN, TIME_DELTA_REPLACEMENT, text_output) + text_output = re.sub(TIME_MESSAGE_PATTERN, TIME_MESSAGE_REPLACEMENT, text_output) return json.loads(text_output) diff --git a/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_base.json b/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_base.json index eface92..d2dad52 100644 --- a/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_base.json +++ b/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_base.json @@ -1,6 +1,7 @@ { "module": "autograder.api.courses.assignments.submissions.submit", "arguments": { + "allow-late": false }, "files": [ "__DATA_DIR__(hw0_solution.py)" diff --git a/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_epoch_allow.json b/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_epoch_allow.json new file mode 100644 index 0000000..10aa143 --- /dev/null +++ b/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_epoch_allow.json @@ -0,0 +1,41 @@ +{ + "module": "autograder.api.courses.assignments.submissions.submit", + "arguments": { + "course": "course-languages", + "assignment": "bash", + "allow-late": true + }, + "files": [ + "__DATA_DIR__(assignment.sh)" + ], + "output-modifier": "clean_output_timestamps", + "output": { + "rejected": false, + "message": "", + "grading-success": true, + "result": { + "id": "course-languages::bash::course-admin@test.edulinq.org::1234567890123", + "short-id": "1234567890123", + "course-id": "course-languages", + "assignment-id": "bash", + "user": "course-admin@test.edulinq.org", + "message": "", + "max_points": 10, + "score": 10, + "name": "bash", + "questions": [ + { + "name": "Task 1: add()", + "max_points": 10, + "score": 10, + "message": "", + "grading_start_time": 1234567890123, + "grading_end_time": 1234567890123 + } + ], + "grading_start_time": 1234567890123, + "grading_end_time": 1234567890123, + "additional-info": null + } + } +} diff --git a/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_epoch_no_allow.json b/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_epoch_no_allow.json new file mode 100644 index 0000000..bb09fd7 --- /dev/null +++ b/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_epoch_no_allow.json @@ -0,0 +1,18 @@ +{ + "module": "autograder.api.courses.assignments.submissions.submit", + "arguments": { + "course": "course-languages", + "assignment": "bash", + "allow-late": false + }, + "files": [ + "__DATA_DIR__(assignment.sh)" + ], + "output-modifier": "clean_output_timestamps", + "output": { + "rejected": true, + "message": "Attempting to submit assignment (A Simple Bash Assignment) late without the 'allow late' option. It was due on (which was ago). Use the 'allow late' option to submit an assignment late. See your interface's documentation for more information.", + "grading-success": false, + "result": null + } +} diff --git a/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_no_compile.json b/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_no_compile.json index 6ace545..d724bd1 100644 --- a/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_no_compile.json +++ b/tests/api/testdata/courses/assignments/submit/courses_assignments_submissions_submit_no_compile.json @@ -1,6 +1,7 @@ { "module": "autograder.api.courses.assignments.submissions.submit", "arguments": { + "allow-late": false }, "files": [ "__DATA_DIR__(hw0_no_compile.py)" diff --git a/tests/cli/test_cli.py b/tests/cli/test_cli.py index a68c197..59d01cf 100644 --- a/tests/cli/test_cli.py +++ b/tests/cli/test_cli.py @@ -24,6 +24,12 @@ TIME_REGEX = r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}' TIME_REPLACEMENT = '