🕹️ Try the demo
jupyterlite-pyodide-lock#
Build reproducible Jupyter Lite sites with jupyterlite-pyodide-kernel and pyodide-lock.
View the full documentation on ReadTheDocs.
Overview#
jupyterlite-pyodide-lock
avoids run time pyodide
and jupyterlite
package
management ambiguity by using a full web browser at build time to customize a
pyodide-lock.json
.
Examples#
Use jupyterlite-pyodide-lock
to minimally provide a more
controlled baseline pyodide
runtime environment, or ensure complex dependencies like
widgets are consistent over time.
Minimal Example#
Ensure pyodide-kernel
's dependencies are locked, assuming
pip
and firefox
.
Create the Minimal Build Environment#
make a
requirements.txt
jupyterlite-core ==0.5.1 jupyterlite-pyodide-kernel ==0.5.2 jupyterlite-pyodide-lock ==0.1.2
Run:
pip install -r requirements.txt
Configure the Minimal Site#
build a
jupyter_lite_config.json
:{ "PyodideLockAddon": { "enabled": true } }
Build the Minimal Site#
build a
jupyter_lite_config.json
:jupyter lite build
Check the Minimal Site Works#
start a simple, local development server
cd _output python -m http.server -b 127.0.0.1
visit the site at
http://127.0.0.1:8000/
make a new Notebook
use basic
python
features
Widgets Example#
Build a JupyterLite site with all the packages needed to run
ipywidgets
in a Notebook, assuming mamba
.
Create the Widget Build Environment#
make an
environment.yml
channels: - conda-forge - nodefaults dependencies: - ipywidgets ==8.1.5 - jupyterlite-core ==0.5.1 - jupyterlite-pyodide-kernel ==0.5.2 - jupyterlite-pyodide-lock-recommended ==0.1.2
the
-recommended
package includesfirefox
andgeckodriver
optionally use a tool like
conda-lock
orpixi
to create a lockfile for the build environment
Run:
mamba env update --file environment.yml --prefix .venv source activate .venv # or just `activate .venv` on windows
Configure the Widgets Site#
build a
jupyter_lite_config.json
:{ "PyodideLockAddon": { "enabled": true, "constraints": ["traitlets ==5.14.3"], "specs": ["ipywidgets ==8.1.5"], "extra_preload_packages": ["ipywidgets"], "bootstrap_wheels": [ "https://files.pythonhosted.org/packages/py3/m/micropip/micropip-0.9.0-py3-none-any.whl" ] }, "PyodideLockOfflineAddon": { "enabled": true } }
note the tight
ipywidgets
pin, ensuring compatibility with the build environmentwhile not required, the
constraints
option allows for controlling transient dependenciesthis feature requires
micropip >=0.9.0
, which is only compatible withpyodide >=0.27
Build the Site with Widgets#
build a
jupyter_lite_config.json
:jupyter lite build
Check Widgets Works Offline#
disconnect from the internet ✈️
this step is optional, but is the most reliable way to validate a reproducible site
start a simple, local development server
cd _output python -m http.server -b 127.0.0.1
visit the site at
http://127.0.0.1:8000/
make a new Notebook
see that
ipywidgets
can be imported, and widgets work:import ipywidgets ipywidgets.FloatSlider()
Motivation#
By default, a
pyodide
distribution provides a precise set of hundreds of package versions known to work together in the browser, described in itspyodide-lock.json
.Among these packages is
micropip
, which gives site users the ability to install packages not included inpyodide-lock.json
. These may be served along with an HTML page, downloaded from PyPI, or anywhere on the internet.jupyterlite-pyodide-kernel
uses this capability to install itself, and its dependencies.At run time,
piplite
provides amicropip
-based shim for the IPython%pip
magic, the most portable approach for interactive package management in Notebook documents.
micropip
(and%pip
) are powerful for interactive usage, but can cause headaches when upstream versions (or their dependencies) change in ways that either no longer provide the same API expected by the exact versions ofpyodide
,pyodide-kernel
, and JupyterLab extensions in a deployed JupyterLite site.
jupyterlite-pyodide-lock
gives content authors tools to manage their effective
pyodide
distribution, making it easier to build, verify, and maintain predictable,
interactive computing environments for future site visitors.
Why Use This?#
in the browser
fetches
pyodide-kernel
, its dependencies, and configured packages in parallel whilepyodide
is starting, skippingmicropip.install
and its requests to the PyPI APIdoesn’t require
%pip install
for locked packages and their dependenciesnotebooks and scripts still need to be well-formed, e.g.
import my_package
once shipped, package versions loaded in the browser won’t change over time
during a build
doesn’t require rebuilding a full custom
pyodide
distributionbut will patch an custom deployed
pyodide
all downloaded wheels can be optionally shipped along with the application
optionally clamp PyPI packages to a known timestamp to ensure newer packages aren’t found during a future solve
supports multiple sources of custom wheels and dependencies
Feature Comparison#
A number of approaches are available for getting reproducible JupyterLite runtime python
environments, either with jupyterlite-pyodide-kernel
or other kernels. Choosing one
requires some trades of simplicity, reproducibility, flexibility, and performance.
⏱️ Note
Each tool is evolving, so the tables below should be verified against the different tools when making a decision.
A visitor to a JupyterLite site's needs may be the top priority...
feature |
|
|
||
---|---|---|---|---|
needs separate |
no (for locked packages) |
yes ( |
no |
no |
allows install by PyPI name |
yes |
yes |
yes |
yes |
allows install from URL |
yes |
yes |
no |
yes |
blocks interaction per package |
run cell |
run cell |
start kernel |
run cell |
caches in the browser |
per package |
per package |
whole environment |
per package |
An author of a JupyterLite site may have additional needs...
feature |
|
|
||
---|---|---|---|---|
requires “heavy” build dependencies |
real browser (and/or |
no |
minimal, see repo |
many, see repo |
ships local wheels |
yes |
yes |
maybe? |
yes |
ships noarch PyPI wheels |
yes |
yes |
yes |
yes |
ships pyodide emscripten wheels |
yes |
yes |
no |
yes |
ships arbitrary pyodide zip C libs |
no |
yes |
no |
yes |
locks multiple versions of same package |
no |
yes |
no |
no |
optionally clamp to a timestamp |
yes |
no |
no |
no |