From 3bc82dc85314fb92915ddbfb85e634b0903c395d Mon Sep 17 00:00:00 2001 From: euri10 Date: Wed, 12 Nov 2025 11:25:55 +0100 Subject: [PATCH 1/5] Add interactive Pyodide playground for SQLSpec documentation Signed-off-by: euri10 --- docs/_ext/__init__.py | 0 docs/_ext/playground.py | 43 ++++++++++++++++++ docs/_ext/playground_template.html | 72 ++++++++++++++++++++++++++++++ docs/conf.py | 1 + docs/index.rst | 1 + docs/playground.rst | 9 ++++ 6 files changed, 126 insertions(+) create mode 100644 docs/_ext/__init__.py create mode 100644 docs/_ext/playground.py create mode 100644 docs/_ext/playground_template.html create mode 100644 docs/playground.rst diff --git a/docs/_ext/__init__.py b/docs/_ext/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/_ext/playground.py b/docs/_ext/playground.py new file mode 100644 index 000000000..32e18c49c --- /dev/null +++ b/docs/_ext/playground.py @@ -0,0 +1,43 @@ +# docs/_ext/playground.py + +import logging +from pathlib import Path +from uuid import uuid4 + +from docutils import nodes +from docutils.parsers.rst import Directive +from jinja2 import Environment, FileSystemLoader + +logger = logging.getLogger(__name__) + + +class WasmPlayground(Directive): + """ + A custom Sphinx directive to embed a Pyodide-powered code playground. + """ + + logger.info("Initializing WasmPlayground directive") + has_content = True + + def run(self): + # Generate unique IDs for the HTML elements + id = uuid4().hex + print(id) + env = Environment(loader=FileSystemLoader(Path(__file__).parent)) + template = env.get_template("playground_template.html") + rendered = template.render(id=id) + return [nodes.raw(text=rendered, format="html")] + + +def setup(app): + """ + Register the directive with Sphinx. + """ + app.add_js_file("https://cdn.jsdelivr.net/pyodide/v0.29.0/full/pyodide.js", priority=100) + app.add_directive("wasm-playground", WasmPlayground) + return { + "version": "1.0", + "parallel_read_safe": True, + "parallel_write_safe": True, + } + diff --git a/docs/_ext/playground_template.html b/docs/_ext/playground_template.html new file mode 100644 index 000000000..ad987e423 --- /dev/null +++ b/docs/_ext/playground_template.html @@ -0,0 +1,72 @@ +

🐍 Pyodide + SQLSpec Runner

+ +
+ + +

+
+  
+  
+
+  
+  
diff --git a/docs/conf.py b/docs/conf.py
index c3b47720e..1b2d44b92 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -61,6 +61,7 @@
     "sphinx_togglebutton",
     "sphinx_paramlinks",
     "sphinxcontrib.mermaid",
+    "docs._ext.playground"
 ]
 intersphinx_mapping = {
     "python": ("https://docs.python.org/3", None),
diff --git a/docs/index.rst b/docs/index.rst
index 5eac61cfa..7c5dd52eb 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -51,6 +51,7 @@ SQLSpec is **NOT an ORM**. It is a flexible connectivity layer that provides a c
     usage/index
     examples/index
     reference/index
+    playground
 
 .. toctree::
     :hidden:
diff --git a/docs/playground.rst b/docs/playground.rst
new file mode 100644
index 000000000..34cc46ef5
--- /dev/null
+++ b/docs/playground.rst
@@ -0,0 +1,9 @@
+======================
+Live Playground
+======================
+
+You can try ``sqlspec`` live in your browser. The code block below
+is a full, interactive Python environment powered by Pyodide
+(WebAssembly).
+
+.. wasm-playground::

From 3b493736e4ba6bd3ae1269358b39df103f70f8e2 Mon Sep 17 00:00:00 2001
From: euri10 
Date: Wed, 12 Nov 2025 11:27:15 +0100
Subject: [PATCH 2/5] lint

---
 docs/_ext/playground.py            | 1 -
 docs/_ext/playground_template.html | 1 -
 2 files changed, 2 deletions(-)

diff --git a/docs/_ext/playground.py b/docs/_ext/playground.py
index 32e18c49c..d0716e133 100644
--- a/docs/_ext/playground.py
+++ b/docs/_ext/playground.py
@@ -22,7 +22,6 @@ class WasmPlayground(Directive):
     def run(self):
         # Generate unique IDs for the HTML elements
         id = uuid4().hex
-        print(id)
         env = Environment(loader=FileSystemLoader(Path(__file__).parent))
         template = env.get_template("playground_template.html")
         rendered = template.render(id=id)
diff --git a/docs/_ext/playground_template.html b/docs/_ext/playground_template.html
index ad987e423..dd1285cfa 100644
--- a/docs/_ext/playground_template.html
+++ b/docs/_ext/playground_template.html
@@ -36,7 +36,6 @@ 

🐍 Pyodide + SQLSpec Runner

await pyodide.loadPackage("micropip"); const micropip = pyodide.pyimport("micropip"); - output.textContent += "Installing sqlspec (this may take ~30s)...\n"; await micropip.install("sqlspec[aiosqlite]"); await micropip.install("sqlite3"); From 98ff9364c5230b755134ffb76434cb3495607caf Mon Sep 17 00:00:00 2001 From: euri10 Date: Wed, 12 Nov 2025 11:40:13 +0100 Subject: [PATCH 3/5] lint --- docs/_ext/playground.py | 16 ++++++++-------- docs/conf.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/_ext/playground.py b/docs/_ext/playground.py index d0716e133..73a057297 100644 --- a/docs/_ext/playground.py +++ b/docs/_ext/playground.py @@ -2,11 +2,16 @@ import logging from pathlib import Path +from typing import Any from uuid import uuid4 from docutils import nodes from docutils.parsers.rst import Directive from jinja2 import Environment, FileSystemLoader +from typing_extensions import Self + +__all__ = ("WasmPlayground", "setup", ) + logger = logging.getLogger(__name__) @@ -19,7 +24,7 @@ class WasmPlayground(Directive): logger.info("Initializing WasmPlayground directive") has_content = True - def run(self): + def run(self: Self) -> list[Any]: # Generate unique IDs for the HTML elements id = uuid4().hex env = Environment(loader=FileSystemLoader(Path(__file__).parent)) @@ -28,15 +33,10 @@ def run(self): return [nodes.raw(text=rendered, format="html")] -def setup(app): +def setup(app: Any) -> dict[str, Any]: """ Register the directive with Sphinx. """ app.add_js_file("https://cdn.jsdelivr.net/pyodide/v0.29.0/full/pyodide.js", priority=100) app.add_directive("wasm-playground", WasmPlayground) - return { - "version": "1.0", - "parallel_read_safe": True, - "parallel_write_safe": True, - } - + return {"version": "1.0", "parallel_read_safe": True, "parallel_write_safe": True} diff --git a/docs/conf.py b/docs/conf.py index 1b2d44b92..a88e59d68 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -61,7 +61,7 @@ "sphinx_togglebutton", "sphinx_paramlinks", "sphinxcontrib.mermaid", - "docs._ext.playground" + "docs._ext.playground", ] intersphinx_mapping = { "python": ("https://docs.python.org/3", None), From c4bd60da2eeb77e2347ae445ca5d0317195962be Mon Sep 17 00:00:00 2001 From: euri10 Date: Wed, 12 Nov 2025 11:52:10 +0100 Subject: [PATCH 4/5] need to fix autoformatting.... --- docs/_ext/playground.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_ext/playground.py b/docs/_ext/playground.py index 73a057297..7193ce474 100644 --- a/docs/_ext/playground.py +++ b/docs/_ext/playground.py @@ -10,7 +10,7 @@ from jinja2 import Environment, FileSystemLoader from typing_extensions import Self -__all__ = ("WasmPlayground", "setup", ) +__all__ = ("WasmPlayground", "setup") logger = logging.getLogger(__name__) From e1e50ac63ed7f807cf9517164cd0cff9715993f4 Mon Sep 17 00:00:00 2001 From: euri10 Date: Wed, 12 Nov 2025 12:58:45 +0100 Subject: [PATCH 5/5] basic style --- docs/_ext/playground_template.html | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/_ext/playground_template.html b/docs/_ext/playground_template.html index dd1285cfa..61cea4f17 100644 --- a/docs/_ext/playground_template.html +++ b/docs/_ext/playground_template.html @@ -1,3 +1,24 @@ +

🐍 Pyodide + SQLSpec Runner