Execute Notebooks at Build Time
Generate figures and other rich content using Jupyter kernels
The MyST CLI can execute your notebooks and markdown files by passing the --execute
flag to the start
and build
commands, i.e.:
myst start --execute
myst build --execute
The following computational content will be executed:
- Notebook cells will be executed in the order they appeared in a notebook (ie, a file ending in
.ipynb
). {code-block}
directives will be executed similar to a code block cell. See Executable Markdown Files for more information.- Inline expressions with the
{eval}
role can be used to insert the outputs of a computation in-line with other text.
Expect a code-cell to fail¶
By default, MyST will stop executing a notebook if a cell raises an error.
If instead you’d like MyST to continue executing subsequent cells (e.g., in order to demonstrate an expected error message), add the raises-exception
tag to the cell.
If a cell with this tag raises an error, then the error is provided with the cell output, and MyST will continue executing the rest of the cells in a notebook.
The easiest way to add cell tags is via the JupyterLab interface.
Additionally, you can specify tags (and other cell metadata) with markdown using the {code-cell}
directive.
Here’s an example of adding this tag with a {code-cell}
directive:
```{code-cell}
:tags: raises-exception
print("Hello" + 10001)
```
Skip particular code-cells¶
Sometimes, you might have a notebook containing code that you don’t want to execute. For example, you might have code-cells that prompt the user for input, which should be skipped during a website build. MyST understands the same skip-execution
cell-tag that other Jupyter Notebook tools (such as Jupyter Book) use to prevent a cell from being executed.
For Markdown notebooks using the {code-cell}
directive, the skip-execution
tag can be added as follows:
```{code-cell}
:tags: skip-execution
name = input("What is your name?")
```
Cache execution outputs¶
When MyST executes your notebook, it will store the outputs in a cache in a folder called execute/
in your MyST build folder.
On subsequent builds, MyST will re-use this cache rather than re-execute.
If you change the computational content of a notebook or a markdown page (ie, code in a code cell, or in an inline expression), then this cache will be reset and the code will be re-executed at the next build.
Force execution by deleting the cache¶
If you’d like to force re-execution of all the code in your MyST documents, use the following command:
myst clean --execute
Alternatively, you can manually delete the execute/
folder in your build folder, e.g.:
rm -rf _build/execute
How MyST executes your code¶
MyST uses a Jupyter Server to execute your code. Jupyter Server is distributed as a Python package, which can be installed from PyPI or conda-forge, e.g.
pip install jupyter-server
Jupyter Server is only responsible for orchestrating execution of your code. To actually perform execution, you must also install a kernel. For Python, this might be ipykernel
, e.g.
pip install ipykernel
If Jupyter Server is installed and the --execute
flag is passed to myst start
or myst build
, then MyST will attempt to find a healthy existing Jupyter Server. Internally, this is performed using python -m jupyter_server list
. If no existing servers are found, then MyST will attempt to launch one using python -m jupyter_server
.
Manually launch a Jupyter server¶
You can manually launch a Jupyter server and instruct MyST to use it for computation (rather than having MyST start its own Jupyter server). This gives you more control over the process that executes your content, including specifying Jupyter servers that exist on non-local hardware (e.g. running in the cloud).
To manually specify a server, you must set two variables:
JUPYTER_BASE_URL
: a URL where the server can be found. On a local machine, this is by defaulthttp://localhost:8888
.JUPYTER_TOKEN
: the token that allows access to the Jupyter server.
For example, the following code sets these variables, then starts a Jupyter server with them so that MyST will use them to execute code:
# Set the port for our local Jupyter process
port="8888"
# Define environment variables that will be used by MyST
# We'll use the values of these variables in our Jupyter server as well.
export JUPYTER_BASE_URL="http://localhost:${port}"
export JUPYTER_TOKEN="my-jupyter-token"
# Start the Jupyter server re-using the variables above
jupyter server --IdentityProvider.token="${JUPYTER_TOKEN}" --ServerApp.port="${port}" &
# Run the MyST build
# It will use the JUPYTER_* variables above to look for the server.
myst build --execute
# Stop the Jupyter server!
kill %1