From 5986f7c087de9fd8cd9b5a743e76ebd1a83f1e97 Mon Sep 17 00:00:00 2001 From: Tim Paine <3105306+timkpaine@users.noreply.github.com> Date: Fri, 25 Sep 2026 15:39:30 -0400 Subject: [PATCH 1/2] Update Pyodide build to Python 3.14 Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com> --- .github/workflows/build.yaml | 10 +++++----- DEVELOPMENT.md | 4 ++-- package.json | 4 ++-- rust/perspective-python/build.mjs | 4 ++-- rust/perspective-python/pyproject.toml | 1 + rust/perspective-server/cpp/perspective/CMakeLists.txt | 2 +- tools/scripts/workspace.mjs | 2 +- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 6ca8f1beed..6a56f843d0 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -511,7 +511,7 @@ jobs: arch: - x86_64 python-version: - - "3.13" + - "3.14" node-version: [22.x] steps: - name: Checkout @@ -578,8 +578,8 @@ jobs: for w in "${wheels[@]}"; do echo "checking $w" case "$w" in - *pyemscripten_2025_0_wasm32.whl) ;; - *) echo "::error::$w is not tagged pyemscripten_2025_0_wasm32"; exit 1 ;; + *pyemscripten_2026_0_wasm32.whl) ;; + *) echo "::error::$w is not tagged pyemscripten_2026_0_wasm32"; exit 1 ;; esac unzip -l "$w" | grep 'perspective/widget/static/perspective-anywidget.js' \ || { echo "::error::$w is missing the anywidget JS bundle"; exit 1; } @@ -605,7 +605,7 @@ jobs: arch: - x86_64 python-version: - - "3.13" + - "3.14" node-version: [22.x] steps: - name: Checkout @@ -1240,7 +1240,7 @@ jobs: - uses: actions/download-artifact@v4 with: - name: perspective-python-dist-wasm32-emscripten-3.13 + name: perspective-python-dist-wasm32-emscripten-3.14 - uses: actions/download-artifact@v4 with: diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 4b55a60283..2761c5cafb 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -138,10 +138,10 @@ Deviating from this specific version of Emscripten specified in the project's `package.json` can introduce various errors that are extremely difficult to debug. -To install a specific version of Emscripten (e.g. `4.0.9`): +To install a specific version of Emscripten (e.g. `5.0.3`): ```bash -./emsdk install 4.0.9 +./emsdk install 5.0.3 ``` Set `PSP_SKIP_EMSDK_INSTALL=1` to prevent `pnpm install` from downloading the diff --git a/package.json b/package.json index 10683c04dd..6b858d7ac8 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,10 @@ } }, "type": "module", - "emscripten": "4.0.9", + "emscripten": "5.0.3", "binaryen": "version_132", "llvm": "17.0.6", - "pyodide": "0.29.4", + "pyodide": "314.0.7", "engines": { "node": ">=16 <27" }, diff --git a/rust/perspective-python/build.mjs b/rust/perspective-python/build.mjs index 787788e481..458d741250 100644 --- a/rust/perspective-python/build.mjs +++ b/rust/perspective-python/build.mjs @@ -32,7 +32,7 @@ if (!!process.env.PSP_DEBUG) { const is_pyodide = !!process.env.PSP_PYODIDE; const python_version = - process.env.PSP_PYTHON_VERSION || (is_pyodide ? "3.13" : "3.12"); + process.env.PSP_PYTHON_VERSION || (is_pyodide ? "3.14" : "3.12"); const version = pkg.version; @@ -50,7 +50,7 @@ if (is_pyodide) { ); emsdk_prefix = `cd ${emsdkdir} && . ./emsdk_env.sh && ./emsdk activate ${emscripten} && cd ${cwd} && `; env.MATURIN_PYEMSCRIPTEN_PLATFORM_VERSION = - process.env.MATURIN_PYEMSCRIPTEN_PLATFORM_VERSION || "2025_0"; + process.env.MATURIN_PYEMSCRIPTEN_PLATFORM_VERSION || "2026_0"; } // if not windows diff --git a/rust/perspective-python/pyproject.toml b/rust/perspective-python/pyproject.toml index bb9743e4ec..2cd56d0521 100644 --- a/rust/perspective-python/pyproject.toml +++ b/rust/perspective-python/pyproject.toml @@ -55,6 +55,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Framework :: Jupyter", "Framework :: Jupyter :: JupyterLab", "Framework :: Jupyter :: JupyterLab :: 3", diff --git a/rust/perspective-server/cpp/perspective/CMakeLists.txt b/rust/perspective-server/cpp/perspective/CMakeLists.txt index 9df7c5611c..a65c04f8e5 100644 --- a/rust/perspective-server/cpp/perspective/CMakeLists.txt +++ b/rust/perspective-server/cpp/perspective/CMakeLists.txt @@ -369,7 +369,7 @@ endif() set(RAPIDJSON_BUILD_TESTS OFF CACHE BOOL "Disable rapidjson tests") if(PSP_PYODIDE) - set(RELOCATABLE_FLAGS " -sRELOCATABLE=1 -sSIDE_MODULE=2 -fwasm-exceptions -sSUPPORT_LONGJMP=wasm \ ") + set(RELOCATABLE_FLAGS " -sSIDE_MODULE=2 -fwasm-exceptions -sSUPPORT_LONGJMP=wasm \ ") string(APPEND CMAKE_EXE_LINKER_FLAGS "${RELOCATABLE_FLAGS} -sWASM_BIGINT=1 ") string(APPEND CMAKE_C_FLAGS "${RELOCATABLE_FLAGS}") string(APPEND CMAKE_CXX_FLAGS "${RELOCATABLE_FLAGS}") diff --git a/tools/scripts/workspace.mjs b/tools/scripts/workspace.mjs index 90657a2fc0..17308db16f 100644 --- a/tools/scripts/workspace.mjs +++ b/tools/scripts/workspace.mjs @@ -42,7 +42,7 @@ export function getRustWheelsDir() { export function getEmscriptenWheelPath() { const pspVersion = getWorkspacePackageJson().version.replace("-", "."); - const wheeljunk = "cp311-abi3-pyemscripten_2025_0_wasm32"; + const wheeljunk = "cp311-abi3-pyemscripten_2026_0_wasm32"; return path.join( rustWheelsDir, `perspective_python-${pspVersion}-${wheeljunk}.whl`, From 0e0edea83fb8f854f67d2b2fbb4ab5d8acebffce Mon Sep 17 00:00:00 2001 From: Tim Paine <3105306+timkpaine@users.noreply.github.com> Date: Fri, 25 Sep 2026 18:24:38 -0400 Subject: [PATCH 2/2] Separate Pyodide Emscripten toolchain Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com> --- .github/workflows/build.yaml | 8 ++++---- DEVELOPMENT.md | 7 ++++--- package.json | 3 ++- rust/perspective-python/build.mjs | 4 ++-- tools/scripts/install_emsdk.mjs | 4 +++- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 6a56f843d0..7eaf3932d9 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -526,8 +526,8 @@ jobs: name: perspective-metadata path: rust/ - # Shares the `emscripten-wasm32` ccache prefix and `wasm32` - # emsdk sysroot with `build_js` — same toolchain, same target. + # Pyodide requires a newer Emscripten toolchain than the browser + # build, so its compiler and sysroot caches must remain separate. - name: Initialize Build id: init-step uses: ./.github/actions/install-deps @@ -535,8 +535,8 @@ jobs: javascript: "false" arch: ${{ matrix.arch }} manylinux: "false" - ccache: "emscripten-wasm32" - emsdk_cache: "wasm32" + ccache: "pyodide-wasm32" + emsdk_cache: "pyodide-wasm32" cargo_cache: "false" cache_save: ${{ steps.config-step.outputs.SAVE_CACHE }} skip_cache: ${{ steps.config-step.outputs.SKIP_CACHE }} diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 2761c5cafb..7e06a042b2 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -138,10 +138,10 @@ Deviating from this specific version of Emscripten specified in the project's `package.json` can introduce various errors that are extremely difficult to debug. -To install a specific version of Emscripten (e.g. `5.0.3`): +To install a specific version of Emscripten (e.g. `4.0.9`): ```bash -./emsdk install 5.0.3 +./emsdk install 4.0.9 ``` Set `PSP_SKIP_EMSDK_INSTALL=1` to prevent `pnpm install` from downloading the @@ -168,7 +168,8 @@ this within a virtual environment. To build for [Pyodide](https://pyodide.org/), select `perspective-python (pyodide)` in `pnpm run setup` and install the pinned -Pyodide distribution with `pnpm run install_pyodide`. +Pyodide distribution with `pnpm run install_pyodide`. Pyodide builds use the +separate `pyodide_emscripten` version pinned in `package.json`. ### `perspective-jupyterlab` diff --git a/package.json b/package.json index 6b858d7ac8..e488c51875 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ } }, "type": "module", - "emscripten": "5.0.3", + "emscripten": "4.0.9", + "pyodide_emscripten": "5.0.3", "binaryen": "version_132", "llvm": "17.0.6", "pyodide": "314.0.7", diff --git a/rust/perspective-python/build.mjs b/rust/perspective-python/build.mjs index 458d741250..60e30a8383 100644 --- a/rust/perspective-python/build.mjs +++ b/rust/perspective-python/build.mjs @@ -45,10 +45,10 @@ const env = { ...process.env }; let emsdk_prefix = ""; if (is_pyodide) { const emsdkdir = path.resolve(__dirname, "../../.emsdk"); - const { emscripten } = JSON.parse( + const { pyodide_emscripten } = JSON.parse( fs.readFileSync(path.resolve(__dirname, "../../package.json")), ); - emsdk_prefix = `cd ${emsdkdir} && . ./emsdk_env.sh && ./emsdk activate ${emscripten} && cd ${cwd} && `; + emsdk_prefix = `cd ${emsdkdir} && . ./emsdk_env.sh && ./emsdk activate ${pyodide_emscripten} && cd ${cwd} && `; env.MATURIN_PYEMSCRIPTEN_PLATFORM_VERSION = process.env.MATURIN_PYEMSCRIPTEN_PLATFORM_VERSION || "2026_0"; } diff --git a/tools/scripts/install_emsdk.mjs b/tools/scripts/install_emsdk.mjs index 94a820e7b1..015b26f811 100644 --- a/tools/scripts/install_emsdk.mjs +++ b/tools/scripts/install_emsdk.mjs @@ -20,7 +20,9 @@ import "zx/globals"; const pkg = getWorkspacePackageJson(); -const emscripten = pkg.emscripten; +const emscripten = process.env.PSP_PYODIDE + ? pkg.pyodide_emscripten + : pkg.emscripten; dotenv.config({ path: "./.perspectiverc", quiet: true });