Skip to content

Commit a847439

Browse files
committed
[feat] Update scripts and README
1 parent b3240c9 commit a847439

File tree

2 files changed

+188
-55
lines changed

2 files changed

+188
-55
lines changed

README.md

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,90 @@ Please file [bug reports](https://github.com/streamlit/streamlit/issues/new?temp
1717
## 📦 Installation
1818

1919
```bash
20-
pip install streamlit-bokeh
20+
uv pip install streamlit-bokeh
2121
```
2222

2323
Ensure you have **Streamlit** and **Bokeh** installed as well:
2424

2525
```bash
26-
pip install streamlit bokeh
26+
uv pip install streamlit bokeh
27+
```
28+
29+
---
30+
31+
## 🛠️ Development
32+
33+
### Prerequisites
34+
35+
- **Python** 3.10–3.13
36+
- **Node.js** 24.x.y (see `.nvmrc`)
37+
- **uv** (fast Python package manager)
38+
39+
### 1) Create and activate a virtual environment
40+
41+
```bash
42+
uv venv .venv
43+
source .venv/bin/activate
44+
```
45+
46+
### 2) Install Python dependencies from `pyproject.toml`
47+
48+
```bash
49+
# Minimal runtime install (editable)
50+
uv pip install -e .
51+
52+
# Recommended for development (includes tests/tools)
53+
uv pip install -e ".[devel]"
54+
```
55+
56+
### 3) Install and build the frontend
57+
58+
```bash
59+
cd streamlit_bokeh/frontend
60+
corepack enable
61+
yarn install
62+
yarn build # one-time build to produce frontend/build assets
63+
64+
# Optional: frontend dev server
65+
# Use `yarn dev:v2` to utilize the Custom Component v2 frontend (recommended).
66+
# Use `yarn dev:v1` to utilize the Custom Component v1 frontend (legacy).
67+
yarn dev:v2
68+
```
69+
70+
### 4) Run a local demo
71+
72+
```bash
73+
streamlit run ./e2e_playwright/bokeh_chart_basics.py
74+
```
75+
76+
### 5) Run tests
77+
78+
Python end-to-end tests (Playwright):
79+
80+
```bash
81+
# Build the package
82+
uv build
83+
# Install the test dependencies
84+
uv pip install -r e2e_playwright/test-requirements.txt
85+
# Install browsers (first time only)
86+
python -m playwright install --with-deps
87+
# Run tests
88+
pytest e2e_playwright -n auto
89+
```
90+
91+
Frontend tests and type checks:
92+
93+
```bash
94+
cd streamlit_bokeh/frontend
95+
yarn test
96+
yarn typecheck
97+
```
98+
99+
### 6) Build the Python package (optional)
100+
101+
```bash
102+
uv build
103+
ls dist/
27104
```
28105

29106
---

scripts/update_bokeh_version.py

Lines changed: 109 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@
1414

1515
import os
1616
import re
17+
import subprocess
18+
1719
import requests
1820
import semver
19-
import subprocess
21+
import toml
2022

21-
SETUP_PY_PATH = "setup.py"
23+
PYPROJECT_TOML_PATH = "pyproject.toml"
24+
PACKAGE_PYPROJECT_TOML_PATH = "streamlit_bokeh/pyproject.toml"
2225

2326

2427
def get_latest_bokeh_version():
@@ -31,29 +34,31 @@ def get_latest_bokeh_version():
3134

3235

3336
def get_component_version():
34-
with open(SETUP_PY_PATH, "r") as f:
35-
setup_content = f.read()
37+
with open(PYPROJECT_TOML_PATH, "r") as f:
38+
pyproject_data = toml.load(f)
3639

37-
# Extract version from setup.py
38-
match = re.search(r"version\s*=\s*['\"]([\d\.]+)(['\"])", setup_content)
40+
# Extract version from pyproject.toml
41+
version = pyproject_data.get("project", {}).get("version")
3942

40-
if match:
41-
return match.group(1)
43+
if version:
44+
return version
4245
else:
43-
raise ValueError("Bokeh version not found in the file")
46+
raise ValueError("Component version not found in pyproject.toml")
4447

4548

4649
def get_dependency_bokeh_version():
47-
with open(SETUP_PY_PATH, "r") as f:
48-
setup_content = f.read()
50+
with open(PYPROJECT_TOML_PATH, "r") as f:
51+
pyproject_data = toml.load(f)
4952

50-
# Extract Bokeh version from dependency line (e.g., bokeh==2.4.3)
51-
match = re.search(r"bokeh\s*==\s*([\d\.]+)", setup_content)
53+
# Extract Bokeh version from dependencies list
54+
dependencies = pyproject_data.get("project", {}).get("dependencies", [])
5255

53-
if match:
54-
return match.group(1)
55-
else:
56-
raise ValueError("Bokeh version not found in the file")
56+
for dep in dependencies:
57+
match = re.search(r"bokeh\s*==\s*([\d\.]+)", dep)
58+
if match:
59+
return match.group(1)
60+
61+
raise ValueError("Bokeh version not found in dependencies")
5762

5863

5964
def download_files(new_version, destination):
@@ -67,6 +72,9 @@ def download_files(new_version, destination):
6772
f"https://raw.githubusercontent.com/bokeh/bokeh/refs/tags/{new_version}/LICENSE.txt",
6873
]
6974

75+
# Ensure destination/bokeh directory exists
76+
os.makedirs(os.path.join(destination, "bokeh"), exist_ok=True)
77+
7078
for url in files_to_download:
7179
filename = os.path.basename(url)
7280
print(f"Downloading {filename}")
@@ -77,28 +85,30 @@ def download_files(new_version, destination):
7785
f.write(chunk)
7886

7987

80-
def update_setup_py(new_version, old_bokeh_version, new_bokeh_version):
81-
with open(SETUP_PY_PATH, "r") as f:
82-
setup_content = f.read()
88+
def update_pyproject_toml(new_version, old_bokeh_version, new_bokeh_version):
89+
for path in (PYPROJECT_TOML_PATH, PACKAGE_PYPROJECT_TOML_PATH):
90+
if not os.path.exists(path):
91+
raise FileNotFoundError(f"File {path} not found")
8392

84-
# Replace package version in `version='...'`
85-
# This pattern is naive; adapt as needed for your file structure.
86-
setup_content = re.sub(
87-
r"(version\s*=\s*['\"])([\d\.]+)(['\"])",
88-
rf"\g<1>{new_version}\g<3>",
89-
setup_content,
90-
)
93+
with open(path, "r") as f:
94+
pyproject_data = toml.load(f)
9195

92-
# Replace bokeh==old_version with bokeh==new_version
93-
if old_bokeh_version:
94-
setup_content = re.sub(
95-
rf"(bokeh\s*==\s*){old_bokeh_version}",
96-
rf"\g<1>{new_bokeh_version}",
97-
setup_content,
98-
)
96+
project = pyproject_data.get("project")
97+
98+
# Update project version if present
99+
if project and "version" in project:
100+
project["version"] = new_version
101+
102+
# Update bokeh dependency version if present in this file
103+
if old_bokeh_version and "dependencies" in project:
104+
dependencies = project["dependencies"]
105+
for i, dep in enumerate(dependencies):
106+
if isinstance(dep, str) and dep.startswith("bokeh=="):
107+
dependencies[i] = f"bokeh=={new_bokeh_version}"
108+
break
99109

100-
with open(SETUP_PY_PATH, "w") as f:
101-
f.write(setup_content)
110+
with open(path, "w") as f:
111+
toml.dump(pyproject_data, f)
102112

103113

104114
def update_test_requirements(
@@ -160,16 +170,56 @@ def update_init_py(old_bokeh_version, new_bokeh_version):
160170
f.write(init_py_contents)
161171

162172

163-
def update_index_html(public_dir, old_version, new_version):
164-
index_html_path = os.path.join(public_dir, "index.html")
165-
if os.path.exists(index_html_path):
166-
with open(index_html_path, "r", encoding="utf-8") as f:
173+
def update_loader_imports(old_bokeh_version, new_bokeh_version):
174+
"""
175+
Update versioned Bokeh asset import paths in the TypeScript loader to the new version.
176+
177+
This replaces occurrences like `bokeh-3.8.0.min.js` with `bokeh-<new>.min.js`
178+
in `streamlit_bokeh/frontend/src/loaders.ts`.
179+
"""
180+
loader_path = "streamlit_bokeh/frontend/src/loaders.ts"
181+
with open(loader_path, "r", encoding="utf-8") as f:
182+
contents = f.read()
183+
184+
suffixes = ["mathjax", "gl", "api", "tables", "widgets", ""]
185+
for suffix in suffixes:
186+
old_str = (
187+
f"bokeh-{suffix}-{old_bokeh_version}.min.js"
188+
if suffix
189+
else f"bokeh-{old_bokeh_version}.min.js"
190+
)
191+
new_str = (
192+
f"bokeh-{suffix}-{new_bokeh_version}.min.js"
193+
if suffix
194+
else f"bokeh-{new_bokeh_version}.min.js"
195+
)
196+
contents = contents.replace(old_str, new_str)
197+
198+
with open(loader_path, "w", encoding="utf-8") as f:
199+
f.write(contents)
200+
201+
202+
def update_index_html(frontend_dir, old_version, new_version):
203+
"""
204+
Update the index.html files to reference the new Bokeh asset version.
205+
Only the source Vite entry point (`frontend/index.html`) needs to be updated,
206+
since build artifacts are regenerated.
207+
"""
208+
209+
index_html_paths = [os.path.join(frontend_dir, "index.html")]
210+
211+
cdn_suffixes = ["mathjax", "gl", "api", "tables", "widgets", ""]
212+
found_index = False
213+
214+
for path in index_html_paths:
215+
if not os.path.exists(path):
216+
continue
217+
218+
found_index = True
219+
with open(path, "r", encoding="utf-8") as f:
167220
html_content = f.read()
168221

169-
# If old_version is known, do a direct replacement
170222
if old_version:
171-
# Replace each script reference with the new version
172-
cdn_suffixes = ["mathjax", "gl", "api", "tables", "widgets", ""]
173223
for suffix in cdn_suffixes:
174224
old_str = (
175225
f"bokeh-{suffix}-{old_version}.min.js"
@@ -183,10 +233,13 @@ def update_index_html(public_dir, old_version, new_version):
183233
)
184234
html_content = html_content.replace(old_str, new_str)
185235

186-
with open(index_html_path, "w", encoding="utf-8") as f:
236+
with open(path, "w", encoding="utf-8") as f:
187237
f.write(html_content)
188-
else:
189-
print("No index.html found in frontend/public. Skipping HTML update.")
238+
239+
if not found_index:
240+
print(
241+
"No index.html found under streamlit_bokeh/frontend. Skipping HTML update."
242+
)
190243

191244

192245
def check_remote_branch_exists(remote: str, new_version: str) -> bool:
@@ -242,21 +295,24 @@ def check_remote_branch_exists(remote: str, new_version: str) -> bool:
242295
exit(0)
243296

244297
print("New version available!")
245-
public_dir = "streamlit_bokeh/frontend/public"
298+
assets_dir = "streamlit_bokeh/frontend/src/assets"
299+
frontend_dir = "streamlit_bokeh/frontend"
246300

247301
# Remove original files
248-
bokeh_dir = os.path.join(public_dir, "bokeh")
302+
bokeh_dir = os.path.join(assets_dir, "bokeh")
303+
os.makedirs(bokeh_dir, exist_ok=True)
249304
for filename in os.listdir(bokeh_dir):
250305
if "bokeh" in filename and filename.endswith(".js"):
251306
os.remove(os.path.join(bokeh_dir, filename))
252307

253-
download_files(new_bokeh_version, public_dir)
254-
# Update the bokeh dependency version in index.html and __init__.py
255-
update_index_html(public_dir, old_bokeh_version, new_bokeh_version)
308+
download_files(new_bokeh_version, assets_dir)
309+
# Update the bokeh dependency version in index.html, TS loader and __init__.py
310+
update_index_html(frontend_dir, old_bokeh_version, new_bokeh_version)
311+
update_loader_imports(old_bokeh_version, new_bokeh_version)
256312
update_init_py(old_bokeh_version, new_bokeh_version)
257313

258-
# Update the bokeh dependency version and component version in setup.py and test-requirements.txt
259-
update_setup_py(new_version, old_bokeh_version, new_bokeh_version)
314+
# Update the bokeh dependency version in pyproject.toml and test-requirements.txt
315+
update_pyproject_toml(new_version, old_bokeh_version, new_bokeh_version)
260316
update_test_requirements(
261317
old_bokeh_version, new_bokeh_version, old_version, new_version
262318
)

0 commit comments

Comments
 (0)