Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strip tagged cells from .ipynb notebooks passed to the NotebookLite and JupyterLite directives #180

Merged
merged 15 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

jupyterlite_contents = "./custom_contents"
jupyterlite_bind_ipynb_suffix = False
strip_tagged_cells = True

master_doc = "index"

Expand Down
66 changes: 66 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,72 @@ to your JupyterLite deployment.
jupyterlite_config = "jupyterlite_config.json"
```

## Strip particular tagged cells from IPython Notebooks

When using the `NotebookLite`, `JupyterLite`, or `Voici` directives with a notebook passed to them, you can
strip particular tagged cells from the notebook before rendering it in the JupyterLite console.

This behaviour can be enabled by setting the following config:

```python
strip_tagged_cells = True
```

and then by tagging the cells you want to strip with the tag `jupyterlite_sphinx_strip` in the JSON metadata
of the cell, like this:

```json
{
"tags": [
"jupyterlite_sphinx_strip": "true"
]
}
```

This is useful when you want to remove some cells from the rendered notebook in the JupyterLite
console, for example, cells that are used for adding reST-based directives or other
Sphinx-specific content.

For example, you can use this feature to remove the `toctree` directive from the rendered notebook
in the JupyterLite console:

```json
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"tags": [
"jupyterlite_sphinx_strip": "true"
]
},
"source": [
"# Table of Contents\n",
"\n",
"```{toctree}\n",
":maxdepth: 2\n",
"\n",
"directives/jupyterlite\n",
"directives/notebooklite\n",
"directives/replite\n",
"directives/voici\n",
"directives/try_examples\n",
"full\n",
"changelog\n",
"```"
]
}
]
}
```

where the cell with the `toctree` directive will be removed from the rendered notebook in
the JupyterLite console.

Note that this feature is only available for the `NotebookLite`, `JupyterLite`, and the
`Voici` directives and works with the `.ipynb` files passed to them. It is not implemented
for the `TryExamples` directive.

## Disable the `.ipynb` docs source binding

By default, jupyterlite-sphinx binds the `.ipynb` source suffix so that it renders Notebooks included in the doctree with JupyterLite.
Expand Down
33 changes: 28 additions & 5 deletions jupyterlite_sphinx/jupyterlite_sphinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

from ._try_examples import examples_to_notebook, insert_try_examples_directive

import nbformat

try:
import voici
except ImportError:
Expand Down Expand Up @@ -338,12 +340,32 @@ def run(self):

notebooks_dir = Path(self.env.app.srcdir) / CONTENT_DIR / notebook_name

# Copy the Notebook for NotebookLite to find
notebook_is_stripped: bool = self.env.config.strip_tagged_cells

# Create a folder to copy the notebooks to and for NotebookLite to find
os.makedirs(os.path.dirname(notebooks_dir), exist_ok=True)
try:
shutil.copyfile(notebook, str(notebooks_dir))
except shutil.SameFileError:
pass

if notebook_is_stripped:
# Note: the directives meant to be stripped must be inside their own
# cell so that the cell itself gets removed from the notebook. This
# is so that we don't end up removing useful data or directives that
# are not meant to be removed.

agriyakhetarpal marked this conversation as resolved.
Show resolved Hide resolved
nb = nbformat.read(notebook, as_version=4)
print(f"Opened {notebook_name}")
nb = nbformat.read(notebook, as_version=4)
nb.cells = [
cell
for cell in nb.cells
if "true" not in cell.metadata.get("strip", [])
]
nbformat.write(nb, notebooks_dir, version=4)

# If notebook_is_stripped is False, then copy the notebook(s) to notebooks_dir.
# If it is True, then they have already been copied to notebooks_dir by the
# nbformat.write() function above.
else:
shutil.copy(notebook, notebooks_dir)
else:
notebook_name = None

Expand Down Expand Up @@ -749,6 +771,7 @@ def setup(app):
app.add_config_value("jupyterlite_contents", None, rebuild="html")
app.add_config_value("jupyterlite_bind_ipynb_suffix", True, rebuild="html")
app.add_config_value("jupyterlite_silence", True, rebuild=True)
app.add_config_value("strip_tagged_cells", False, rebuild=True)

# Pass a dictionary of additional options to the JupyterLite build command
app.add_config_value("jupyterlite_build_command_options", None, rebuild="html")
Expand Down
Loading