From 39582f7099f439832235d81af4282f6fea8fe87a Mon Sep 17 00:00:00 2001 From: Yuvi Panda Date: Wed, 5 Jul 2023 07:48:36 -0700 Subject: [PATCH] Install Pluto.jl and jupyter-pluto-proxy (#1929) * Install Pluto.jl and jupyter-pluto-proxy [Pluto.jl](https://plutojl.org/) is an alternative reactive notebook frontend focused specifically on Julia. I think shipping this by default in the julia-enabled images helps serve the Julia community better, particularly when used with JupyterHub. For context, I am working with the Julia users of the [Jupyter Meets the Earth](https://jupytearth.org/) project, and trying to understand how to best serve their needs on a JupyterHub. We currently maintain a massive image that 'has everything', but I'm trying to instead work upstream wherever possible so everyone working in these subfields can benefit. Meeting Julia users where they are at seems a useful path forward here. * Add note about Pluto.jl to selecting.md * Default to replacing - with _ in package imports * Add jupyter-pluto-proxy to package import mapping * Add Pluto.jl to datascience-notebook image * Add test for pluto proxy starting correctly * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update test_packages.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Ayaz Salikhov --- docs/using/selecting.md | 3 ++ .../setup-scripts/setup-julia-packages.bash | 10 +++++- tests/base-notebook/test_packages.py | 1 + .../datascience-notebook/test_julia_starts.py | 32 +++++++++++++++++++ tests/julia-notebook/test_pluto.py | 32 +++++++++++++++++++ 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 tests/datascience-notebook/test_julia_starts.py create mode 100644 tests/julia-notebook/test_pluto.py diff --git a/docs/using/selecting.md b/docs/using/selecting.md index f93aad70..7083dcbb 100644 --- a/docs/using/selecting.md +++ b/docs/using/selecting.md @@ -118,6 +118,8 @@ It contains: - Everything in `jupyter/minimal-notebook` and its ancestor images - The [Julia Programming Language](https://julialang.org/) - [IJulia](https://github.com/JuliaLang/IJulia.jl) to support Julia code in Jupyter notebook +- [Pluto.jl](https://plutojl.org/) reactive Julia notebook interface, made accessible with [jupyter-pluto-proxy](https://github.com/yuvipanda/jupyter-pluto-proxy) +- [HDF5](https://github.com/JuliaIO/HDF5.jl) package ### jupyter/scipy-notebook @@ -188,6 +190,7 @@ communities. - [rpy2](https://rpy2.github.io/doc/latest/html/index.html) package - The [Julia](https://julialang.org/) compiler and base environment - [IJulia](https://github.com/JuliaLang/IJulia.jl) to support Julia code in Jupyter notebooks +- [Pluto.jl](https://plutojl.org/) reactive Julia notebook interface, made accessible with [jupyter-pluto-proxy](https://github.com/yuvipanda/jupyter-pluto-proxy) - [HDF5](https://github.com/JuliaIO/HDF5.jl) package ### jupyter/pyspark-notebook diff --git a/minimal-notebook/setup-scripts/setup-julia-packages.bash b/minimal-notebook/setup-scripts/setup-julia-packages.bash index 0be05426..faeee01e 100755 --- a/minimal-notebook/setup-scripts/setup-julia-packages.bash +++ b/minimal-notebook/setup-scripts/setup-julia-packages.bash @@ -11,7 +11,8 @@ import Pkg; Pkg.update(); Pkg.add([ "HDF5", - "IJulia" + "IJulia", + "Pluto" ]); Pkg.precompile(); ' @@ -23,3 +24,10 @@ mv "${HOME}/.local/share/jupyter/kernels/julia"* "${CONDA_DIR}/share/jupyter/ker chmod -R go+rx "${CONDA_DIR}/share/jupyter" rm -rf "${HOME}/.local" fix-permissions "${JULIA_PKGDIR}" "${CONDA_DIR}/share/jupyter" + +# Install jupyter-pluto-proxy to get Pluto to work on JupyterHub +mamba install --yes \ + 'jupyter-pluto-proxy' && \ + mamba clean --all -f -y && \ + fix-permissions "${CONDA_DIR}" && \ + fix-permissions "/home/${NB_USER}" diff --git a/tests/base-notebook/test_packages.py b/tests/base-notebook/test_packages.py index f6f9c085..b56d6120 100644 --- a/tests/base-notebook/test_packages.py +++ b/tests/base-notebook/test_packages.py @@ -52,6 +52,7 @@ LOGGER = logging.getLogger(__name__) PACKAGE_MAPPING = { # Python "beautifulsoup4": "bs4", + "jupyter-pluto-proxy": "jupyter_pluto_proxy", "matplotlib-base": "matplotlib", "pytables": "tables", "scikit-image": "skimage", diff --git a/tests/datascience-notebook/test_julia_starts.py b/tests/datascience-notebook/test_julia_starts.py new file mode 100644 index 00000000..a0d59b39 --- /dev/null +++ b/tests/datascience-notebook/test_julia_starts.py @@ -0,0 +1,32 @@ +import logging +import secrets +import time + +import requests + +from tests.conftest import TrackedContainer, find_free_port + +LOGGER = logging.getLogger(__name__) + + +def test_pluto_proxy( + container: TrackedContainer, http_client: requests.Session +) -> None: + """Pluto proxy starts Pluto correctly""" + host_port = find_free_port() + token = secrets.token_hex() + container.run_detached( + command=[ + "start.sh", + "jupyter", + "lab", + "--port=8888", + f"--LabApp.token={token}", + ], + ports={"8888/tcp": host_port}, + ) + # Give the server a bit of time to start + time.sleep(3) + resp = http_client.get(f"http://localhost:{host_port}/pluto?token={token}") + resp.raise_for_status() + assert "Pluto.jl notebooks" in resp.text, "Pluto.jl text not found in /pluto page" diff --git a/tests/julia-notebook/test_pluto.py b/tests/julia-notebook/test_pluto.py new file mode 100644 index 00000000..a0d59b39 --- /dev/null +++ b/tests/julia-notebook/test_pluto.py @@ -0,0 +1,32 @@ +import logging +import secrets +import time + +import requests + +from tests.conftest import TrackedContainer, find_free_port + +LOGGER = logging.getLogger(__name__) + + +def test_pluto_proxy( + container: TrackedContainer, http_client: requests.Session +) -> None: + """Pluto proxy starts Pluto correctly""" + host_port = find_free_port() + token = secrets.token_hex() + container.run_detached( + command=[ + "start.sh", + "jupyter", + "lab", + "--port=8888", + f"--LabApp.token={token}", + ], + ports={"8888/tcp": host_port}, + ) + # Give the server a bit of time to start + time.sleep(3) + resp = http_client.get(f"http://localhost:{host_port}/pluto?token={token}") + resp.raise_for_status() + assert "Pluto.jl notebooks" in resp.text, "Pluto.jl text not found in /pluto page"