diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 6d0fdef..c74882a 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -29,9 +29,12 @@ jobs: - name: Setup pixi uses: prefix-dev/setup-pixi@19eac09b398e3d0c747adc7921926a6d802df4da # v0.8.8 - - name: Build executed notebooks and HTML + - name: Build HTML run: pixi run build + - name: Build jupyterlite + run: pixi run build_wasm + - name: Upload executed notebooks as GitHub artifact (for debugging) uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8587102..edf8496 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,3 +100,15 @@ jobs: - name: Build static site run: pixi run build + + pixi_build_wasm: + name: Build jupyterlite site with pixi + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup pixi + uses: prefix-dev/setup-pixi@v0.8.1 + + - name: Build jupyterlite site + run: pixi run build_wasm diff --git a/.gitignore b/.gitignore index 6154ca0..c866267 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ _build/* # No .ipynb files should be stored in this repository. *.ipynb +# Jupyterlite Database +.jupyterlite.doit.db + # We treat this repository as a library, not an application, and thus we do not # include the lockfile in source control. For a specific event, like a # workshop, we suggest committing the lockfile on a branch dedicated to the diff --git a/activate.sh b/activate.sh new file mode 100644 index 0000000..eb3c39a --- /dev/null +++ b/activate.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -eux + +mkdir -p ${CONDA_PREFIX}/share/jupyter/lab/settings +cp ${PIXI_PROJECT_ROOT}/.binder/overrides.json ${CONDA_PREFIX}/share/jupyter/lab/settings/overrides.json diff --git a/convert_all_jupyterlite.sh b/convert_all_jupyterlite.sh new file mode 100755 index 0000000..12e8ff2 --- /dev/null +++ b/convert_all_jupyterlite.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# This is a script which copies the contents of the tutorials +# directory into a build directory (_build/ipynbs). +# The notebook markdown files are converted to ipynbs with other +# files (non-executable md files, static images, etc) are copied +# directly. +# This is intended for jupyterlite to build pointing to the build +# directory since the markdown files do not currently work in +# jupyterlite. + +# Find Markdown files convert. +files_to_process=$(find tutorials -type f) + +OUTDIR="_build/ipynbs" + +# Identify Markdown files that are Jupytext and convert them all. +for file in ${files_to_process}; do + # Ensure result directory exists + echo "Making directory: $OUTDIR/$(dirname $file)" + mkdir -p $OUTDIR/$(dirname $file) + + echo loop in $file + # Extract the kernel information from the Jupytext Markdown file. + kernel_info=$(grep -A 10 '^---$' "$file" | grep -E 'kernelspec') + # Copy directly if not a notebook file + if [ -z "$kernel_info" ]; then + cp $file $OUTDIR/$file + continue + fi + # Convert to ipynb format, to be consumed by pytest nbval plugin. + notebook_file="${file%.md}.ipynb" + jupytext --to ipynb "$file" --output $OUTDIR/${notebook_file} +done diff --git a/pixi.toml b/pixi.toml index 528ef42..c7afd6d 100644 --- a/pixi.toml +++ b/pixi.toml @@ -5,13 +5,16 @@ authors = [ "Ross Barnowski ", "Kyle Sunden ", ] -channels = ["conda-forge"] +channels = ["https://repo.mamba.pm/emscripten-forge", "conda-forge"] description = "Add a short description here" name = "executable-tutorials" -platforms = ["linux-64", "osx-64", "osx-arm64", "win-64"] +platforms = ["linux-64", "osx-64", "osx-arm64", "win-64", "emscripten-wasm32"] version = "0.1.0" -[tasks] +[feature.base] +platforms = ["linux-64", "osx-64", "osx-arm64", "win-64"] + +[feature.base.tasks] build = { cmd = [ "sphinx-build", ".", # source directory @@ -25,22 +28,23 @@ clean = "rm -rf _build/*" start = "jupyter lab --FileContentsManager.preferred_dir tutorials" test = "bash ./test.sh" -[activation] +[feature.base.activation] # Workaround overrides JupyterLab configuration (at the environment level) to # make double-clicking on a Jupytext Markdown file open that file as a # notebook. This is important for the development workflow for contributors. -scripts = ["bash .binder/postBuild"] +scripts = ["activate.sh"] -[dependencies] +[feature.base.dependencies] python = ">=3.11" matplotlib-base = ">=3.9" -ipympl = ">=0.9" jupyterlab = ">=4.2" jupyterlab-myst = ">=2.4" pytest = ">=8.3.5,<9" nbval = ">=0.11.0,<0.12" +jupytext = ">=1.17.1,<2" +ipympl = ">=0.9" -[pypi-dependencies] +[feature.base.pypi-dependencies] sphinx = ">=8.0.2" myst-nb = ">=1.1" jupytext = ">=1.16" @@ -49,19 +53,59 @@ sphinx-copybutton = ">=0.5" sphinx-design = "*" pytest-custom_exit_code = "*" +[feature.py312] +platforms = ["linux-64", "osx-64", "osx-arm64", "win-64"] + [feature.py312.dependencies] python = "3.12.*" +[feature.py313] +platforms = ["linux-64", "osx-64", "osx-arm64", "win-64"] + [feature.py313.dependencies] python = "3.13.*" -[feature.jupyterlite.dependencies] +[feature.jupyterlite-runtime] +channels = ["https://repo.mamba.pm/emscripten-forge", "conda-forge"] +platforms = ["emscripten-wasm32"] + +[feature.jupyterlite-runtime.dependencies] +xeus-python = "*" +python = ">=3.11" +matplotlib = ">=3.9" +ipympl = ">=0.9" +jupytext = ">=1.16" + +[feature.jupyterlite-host] +channels = ["conda-forge"] +platforms = ["linux-64", "osx-64", "osx-arm64", "win-64"] + +[feature.jupyterlite-host.dependencies] jupyterlab = "~=4.2.4" jupyterlite-core = "==0.4.0" -jupyterlite-pyodide-kernel = "==0.4.1" +jupyterlite-xeus = "*" notebook = "~=7.2.1" +jupyterlab-myst = ">=2.4" +jupytext = ">=1.16" +ipympl = ">=0.9" + +[feature.jupyterlite-host.tasks] +setup_wasm = {cmd = "pixi install -e jupyterlite-runtime", inputs = ["pixi.lock"]} +convert_ipynbs = {cmd = "bash convert_all_jupyterlite.sh", inputs = ["tutorials/"], outputs = ["_build/ipynbs"]} + +[feature.jupyterlite-host.tasks.build_wasm] +cmd = "jupyter lite build --XeusAddon.prefix=.pixi/envs/jupyterlite-runtime --contents _build/ipynbs/tutorials --output-dir _build/html/jupyterlite --settings-overrides=.binder/overrides.json --log-level DEBUG" +depends-on = ["setup_wasm", "convert_ipynbs"] +outputs = ["_build/html/jupyterlite/"] +inputs = ["pixi.lock", "tutorials/"] + +[feature.jupyterlite-host.tasks.start_wasm] +cmd = "python -m http.server 8000 -d _build/html/jupyterlite/" +depends-on = ["build_wasm"] [environments] -py312 = ["py312"] -py313 = ["py313"] -jupyterlite = ["jupyterlite"] +default = ["base"] +py312 = ["base", "py312"] +py313 = ["base", "py313"] +jupyterlite-runtime = ["jupyterlite-runtime"] +jupyterlite-host = ["jupyterlite-host"]