diff --git a/build.sh b/build.sh index b7ccdaa..1c50fee 100755 --- a/build.sh +++ b/build.sh @@ -13,6 +13,7 @@ jupyter lite build --contents content --output-dir dist python3 - <<'PY' import hashlib import json +import re import shutil from pathlib import Path @@ -29,6 +30,23 @@ kernel_settings = config["jupyter-config-data"]["litePluginSettings"][ ] kernel_settings["pyodideUrl"] = f"./static/pyodide/{versioned_module.name}" config_path.write_text(json.dumps(config, indent=2) + "\n") + +kernel_extension_dir = Path( + "dist/extensions/@jupyterlite/pyodide-kernel-extension/static" +) +load_pyodide_pattern = re.compile( + r"\(await ([A-Za-z_$][\w$]*|__webpack_require__)\(476\)\(([A-Za-z_$][\w$]*)\)\)\.loadPyodide" +) +patched_files = [] +for path in kernel_extension_dir.glob("*.js"): + source = path.read_text() + patched = load_pyodide_pattern.sub(r"(await import(\2)).loadPyodide", source) + if patched != source: + path.write_text(patched) + patched_files.append(path.name) + +if not patched_files: + raise SystemExit("No Pyodide dynamic import bundle entry was patched") PY find content/ -type f -exec cat {} \; | sha256sum | cut -d' ' -f1 > content-hash.txt HASH=$(cat content-hash.txt) diff --git a/tests/test_notebooks_pyodide.py b/tests/test_notebooks_pyodide.py index 248ddea..d7c5478 100644 --- a/tests/test_notebooks_pyodide.py +++ b/tests/test_notebooks_pyodide.py @@ -51,6 +51,17 @@ def test_configured_pyodide_module_exists(): assert (DIST / pyodide_url.removeprefix("./")).exists() +def test_pyodide_kernel_uses_native_dynamic_import(): + extension_dir = DIST / "extensions" / "@jupyterlite" / "pyodide-kernel-extension" / "static" + js_files = list(extension_dir.glob("*.js")) + assert js_files + bundle_source = "\n".join(path.read_text(encoding="utf8") for path in js_files) + assert ".endsWith(\".mjs\")?t=(await import(" in bundle_source + assert "(476)(r)).loadPyodide" not in bundle_source + assert "(476)(n)).loadPyodide" not in bundle_source + assert "(476)(s)).loadPyodide" not in bundle_source + + def _execute_notebook(notebook_path: Path, *, cells: int | None = None, timeout: int = 600) -> None: """Execute a notebook using the local CPython kernel.