Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
dca790a
refactor: share WASM fetch and replacement patch utilities
peter-gy May 8, 2026
b6351cf
feat: add DuckDB WASM remote-source fallbacks
peter-gy May 8, 2026
9f03093
feat: wire DuckDB WASM SQL through marimo
peter-gy May 8, 2026
3549988
test: cover DuckDB WASM parity and runtime integration
peter-gy May 8, 2026
c0218b4
refactor: clarify DuckDB WASM patch specs
peter-gy May 8, 2026
2fc69d0
docs: clarify def details
peter-gy May 8, 2026
3283670
fix: preserve DuckDB WASM remote reader semantics
peter-gy May 8, 2026
a78037e
fix: tighten DuckDB WASM SQL patch wrapper
peter-gy May 8, 2026
a3ae692
fix: handle nullable DuckDB SQL summary relations
peter-gy May 9, 2026
31e3e19
fix: skip DuckDB catalog lookup for local WASM SQL
peter-gy May 9, 2026
e4f4bfb
fix: avoid stale DuckDB WASM view rewrites
peter-gy May 9, 2026
a5be229
fix: narrow DuckDB WASM package preloading
peter-gy May 9, 2026
2e77fbf
refactor: keep DuckDB SQL wrapper contract non-optional
peter-gy May 9, 2026
32dc803
test: clean up views
peter-gy May 9, 2026
6fe3e01
fix: preserve DuckDB catalog semantics in WASM rewrites
peter-gy May 9, 2026
1665f99
fix: broaden DuckDB WASM package preloading
peter-gy May 9, 2026
942e191
fix: address DuckDB WASM review comments
peter-gy May 12, 2026
7224e5a
fix: support older sqlglot URL scan metadata
peter-gy May 12, 2026
e50c8b5
docs: comment adjustments
peter-gy May 12, 2026
c82765d
refactor: reduce WASM patch helper duplication
peter-gy May 12, 2026
43a4ddd
refactor: simplify DuckDB WASM source resolution
peter-gy May 12, 2026
7110d6a
test: compact DuckDB WASM regression coverage
peter-gy May 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions frontend/src/core/islands/worker/worker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from "rpc-anywhere";
import type { NotificationPayload } from "@/core/kernel/messages";
import type { ParentSchema } from "@/core/wasm/rpc";
import { shouldLoadDuckDBPackages } from "@/core/wasm/utils";
import { TRANSPORT_ID } from "@/core/wasm/worker/constants";
import { getPyodideVersion } from "@/core/wasm/worker/getPyodideVersion";
import { MessageBuffer } from "@/core/wasm/worker/message-buffer";
Expand Down Expand Up @@ -85,8 +86,8 @@ const requestHandler = createRPCRequestHandler({
loadPackages: async (code: string) => {
await pyodideReadyPromise; // Make sure loading is done

if (code.includes("mo.sql")) {
// Add pandas and duckdb to the code
if (shouldLoadDuckDBPackages(code)) {
// Add pandas and duckdb to the code for mo.sql and for remote duckdb sources
code = `import pandas\n${code}`;
code = `import duckdb\n${code}`;
code = `import sqlglot\n${code}`;
Comment thread
peter-gy marked this conversation as resolved.
Expand Down
34 changes: 34 additions & 0 deletions frontend/src/core/wasm/__tests__/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* Copyright 2026 Marimo. All rights reserved. */

import { describe, expect, it } from "vitest";
import { shouldLoadDuckDBPackages } from "../utils";

describe("shouldLoadDuckDBPackages", () => {
it("loads for mo.sql", () => {
expect(shouldLoadDuckDBPackages('df = mo.sql("SELECT 1")')).toBe(true);
});

it("loads for duckdb imports and usage", () => {
expect(shouldLoadDuckDBPackages("import duckdb")).toBe(true);
expect(shouldLoadDuckDBPackages("from duckdb import sql")).toBe(true);
expect(shouldLoadDuckDBPackages("import pandas, duckdb")).toBe(true);
expect(shouldLoadDuckDBPackages("rows = duckdb.sql('SELECT 1')")).toBe(
true,
);
});

it("loads when package discovery found duckdb", () => {
expect(
shouldLoadDuckDBPackages("print('hello')", new Set(["duckdb"])),
).toBe(true);
});

it("does not load for incidental duckdb text", () => {
expect(shouldLoadDuckDBPackages("name = 'duckdb'")).toBe(false);
expect(shouldLoadDuckDBPackages("# import duckdb")).toBe(false);
});

it("does not load without mo.sql, duckdb usage, or discovery", () => {
expect(shouldLoadDuckDBPackages("print('hello')")).toBe(false);
});
});
14 changes: 14 additions & 0 deletions frontend/src/core/wasm/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,17 @@ export function isWasm(): boolean {
document.querySelector("marimo-wasm") !== null
);
}

const DUCKDB_USAGE_PATTERN =
/(^|\n)\s*(?:import\s+[^\n#]*\bduckdb\b|from\s+duckdb\b|[^\n#]*\bduckdb\s*\.)/;

export function shouldLoadDuckDBPackages(
code: string,
foundPackages?: ReadonlySet<string>,
): boolean {
return (
code.includes("mo.sql") ||
DUCKDB_USAGE_PATTERN.test(code) ||
Comment thread
peter-gy marked this conversation as resolved.
foundPackages?.has("duckdb") === true
);
Comment thread
peter-gy marked this conversation as resolved.
}
5 changes: 3 additions & 2 deletions frontend/src/core/wasm/worker/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { WasmFileSystem } from "./fs";
import { getMarimoWheel } from "./getMarimoWheel";
import { t } from "./tracer";
import type { SerializedBridge, WasmController } from "./types";
import { shouldLoadDuckDBPackages } from "../utils";

const MAKE_SNAPSHOT = false;

Expand Down Expand Up @@ -163,8 +164,8 @@ export class DefaultWasmController implements WasmController {
private async loadNotebookDeps(code: string, foundPackages: Set<string>) {
const pyodide = this.requirePyodide;

if (code.includes("mo.sql")) {
// We need pandas and duckdb for mo.sql
if (shouldLoadDuckDBPackages(code, foundPackages)) {
// We need pandas and duckdb for mo.sql and for remote duckdb sources
code = `import pandas\n${code}`;
code = `import duckdb\n${code}`;
code = `import sqlglot\n${code}`;
Comment thread
peter-gy marked this conversation as resolved.
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/core/wasm/worker/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import type {
SerializedBridge,
WasmController,
} from "./types";
import { shouldLoadDuckDBPackages } from "../utils";

/**
* Web worker responsible for running the notebook.
Expand Down Expand Up @@ -141,8 +142,8 @@ const requestHandler = createRPCRequestHandler({
const span = t.startSpan("loadPackages");
await pyodideReadyPromise; // Make sure loading is done

if (code.includes("mo.sql")) {
// Add pandas and duckdb to the code
if (shouldLoadDuckDBPackages(code)) {
// Add pandas and duckdb to the code for mo.sql and for remote duckdb sources
code = `import pandas\n${code}`;
code = `import duckdb\n${code}`;
code = `import sqlglot\n${code}`;
Comment thread
peter-gy marked this conversation as resolved.
Expand Down
12 changes: 12 additions & 0 deletions marimo/_output/formatters/df_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from marimo._plugins.stateless.plain_text import plain_text
from marimo._plugins.ui._impl import tabs
from marimo._plugins.ui._impl.table import get_default_table_page_size, table
from marimo._runtime._wasm._duckdb import patch_duckdb_for_wasm
from marimo._runtime._wasm._polars import patch_polars_for_wasm

LOGGER = _loggers.marimo_logger()
Expand Down Expand Up @@ -160,6 +161,17 @@ def _show_marimo_dataframe(
return table(df, selection=None, pagination=None)._mime_()


class DuckDBFormatter(FormatterFactory):
"""Use DuckDB's lazy import hook to install WASM runtime patches."""

@staticmethod
def package_name() -> str:
return "duckdb"

def register(self) -> Unregister:
return patch_duckdb_for_wasm()


class DataFusionFormatter(FormatterFactory):
@staticmethod
def package_name() -> str:
Expand Down
2 changes: 2 additions & 0 deletions marimo/_output/formatters/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from marimo._output.formatters.cell import CellFormatter
from marimo._output.formatters.df_formatters import (
DataFusionFormatter,
DuckDBFormatter,
IbisFormatter,
PolarsFormatter,
PyArrowFormatter,
Expand Down Expand Up @@ -54,6 +55,7 @@
AltairFormatter.package_name(): AltairFormatter(),
MatplotlibFormatter.package_name(): MatplotlibFormatter(),
DataFusionFormatter.package_name(): DataFusionFormatter(),
DuckDBFormatter.package_name(): DuckDBFormatter(),
IbisFormatter.package_name(): IbisFormatter(),
PandasFormatter.package_name(): PandasFormatter(),
PolarsFormatter.package_name(): PolarsFormatter(),
Expand Down
Loading
Loading