diff --git a/_extensions/pyodide/qpyodide-document-engine-initialization.js b/_extensions/pyodide/qpyodide-document-engine-initialization.js index 1926571..ac69fe8 100644 --- a/_extensions/pyodide/qpyodide-document-engine-initialization.js +++ b/_extensions/pyodide/qpyodide-document-engine-initialization.js @@ -32,11 +32,21 @@ globalThis.qpyodideInstance = await import( // Setup a namespace for global scoping // await loadedPyodide.runPythonAsync("globalScope = {}"); + + // Update status to reflect the next stage of the procedure + qpyodideUpdateStatusHeaderSpinner("Initializing Python Packages"); // Load the `micropip` package to allow installation of packages. await mainPyodide.loadPackage("micropip"); + await mainPyodide.runPythonAsync(`import micropip`); + + // Load the `pyodide_http` package to shim uses of `requests` and `urllib3`. + // This allows for `pd.read_csv(url)` to work flawlessly. + // Details: https://github.com/coatless-quarto/pyodide/issues/9 + await mainPyodide.loadPackage("pyodide_http"); await mainPyodide.runPythonAsync(` - import micropip + import pyodide_http + pyodide_http.patch_all() # Patch all libraries `); // Load the `matplotlib` package with necessary environment hook @@ -53,11 +63,12 @@ globalThis.qpyodideInstance = await import( qpyodideSetInteractiveButtonState( ` Run Code`, true - ); + ); - if (qpyodideShowStartupMessage) { - qpyodideStartupMessage.innerText = "🟢 Ready!" - } + // Set document status to viable + qpyodideUpdateStatusHeader( + "🟢 Ready!" + ); // Assign Pyodide into the global environment globalThis.mainPyodide = mainPyodide; diff --git a/_extensions/pyodide/qpyodide-document-status.js b/_extensions/pyodide/qpyodide-document-status.js index 5fff260..bb53113 100644 --- a/_extensions/pyodide/qpyodide-document-status.js +++ b/_extensions/pyodide/qpyodide-document-status.js @@ -18,11 +18,22 @@ globalThis.qpyodideUpdateStatusMessage = function(message) { // Function to update the status message globalThis.qpyodideUpdateStatusHeader = function(message) { - qpyodideStartupMessage.innerHTML = ` + + if (!qpyodideShowStartupMessage) return; + + qpyodideStartupMessage.innerHTML = message; +} + +// Status header update with customized spinner message +globalThis.qpyodideUpdateStatusHeaderSpinner = function(message) { + + qpyodideUpdateStatusHeader(` - ${message}`; + ${message} + `); } + // Function that attaches the document status message function qpyodideDisplayStartupMessage(showStartupMessage) { if (!showStartupMessage) { diff --git a/docs/qpyodide-code-cell-demo.qmd b/docs/qpyodide-code-cell-demo.qmd index de992c1..f2688d0 100644 --- a/docs/qpyodide-code-cell-demo.qmd +++ b/docs/qpyodide-code-cell-demo.qmd @@ -125,7 +125,22 @@ num_list = [1, 2, 3] ## Load a package -We've enabled _dynamic_ package detection to handle importing packages into the environment. The _dynamic_ part comes from detecting whether a non-core Python package is used, installing, and, then, importing it. +There are two types of Python packages that will work within an interactive cell. + +- pure Python packages + - denoted by `*py3-none-any.whl` on PyPI +- Python packages compiled for Pyodide + - denoted by `*-cp310-cp310-emscripten_3_1_27_wasm32.whl` that require a specific Python and Emscripten versions + +The latter option makes up part of the Pyodide "core" or "base" set of Python packages. + +:::{.callout-important} +Not all functionality of a Python package may be available in the browser due to limitations or different versions being present. +::: + +### Loading a Pyodide core package + +For packages that are part of [Pyodide core](https://pyodide.org/en/stable/usage/packages-in-pyodide.html), we've enabled _dynamic_ package detection to handle importing packages into the environment. The _dynamic_ part comes from detecting whether a Python package is being used through an import statement and automatically taking care of the installation process behind the scenes. :::{.callout-note} Importing a package for the first time will require more time. Subsequent import statements will be resolve quicker. @@ -173,7 +188,7 @@ from palmerpenguins import load_penguins # Load data in the package penguins = load_penguins() -# Display th e first 5 rows of the data using Pandas +# Display the first 5 rows of the data using Pandas penguins.head() ``` @@ -190,3 +205,13 @@ y = [-5, 8, 9, 4] plt.plot(x, y) plt.show() ``` + +## External Data + +Interactive cells also allow for a limited subset of operations when working with external data. For example, we can use Pandas' `read_csv()` function to ingest data from a URL. +```{pyodide-python} +import pandas as pd + +df = pd.read_csv("https://raw.githubusercontent.com/mwaskom/seaborn-data/master/penguins.csv") +df.head() +``` \ No newline at end of file diff --git a/docs/qpyodide-release-notes.qmd b/docs/qpyodide-release-notes.qmd index 0ccb258..af7f81b 100644 --- a/docs/qpyodide-release-notes.qmd +++ b/docs/qpyodide-release-notes.qmd @@ -19,6 +19,13 @@ format: - New code cell option that set the interactive cell to be read-only. ([#4](https://github.com/coatless-quarto/pyodide/issues/4)) +## Changes + +- We now load the `micropip` and `pyodide_http` packages during document initialization. + - `micropip` package allows for installation of pure Python or Pyodide-compiled Python packages. + ([#3](https://github.com/coatless-quarto/pyodide/issues/3)) + - `pyodide_http` provides the necessary shims to ensure uses of `requests` and `urllib3` are + able to be processed instead of returning a URL error. ([#9](https://github.com/coatless-quarto/pyodide/issues/9)) # 0.0.1: What does the Python Say? (02-19-2024) diff --git a/tests/qpyodide-test-url.qmd b/tests/qpyodide-test-url.qmd new file mode 100644 index 0000000..8cfe2e4 --- /dev/null +++ b/tests/qpyodide-test-url.qmd @@ -0,0 +1,15 @@ +--- +title: "Test: Accessing Data via URL" +format: html +filters: + - pyodide +--- + +This test is designed to check if HTTP requests are shimmed so that the operation can be performed. + +```{pyodide-python} +import pandas as pd + +df = pd.read_csv("https://raw.githubusercontent.com/mwaskom/seaborn-data/master/penguins.csv") +df.head() +``` \ No newline at end of file