Coverage for e2xgrader/server_extensions/apps/validate_assignment/validator.py: 77%

30 statements  

« prev     ^ index     » next       coverage.py v7.4.2, created at 2024-03-14 13:22 +0100

1from typing import List, Union 

2 

3from nbformat.notebooknode import NotebookNode 

4from nbgrader import utils 

5from nbgrader.validator import Validator 

6 

7from ....utils.extra_cells import ( 

8 get_choices, 

9 is_attachment_cell, 

10 is_extra_cell, 

11 is_multiplechoice, 

12 is_singlechoice, 

13) 

14 

15 

16class E2XValidator(Validator): 

17 def validate_extra_cell(self, cell: NotebookNode) -> Union[None, float]: 

18 if ( 

19 (is_multiplechoice(cell) or is_singlechoice(cell)) 

20 and len(get_choices(cell)) < 1 

21 ) or (is_attachment_cell(cell) and len(cell.get("attachments", {})) < 1): 

22 return 0 

23 

24 def code_cell_errored(self, cell: NotebookNode) -> bool: 

25 for output in cell.outputs: 

26 if ( 

27 output.output_type == "error" 

28 or output.output_type == "stream" 

29 and output.name == "stderr" 

30 ): 

31 return True 

32 return False 

33 

34 def _get_failed_cells(self, nb: NotebookNode) -> List[NotebookNode]: 

35 failed = [] 

36 for cell in nb.cells: 

37 if self._should_skip_cell(cell): 

38 continue 

39 

40 # if it's a grade cell, the check the grade 

41 if utils.is_grade(cell): 

42 score, max_score = utils.determine_grade(cell, self.log) 

43 

44 if is_extra_cell(cell): 

45 score = self.validate_extra_cell(cell) 

46 

47 # it's a markdown cell, so we can't do anything 

48 if score is not None and score < max_score: 

49 failed.append(cell) 

50 elif ( 

51 self.validate_all 

52 and cell.cell_type == "code" 

53 and self.code_cell_errored(cell) 

54 ): 

55 failed.append(cell) 

56 

57 return failed 

58 

59 def _should_skip_cell(self, cell: NotebookNode) -> bool: 

60 return not (self.validate_all or utils.is_grade(cell) or utils.is_locked(cell))