Skip to content

Commit 4c3c5ba

Browse files
feat: add a new field "execute_readme_py" to afterpython.toml to pass in "--execute" option when running "marimo export html-wasm"
1 parent 71f61a3 commit 4c3c5ba

11 files changed

Lines changed: 166 additions & 92 deletions

File tree

afterpython/README_sample.py

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
1+
# ruff: noqa
2+
3+
# /// script
4+
# requires-python = ">=3.13"
5+
# dependencies = [
6+
# "marimo>=0.23.8",
7+
# "pfeed==0.0.8",
8+
# ]
9+
# ///
10+
111
import marimo
212

3-
__generated_with = "0.23.4"
13+
__generated_with = "0.23.8"
414
app = marimo.App()
515

616

7-
@app.cell(hide_code=True)
17+
@app.cell
818
def _():
919
import marimo as mo
20+
import pfeed as pe
1021

11-
return (mo,)
22+
return mo, pe
1223

1324

1425
@app.cell(hide_code=True)
@@ -25,5 +36,73 @@ def _():
2536
return
2637

2738

39+
@app.cell
40+
async def _():
41+
import sys
42+
43+
if sys.platform == "emscripten":
44+
import micropip
45+
46+
await micropip.install(["polars", "pyarrow", "pyodide-http"])
47+
48+
# avoid creating a thread in tqdm
49+
import tqdm
50+
51+
tqdm.tqdm.monitor_interval = 0
52+
53+
import pyodide_http
54+
55+
pyodide_http.patch_all()
56+
57+
# CORS proxy shim — public.bybit.com sends no CORS headers,
58+
# so route every httpx.get through a proxy that does.
59+
import httpx
60+
61+
_orig_get = httpx.get
62+
PROXY = "https://pfeed-cors.lucky-water-569b.workers.dev/?url="
63+
64+
def _proxied_get(url, *args, **kwargs):
65+
return _orig_get(PROXY + url, *args, **kwargs)
66+
67+
httpx.get = _proxied_get
68+
return
69+
70+
71+
@app.cell(hide_code=True)
72+
def _(mo):
73+
mo.callout(
74+
mo.md(
75+
"**Demo mode.** This is `pfeed` running in WASM — core features "
76+
"are not fully supported. "
77+
"For full functionality, install locally:\n\n"
78+
"```\npip install pfeed[core]\n```\n"
79+
"Click **▶ Run all** (top right) to start. First run takes ~15s while Pyodide and dependencies load."
80+
),
81+
kind="info",
82+
)
83+
return
84+
85+
86+
@app.cell
87+
def _(pe):
88+
bybit = pe.Bybit()
89+
feed = bybit.market_feed
90+
result = feed.download(
91+
product="BTC_USDT_PERP",
92+
resolution="1minute",
93+
start_date="2026-01-01",
94+
end_date="2026-01-01",
95+
storage_config=None,
96+
)
97+
df = result.data.collect()
98+
df
99+
return
100+
101+
102+
@app.cell
103+
def _():
104+
return
105+
106+
28107
if __name__ == "__main__":
29108
app.run()

afterpython/_website/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@afterpython/project-website-template",
3-
"version": "0.3.8",
3+
"version": "0.3.9",
44
"license": "Apache-2.0",
55
"type": "module",
66
"packageManager": "pnpm@11.1.1",

afterpython/_website/src/routes/+page.svelte

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,47 +9,6 @@
99
1010
const { data }: PageProps = $props();
1111
12-
let readmeIframeEl = $state<HTMLIFrameElement | null>(null);
13-
let readmeIframeHeight = $state(800);
14-
15-
function handleReadmeIframeLoad() {
16-
const doc = readmeIframeEl?.contentDocument;
17-
if (!doc) return;
18-
19-
// Marimo's wasm app shell sets html/body to 100vh with internal scrolling,
20-
// which prevents the iframe from sizing to real content. Override so the
21-
// document flows naturally and scrollHeight reflects actual content height.
22-
const style = doc.createElement('style');
23-
style.textContent = `
24-
html, body {
25-
height: auto !important;
26-
min-height: 0 !important;
27-
max-height: none !important;
28-
overflow: visible !important;
29-
}
30-
#App, #root, marimo-mount, [class*="marimo"] {
31-
height: auto !important;
32-
min-height: 0 !important;
33-
max-height: none !important;
34-
overflow: visible !important;
35-
}
36-
`;
37-
(doc.head ?? doc.documentElement).appendChild(style);
38-
39-
const update = () => {
40-
const h = Math.max(
41-
doc.documentElement?.scrollHeight ?? 0,
42-
doc.body?.scrollHeight ?? 0
43-
);
44-
if (h > 0) readmeIframeHeight = h;
45-
};
46-
47-
update();
48-
const ro = new ResizeObserver(update);
49-
if (doc.documentElement) ro.observe(doc.documentElement);
50-
if (doc.body) ro.observe(doc.body);
51-
}
52-
5312
// Extract repository URL safely
5413
const repositoryUrl = $derived(
5514
data.project_url?.find((url: string) => url.startsWith('repository,'))?.split(', ')[1]
@@ -142,13 +101,10 @@
142101

143102
{#if data.readme_py}
144103
<iframe
145-
bind:this={readmeIframeEl}
146104
src={resolve('/readme_py/readme_py.html')}
147105
title="README"
148106
loading="lazy"
149-
onload={handleReadmeIframeLoad}
150-
class="w-full max-w-4xl rounded-2xl border border-bg300 bg-bg100 text-left shadow-lg"
151-
style="height: {readmeIframeHeight}px;"
107+
class="h-[96vh] w-full max-w-4xl rounded-2xl border mb-28 border-bg300 bg-bg100 text-left shadow-lg"
152108
></iframe>
153109
{:else if data.description}
154110
<div

afterpython/afterpython.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ logo_dark = "logo.svg"
1111
thumbnail = "thumbnail.png" # thumbnail for the website, also used as default thumbnail for all content types, e.g. blog posts, tutorials, examples, and guides
1212
announcement = ""
1313
readme_py = "wasm" # marimo html export format: "wasm" or "static"
14+
execute_readme_py = false # execute README.py cells at build time and embed outputs as a preview (wasm mode only)
1415
api_reference = false # set to true to enable the pdoc-generated API reference
1516

1617
# [website.blog]

afterpython/doc/project_website.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,14 @@ Choose the export mode in `afterpython.toml`:
158158
```toml
159159
[website]
160160
readme_py = "wasm" # or "static"
161+
execute_readme_py = false # execute cells at build time and embed outputs as a preview (wasm mode only)
161162
```
162163

163164
- **`wasm`** (default) — interactive. Cells run in the browser via Pyodide. Great for live demos of your package, but adds a ~10MB+ Pyodide download on first visit. Won't work for packages with C extensions that aren't ported to Pyodide.
164165
- **`static`** — pre-rendered HTML, no runtime. Lighter, but cells can't execute. AfterPython adds an "Open in molab" badge so users can still run the notebook on a real Python server hosted by marimo.
165166

167+
Set `execute_readme_py = true` to execute the notebook before exporting and embed the cell outputs as a preview — visitors see results immediately instead of a blank notebook while Pyodide boots. Marimo runs the execution in an isolated environment pinned to WASM-compatible packages when possible. Only honored in `wasm` mode.
168+
166169
`README.md` is still required (PyPI uses it for the long description) and is shown if `README.py` is absent or isn't a marimo notebook.
167170

168171
### FAQs

0 commit comments

Comments
 (0)