forked from ucbds-infra/otter-grader
/
cell_generators.py
171 lines (126 loc) · 5.47 KB
/
cell_generators.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
"""
Miscellaneous cell generators for Otter Assign
"""
import copy
import nbformat
from .constants import MD_RESPONSE_CELL_SOURCE
from .utils import get_source, lock
def gen_init_cell(nb_name):
"""
Generates a cell to initialize Otter in the notebook. The code cell has the following contents:
.. code-block:: python
# Initialize Otter
import otter
grader = otter.Notebook()
Args:
nb_name (``str``): the name of the notebook being graded
Returns:
``nbformat.NotebookNode``: the init cell
"""
cell = nbformat.v4.new_code_cell(f'# Initialize Otter\nimport otter\ngrader = otter.Notebook("{nb_name}")')
lock(cell)
return cell
def gen_markdown_response_cell():
"""
Generates a Markdown response cell with the following contents:
.. code-block:: markdown
_Type your answer here, replacing this text._
Returns:
``nbformat.NotebookNode``: the response cell
"""
return nbformat.v4.new_markdown_cell(MD_RESPONSE_CELL_SOURCE)
def gen_export_cells(instruction_text, pdf=True, filtering=True, force_save=False):
"""
Generates export cells that instruct the student the run a code cell calling
``otter.Notebook.export`` to generate and download their submission. The Markdown cell contains:
.. code-block:: markdown
## Submission
Make sure you have run all cells in your notebook in order before running the cell below, so
that all images/graphs appear in the output. The cell below will generate a zipfile for you
to submit. **Please save before exporting!**
Additional instructions can be appended to this cell by passing a string to ``instruction_text``.
The code cell contains:
.. code-block:: python
# Save your notebook first, then run this cell to export your submission.
grader.export()
The call to ``grader.export()`` contains different arguments based on the values passed to ``pdf``
and ``filtering``.
Args:
instruction_text (``str``): extra instructions for students when exporting
pdf (``bool``, optional): whether a PDF is needed
filtering (``bool``, optional): whether PDF filtering is needed
force_save (``bool``, optional): whether or not to set the ``force_save`` argument of
``otter.Notebook.export`` to ``True``
Returns:
``list`` of ``nbformat.NotebookNode``: generated export cells
"""
instructions = nbformat.v4.new_markdown_cell()
instructions.source = "## Submission\n\nMake sure you have run all cells in your notebook in order before " \
"running the cell below, so that all images/graphs appear in the output. The cell below will generate " \
"a zip file for you to submit. **Please save before exporting!**"
if instruction_text:
instructions.source += '\n\n' + instruction_text
export = nbformat.v4.new_code_cell()
source_lines = ["# Save your notebook first, then run this cell to export your submission."]
args = []
if not filtering:
args += ["filtering=False"]
elif not pdf:
args += ["pdf=False"]
if force_save:
args += ["force_save=True"]
# if filtering and pdf:
# source_lines.append(f"grader.export()")
# elif not filtering:
# source_lines.append(f"grader.export(filtering=False)")
# else:
# source_lines.append(f"grader.export(pdf=False)")
source_lines.append(f"grader.export({', '.join(args)})")
export.source = "\n".join(source_lines)
lock(instructions)
lock(export)
return [instructions, export, nbformat.v4.new_markdown_cell(" ")] # last cell is buffer
def gen_check_all_cell():
"""
Generates a check-all cell and a Markdown cell with instructions to run all tests in the notebook.
The Markdown cell has the following contents:
.. code-block:: markdown
---
To double-check your work, the cell below will rerun all of the autograder tests.
The code cell has the following contents:
.. code-block:: python
grader.check_all()
Returns:
``list`` of ``nbformat.NotebookNode``: generated check-all cells
"""
instructions = nbformat.v4.new_markdown_cell()
instructions.source = "---\n\nTo double-check your work, the cell below will rerun all of the autograder tests."
check_all = nbformat.v4.new_code_cell("grader.check_all()")
lock(instructions)
lock(check_all)
return [instructions, check_all]
def gen_close_export_cell():
"""
Generates a Markdown cell to end question export for PDF filtering. The cell contains:
.. code-block:: markdown
<!-- END QUESTION -->
Returns:
``nbformat.NotebookNode``: new Markdown cell with ``<!-- END QUESTION -->``
"""
cell = nbformat.v4.new_markdown_cell("<!-- END QUESTION -->")
lock(cell)
return cell
def add_close_export_to_cell(cell):
"""
Adds an HTML comment to close question export for PDF filtering to the top of ``cell``. ``cell``
should be a Markdown cell. This adds ``<!-- END QUESTION-->`` as the first line of the cell.
Args:
cell (``nbformat.NotebookNode``): the cell to add the close export to
Returns:
``nbformat.NotebookNode``: the cell with the close export comment at the top
"""
cell = copy.deepcopy(cell)
source = get_source(cell)
source = ["<!-- END QUESTION -->\n", "\n"] + source
cell['source'] = "\n".join(source)
return cell