Source code for grader_convert.preprocessors.overwritecells



from typing import Any, Tuple

from nbconvert.exporters.exporter import ResourcesDict
from nbformat.notebooknode import NotebookNode
from nbformat.v4.nbbase import validate

from grader_convert.gradebook.gradebook import Gradebook, MissingEntry
from grader_convert import utils
from grader_convert.preprocessors.base import NbGraderPreprocessor

[docs]class OverwriteCells(NbGraderPreprocessor): """A preprocessor to overwrite information about grade and solution cells."""
[docs] def preprocess( self, nb: NotebookNode, resources: ResourcesDict ) -> Tuple[NotebookNode, ResourcesDict]: # pull information from the resources self.notebook_id = resources["unique_key"] self.json_path = resources["output_json_path"] self.gradebook = Gradebook(self.json_path) with self.gradebook: nb, resources = super(OverwriteCells, self).preprocess(nb, resources) return nb, resources
[docs] def update_cell_type(self, cell: NotebookNode, cell_type: str) -> None: if cell.cell_type == cell_type: return elif cell_type == "code": cell.cell_type = "code" cell.outputs = [] cell.execution_count = None validate(cell, "code_cell") elif cell_type == "markdown": cell.cell_type = "markdown" if "outputs" in cell: del cell["outputs"] if "execution_count" in cell: del cell["execution_count"] validate(cell, "markdown_cell")
[docs] def report_change(self, name: str, attr: str, old: Any, new: Any) -> None: self.log.warning( "Attribute '%s' for cell %s has changed! (should be: %s, got: %s)", attr, name, old, new, )
[docs] def preprocess_cell( self, cell: NotebookNode, resources: ResourcesDict, cell_index: int ) -> Tuple[NotebookNode, ResourcesDict]: grade_id = cell.metadata.get("nbgrader", {}).get("grade_id", None) if grade_id is None: return cell, resources try: source_cell = self.gradebook.find_source_cell(grade_id, self.notebook_id) except MissingEntry: self.log.warning( "Cell '{}' does not exist in the database".format(grade_id) ) del cell.metadata.nbgrader["grade_id"] return cell, resources # check that the cell type hasn't changed if cell.cell_type != source_cell.cell_type: self.report_change( grade_id, "cell_type", source_cell.cell_type, cell.cell_type ) self.update_cell_type(cell, source_cell.cell_type) # check that the locked status hasn't changed if utils.is_locked(cell) != source_cell.locked: self.report_change( grade_id, "locked", source_cell.locked, utils.is_locked(cell) ) cell.metadata.nbgrader["locked"] = source_cell.locked # if it's a grade cell, check that the max score hasn't changed if utils.is_grade(cell): grade_cell = self.gradebook.find_graded_cell(grade_id, self.notebook_id) old_points = float(grade_cell.max_score) new_points = float(cell.metadata.nbgrader["points"]) if old_points != new_points: self.report_change(grade_id, "points", old_points, new_points) cell.metadata.nbgrader["points"] = old_points # always update the checksum, just in case cell.metadata.nbgrader["checksum"] = source_cell.checksum # if it's locked, check that the checksum hasn't changed if source_cell.locked: old_checksum = source_cell.checksum new_checksum = utils.compute_checksum(cell) if old_checksum != new_checksum: self.report_change(grade_id, "checksum", old_checksum, new_checksum) cell.source = source_cell.source # double check the the checksum is correct now if utils.compute_checksum(cell) != source_cell.checksum: raise RuntimeError( "Inconsistent checksums for cell {}".format(source_cell.name) ) return cell, resources