def test_average_notebook_score(assignment: Gradebook) -> None: assert assignment.average_notebook_score('p1', 'foo') == 0 assert assignment.average_notebook_code_score('p1', 'foo') == 0 assert assignment.average_notebook_written_score('p1', 'foo') == 0 assignment.add_student('hacker123') assignment.add_student('bitdiddle') assignment.add_submission('foo', 'hacker123') assignment.add_submission('foo', 'bitdiddle') assert assignment.average_notebook_score('p1', 'foo') == 0.0 assert assignment.average_notebook_code_score('p1', 'foo') == 0.0 assert assignment.average_notebook_written_score('p1', 'foo') == 0.0 g1 = assignment.find_grade("test1", "p1", "foo", "hacker123") g2 = assignment.find_grade("test2", "p1", "foo", "hacker123") g3 = assignment.find_grade("test1", "p1", "foo", "bitdiddle") g4 = assignment.find_grade("test2", "p1", "foo", "bitdiddle") g1.manual_score = 0.5 g2.manual_score = 2 g3.manual_score = 1 g4.manual_score = 1 assignment.db.commit() assert assignment.average_notebook_score('p1', 'foo') == 2.25 assert assignment.average_notebook_code_score('p1', 'foo') == 0.75 assert assignment.average_notebook_written_score('p1', 'foo') == 1.5
class GetGrades(NbGraderPreprocessor): """Preprocessor for saving grades from the database to the notebook""" def preprocess(self, nb, resources): # pull information from the resources self.notebook_id = resources['nbgrader']['notebook'] self.assignment_id = resources['nbgrader']['assignment'] self.student_id = resources['nbgrader']['student'] self.db_url = resources['nbgrader']['db_url'] # connect to the database self.gradebook = Gradebook(self.db_url) # process the cells nb, resources = super(GetGrades, self).preprocess(nb, resources) submission = self.gradebook.find_submission_notebook( self.notebook_id, self.assignment_id, self.student_id) resources['nbgrader']['score'] = submission.score resources['nbgrader']['max_score'] = submission.max_score return nb, resources def _get_comment(self, cell, resources): """Graders can optionally add comments to the student's solutions, so add the comment information into the database if it doesn't already exist. It should NOT overwrite existing comments that might have been added by a grader already. """ # retrieve or create the comment object from the database comment = self.gradebook.find_comment( cell.metadata['nbgrader']['grade_id'], self.notebook_id, self.assignment_id, self.student_id) # save it in the notebook cell.metadata.nbgrader['comment'] = comment.comment def _get_score(self, cell, resources): grade = self.gradebook.find_grade( cell.metadata['nbgrader']['grade_id'], self.notebook_id, self.assignment_id, self.student_id) cell.metadata.nbgrader['score'] = grade.score cell.metadata.nbgrader['points'] = grade.max_score def preprocess_cell(self, cell, resources, cell_index): # if it's a solution cell, then add a comment if utils.is_solution(cell): self._get_comment(cell, resources) # if it's a grade cell, the add a grade if utils.is_grade(cell): self._get_score(cell, resources) return cell, resources
class SaveAutoGrades(NbGraderPreprocessor): """Preprocessor for saving out the autograder grades into a database""" def preprocess(self, nb, resources): # pull information from the resources self.notebook_id = resources['nbgrader']['notebook'] self.assignment_id = resources['nbgrader']['assignment'] self.student_id = resources['nbgrader']['student'] self.db_url = resources['nbgrader']['db_url'] # connect to the database self.gradebook = Gradebook(self.db_url) # process the cells nb, resources = super(SaveAutoGrades, self).preprocess(nb, resources) return nb, resources def _add_score(self, cell, resources): """Graders can override the autograder grades, and may need to manually grade written solutions anyway. This function adds score information to the database if it doesn't exist. It does NOT override the 'score' field, as this is the manual score that might have been provided by a grader. """ # these are the fields by which we will identify the score # information grade = self.gradebook.find_grade( cell.metadata['nbgrader']['grade_id'], self.notebook_id, self.assignment_id, self.student_id) # determine what the grade is auto_score, _ = utils.determine_grade(cell) grade.auto_score = auto_score # if there was previously a manual grade, or if there is no autograder # score, then we should mark this as needing review if (grade.manual_score is not None) or (grade.auto_score is None): grade.needs_manual_grade = True else: grade.needs_manual_grade = False self.gradebook.db.commit() self.log.debug(grade) def _add_comment(self, cell, resources): comment = self.gradebook.find_comment( cell.metadata['nbgrader']['grade_id'], self.notebook_id, self.assignment_id, self.student_id) if cell.metadata.nbgrader.get("checksum", None) == utils.compute_checksum(cell): comment.auto_comment = "No response." else: comment.auto_comment = None self.gradebook.db.commit() self.log.debug(comment) def preprocess_cell(self, cell, resources, cell_index): # if it's a grade cell, the add a grade if utils.is_grade(cell): self._add_score(cell, resources) if utils.is_solution(cell): self._add_comment(cell, resources) return cell, resources
class TestSaveAutoGrades(TestBase): def setup(self): super(TestSaveAutoGrades, self).setup() db_url = self._init_db() self.gb = Gradebook(db_url) self.gb.add_assignment("ps0") self.gb.add_student("bar") self.preprocessor1 = SaveCells() self.preprocessor2 = SaveAutoGrades() self.resources = { "nbgrader": { "db_url": db_url, "assignment": "ps0", "notebook": "test", "student": "bar" } } def test_grade_correct_code(self): """Is a passing code cell correctly graded?""" cell = self._create_grade_cell("hello", "code", "foo", 1) nb = new_notebook() nb.cells.append(cell) self.preprocessor1.preprocess(nb, self.resources) self.gb.add_submission("ps0", "bar") self.preprocessor2.preprocess(nb, self.resources) grade_cell = self.gb.find_grade("foo", "test", "ps0", "bar") assert_equal(grade_cell.score, 1) assert_equal(grade_cell.max_score, 1) assert_equal(grade_cell.auto_score, 1) assert_equal(grade_cell.manual_score, None) assert not grade_cell.needs_manual_grade def test_grade_incorrect_code(self): """Is a failing code cell correctly graded?""" cell = self._create_grade_cell("hello", "code", "foo", 1) cell.outputs = [new_output('error', ename="NotImplementedError", evalue="", traceback=["error"])] nb = new_notebook() nb.cells.append(cell) self.preprocessor1.preprocess(nb, self.resources) self.gb.add_submission("ps0", "bar") self.preprocessor2.preprocess(nb, self.resources) grade_cell = self.gb.find_grade("foo", "test", "ps0", "bar") assert_equal(grade_cell.score, 0) assert_equal(grade_cell.max_score, 1) assert_equal(grade_cell.auto_score, 0) assert_equal(grade_cell.manual_score, None) assert not grade_cell.needs_manual_grade def test_grade_unchanged_markdown(self): """Is an unchanged markdown cell correctly graded?""" cell = self._create_grade_and_solution_cell("hello", "markdown", "foo", 1) nb = new_notebook() nb.cells.append(cell) self.preprocessor1.preprocess(nb, self.resources) self.gb.add_submission("ps0", "bar") self.preprocessor2.preprocess(nb, self.resources) grade_cell = self.gb.find_grade("foo", "test", "ps0", "bar") assert_equal(grade_cell.score, 0) assert_equal(grade_cell.max_score, 1) assert_equal(grade_cell.auto_score, 0) assert_equal(grade_cell.manual_score, None) assert not grade_cell.needs_manual_grade def test_grade_changed_markdown(self): """Is a changed markdown cell correctly graded?""" cell = self._create_grade_and_solution_cell("hello", "markdown", "foo", 1) nb = new_notebook() nb.cells.append(cell) self.preprocessor1.preprocess(nb, self.resources) self.gb.add_submission("ps0", "bar") cell.source = "hello!" self.preprocessor2.preprocess(nb, self.resources) grade_cell = self.gb.find_grade("foo", "test", "ps0", "bar") assert_equal(grade_cell.score, 0) assert_equal(grade_cell.max_score, 1) assert_equal(grade_cell.auto_score, None) assert_equal(grade_cell.manual_score, None) assert grade_cell.needs_manual_grade def test_comment_unchanged_code(self): """Is an unchanged code cell given the correct comment?""" cell = self._create_solution_cell("hello", "code") nb = new_notebook() nb.cells.append(cell) self.preprocessor1.preprocess(nb, self.resources) self.gb.add_submission("ps0", "bar") self.preprocessor2.preprocess(nb, self.resources) comment = self.gb.find_comment(0, "test", "ps0", "bar") assert_equal(comment.comment, "No response.") def test_comment_changed_code(self): """Is a changed code cell given the correct comment?""" cell = self._create_solution_cell("hello", "code") nb = new_notebook() nb.cells.append(cell) self.preprocessor1.preprocess(nb, self.resources) self.gb.add_submission("ps0", "bar") cell.source = "hello!" self.preprocessor2.preprocess(nb, self.resources) comment = self.gb.find_comment(0, "test", "ps0", "bar") assert_equal(comment.comment, None) def test_comment_unchanged_markdown(self): """Is an unchanged markdown cell given the correct comment?""" cell = self._create_grade_and_solution_cell("hello", "markdown", "foo", 1) nb = new_notebook() nb.cells.append(cell) self.preprocessor1.preprocess(nb, self.resources) self.gb.add_submission("ps0", "bar") self.preprocessor2.preprocess(nb, self.resources) comment = self.gb.find_comment(0, "test", "ps0", "bar") assert_equal(comment.comment, "No response.") def test_comment_changed_markdown(self): """Is a changed markdown cell given the correct comment?""" cell = self._create_grade_and_solution_cell("hello", "markdown", "foo", 1) nb = new_notebook() nb.cells.append(cell) self.preprocessor1.preprocess(nb, self.resources) self.gb.add_submission("ps0", "bar") cell.source = "hello!" self.preprocessor2.preprocess(nb, self.resources) comment = self.gb.find_comment(0, "test", "ps0", "bar") assert_equal(comment.comment, None)
class GetGrades(NbGraderPreprocessor): """Preprocessor for saving grades from the database to the notebook""" def preprocess(self, nb, resources): # pull information from the resources self.notebook_id = resources['nbgrader']['notebook'] self.assignment_id = resources['nbgrader']['assignment'] self.student_id = resources['nbgrader']['student'] self.db_url = resources['nbgrader']['db_url'] # connect to the database self.gradebook = Gradebook(self.db_url) self.comment_index = 0 # process the cells nb, resources = super(GetGrades, self).preprocess(nb, resources) submission = self.gradebook.find_submission_notebook( self.notebook_id, self.assignment_id, self.student_id) resources['nbgrader']['score'] = submission.score resources['nbgrader']['max_score'] = submission.max_score return nb, resources def _get_comment(self, cell, resources): """Graders can optionally add comments to the student's solutions, so add the comment information into the database if it doesn't already exist. It should NOT overwrite existing comments that might have been added by a grader already. """ # retrieve or create the comment object from the database comment = self.gradebook.find_comment( self.comment_index, self.notebook_id, self.assignment_id, self.student_id) # save it in the notebook cell.metadata.nbgrader['comment'] = comment.to_dict() # update the number of comments we have inserted self.comment_index += 1 def _get_score(self, cell, resources): grade = self.gradebook.find_grade( cell.metadata['nbgrader']['grade_id'], self.notebook_id, self.assignment_id, self.student_id) cell.metadata.nbgrader['score'] = grade.score cell.metadata.nbgrader['points'] = grade.max_score def preprocess_cell(self, cell, resources, cell_index): # if it's a solution cell, then add a comment if utils.is_solution(cell): self._get_comment(cell, resources) # if it's a grade cell, the add a grade if utils.is_grade(cell): self._get_score(cell, resources) return cell, resources
class SaveAutoGrades(NbGraderPreprocessor): """Preprocessor for saving out the autograder grades into a database""" def preprocess(self, nb, resources): # pull information from the resources self.notebook_id = resources['nbgrader']['notebook'] self.assignment_id = resources['nbgrader']['assignment'] self.student_id = resources['nbgrader']['student'] self.db_url = resources['nbgrader']['db_url'] # connect to the database self.gradebook = Gradebook(self.db_url) self.comment_index = 0 # process the cells nb, resources = super(SaveAutoGrades, self).preprocess(nb, resources) return nb, resources def _add_score(self, cell, resources): """Graders can override the autograder grades, and may need to manually grade written solutions anyway. This function adds score information to the database if it doesn't exist. It does NOT override the 'score' field, as this is the manual score that might have been provided by a grader. """ # these are the fields by which we will identify the score # information grade = self.gradebook.find_grade( cell.metadata['nbgrader']['grade_id'], self.notebook_id, self.assignment_id, self.student_id) # determine what the grade is auto_score, max_score = utils.determine_grade(cell) grade.auto_score = auto_score self.gradebook.db.commit() self.log.debug(grade) def _add_comment(self, cell, resources): comment = self.gradebook.find_comment( self.comment_index, self.notebook_id, self.assignment_id, self.student_id) if comment.comment: return elif cell.metadata.nbgrader.get("checksum", None) == utils.compute_checksum(cell): comment.comment = "No response." self.gradebook.db.commit() self.log.debug(comment) def preprocess_cell(self, cell, resources, cell_index): # if it's a grade cell, the add a grade if utils.is_grade(cell): self._add_score(cell, resources) if utils.is_solution(cell): self._add_comment(cell, resources) self.comment_index += 1 return cell, resources