C2SM / pyvis

GNU General Public License v3.0
27 stars 12 forks source link

use preprocessor to strip solutions #79

Open mathause opened 1 year ago

mathause commented 1 year ago

For the python intro course I found a nice preprocessor which can strip notebook cells that contain a certain string (e.g. # solution). This could be used to have notebooks with and without solutions. Might need some changes to the structure of the project.

https://git.iac.ethz.ch/ip_python/ip_python/-/blob/main/intro/strip_solutions

Code under details.

``` #!/bin/bash for f in code_with_solutions/*.ipynb; do [[ -e $f ]] || continue f=$(basename ${f}) fN_i=code_with_solutions/${f} # need a relative path fN_o=code/${f} if [[ ${fN_i} -nt ${fN_o} ]]; then # remove all cells that contain "# solution" jupyter nbconvert \ --to notebook \ --ClearOutputPreprocessor.enabled=True \ --RegexRemovePreprocessor.enabled=True \ --RegexRemovePreprocessor.patterns="['# solution.*']" \ ${fN_i} \ --output ../${fN_o} else echo "skipping ${fN_i}" fi done ```
mathause commented 1 year ago

Unfortunately there seems to be no official way to add a cell (at least I found nothing). But the following python snippet should work:

import nbformat
import nbformat.notebooknode
from nbconvert import NotebookExporter

from traitlets.config import Config

fN_in = "code_with_solution.ipynb"
fN_out = "code.ipynb"

fN_in = "code_with_solutions/1.1_numpy_intro.ipynb"

# =====

# create preprocessors
c = Config()
c.NotebookExporter.preprocessors = [
  'nbconvert.preprocessors.ClearOutputPreprocessor',
  'nbconvert.preprocessors.RegexRemovePreprocessor',
]

c.RegexRemovePreprocessor.patterns='# solution.*'

notebook_exporter = NotebookExporter(config=c)

new_cell = {
    'cell_type': 'markdown',
    'metadata': {},
    'source': f'> Notebook auto-generated from _`{fN_in}`_'
}

node = nbformat.notebooknode.from_dict(new_cell)

notebook = notebook = nbformat.read(fN_in, as_version=4)

# add the id to the new cell
notebook.cells = [node] + notebook.cells

__, notebook = nbformat.validator.normalize(notebook)

(body, resources) = notebook_exporter.from_notebook_node(notebook)

with open(fN_out, "w") as f:
    f.writelines(body)

NOTE: RegexRemovePreprocessor needs to be added as well, see https://nbconvert.readthedocs.io/en/latest/nbconvert_library.html#Using-different-preprocessors

EDIT: now with the preprocessors