Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
Empty file added docs/_ext/__init__.py
Empty file.
42 changes: 42 additions & 0 deletions docs/_ext/playground.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# docs/_ext/playground.py

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__)


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: Self) -> list[Any]:
# Generate unique IDs for the HTML elements
id = uuid4().hex
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: 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}
92 changes: 92 additions & 0 deletions docs/_ext/playground_template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<style>
textarea {
width: 100%;
height: 200px;
font-family: monospace;
font-size: 14px;
padding: 0.5rem;
border-radius: 8px;
border: 1px solid #ccc;
background: #fff;
}
pre {
background: #111827;
color: #e5e7eb;
padding: 1rem;
border-radius: 8px;
height: 200px;
overflow-y: auto;
margin-top: 1rem;
}
</style>
<h2>🐍 Pyodide + SQLSpec Runner</h2>
<textarea id="editor-{{ uuid }}">
# Try Python code here
import sqlspec
print("sqlspec version:", sqlspec.__version__)
</textarea>
<br>
<button id="run-button-{{ uuid }}">Loading...</button>

<pre id="output-{{ uuid }}"></pre>

<!-- ✅ Load Pyodide runtime -->
<script src="https://cdn.jsdelivr.net/pyodide/v0.29.0/full/pyodide.js"></script>

<!-- ✅ Your app logic -->
<script>
(async function() {
const editor = document.getElementById("editor-{{ uuid }}");
const output = document.getElementById("output-{{ uuid }}");
const runButton = document.getElementById("run-button-{{ uuid }}");

let pyodide = null;

function writeToOutput(s) {
output.textContent += s + "\n";
output.scrollTop = output.scrollHeight;
}

async function initPyodide() {
try {
pyodide = await loadPyodide();
pyodide.setStdout({ batched: writeToOutput });
pyodide.setStderr({ batched: writeToOutput });
output.textContent = "✅ Pyodide loaded.\nInstalling micropip...\n";

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");

output.textContent += "✅ Ready! You can now run Python code.\n";
runButton.disabled = false;
runButton.textContent = "▶ Run";
} catch (err) {
output.textContent = "❌ Error loading Pyodide: " + err;
console.error(err);
}
}

runButton.disabled = true;
runButton.textContent = "Loading...";
runButton.onclick = async () => {
if (!pyodide) {
output.textContent = "Pyodide is not loaded yet.";
return;
}
const code = editor.value;
output.textContent = "Running code...\n";
try {
await pyodide.runPythonAsync(code);
} catch (err) {
writeToOutput("Python Error: " + err);
console.error(err);
}
};

initPyodide();
})();
</script>
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"sphinx_togglebutton",
"sphinx_paramlinks",
"sphinxcontrib.mermaid",
"docs._ext.playground",
]
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
9 changes: 9 additions & 0 deletions docs/playground.rst
Original file line number Diff line number Diff line change
@@ -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::