Document potential caching issues when using pyodide worker convert target
Regarding this issue: https://github.com/holoviz/panel/issues/5371
I tried with panel 1.3.6 and seem to encounter the same error.
This from the web browser console:
[Log] PythonError: Traceback (most recent call last): (script.js, line 33)
File "micropip/_micropip.py", line 160, in _fetch_bytes
File "micropip/_compat_in_pyodide.py", line 29, in fetch_bytes
File "pyodide/http.py", line 201, in bytes
File "pyodide/http.py", line 125, in _raise_if_failed
OSError: Request for https://cdn.holoviz.org/panel/1.2.1/dist/wheels/bokeh-3.1.1-py3-none-any.whl failed with status 403:
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "_pyodide/_base.py", line 540, in eval_code_async
File "_pyodide/_base.py", line 365, in run_async
File "<exec>", line 3, in <module>
File "micropip/_micropip.py", line 576, in install
File "micropip/_micropip.py", line 342, in gather_requirements
File "micropip/_micropip.py", line 355, in add_requirement
File "micropip/_micropip.py", line 470, in add_wheel
File "micropip/_micropip.py", line 176, in download
File "micropip/_micropip.py", line 168, in _fetch_bytes
ValueError: Can't fetch wheel from 'https://cdn.holoviz.org/panel/1.2.1/dist/wheels/bokeh-3.1.1-py3-none-any.whl'. One common reason for this is when the server blocks Cross-Origin Resource Sharing (CORS). Check if the server is sending the correct 'Access-Control-Allow-Origin' header.
[Log] PythonError: Traceback (most recent call last): (script.js, line 33)
File "_pyodide/_base.py", line 540, in eval_code_async
File "_pyodide/_base.py", line 365, in run_async
File "<exec>", line 3, in <module>
File "micropip/_micropip.py", line 576, in install
File "micropip/_micropip.py", line 342, in gather_requirements
File "micropip/_micropip.py", line 355, in add_requirement
File "micropip/_micropip.py", line 472, in add_wheel
File "micropip/_micropip.py", line 342, in gather_requirements
File "micropip/_micropip.py", line 346, in add_requirement
File "micropip/_micropip.py", line 457, in add_requirement_inner
File "micropip/_micropip.py", line 472, in add_wheel
File "micropip/_micropip.py", line 342, in gather_requirements
File "micropip/_micropip.py", line 346, in add_requirement
File "micropip/_micropip.py", line 444, in add_requirement_inner
File "micropip/_micropip.py", line 312, in find_wheel
ValueError: Can't find a pure Python 3 wheel for 'contourpy>=1'.
See: https://pyodide.org/en/stable/usage/faq.html#micropip-can-t-find-a-pure-python-wheel
You can use `micropip.install(..., keep_going=True)`to get a list of all packages with missing wheels.
[Log] PythonError: Traceback (most recent call last): (script.js, line 33)
File "_pyodide/_base.py", line 540, in eval_code_async
File "_pyodide/_base.py", line 365, in run_async
File "<exec>", line 3, in <module>
File "micropip/_micropip.py", line 576, in install
File "micropip/_micropip.py", line 342, in gather_requirements
File "micropip/_micropip.py", line 349, in add_requirement
File "micropip/_micropip.py", line 457, in add_requirement_inner
File "micropip/_micropip.py", line 472, in add_wheel
File "micropip/_micropip.py", line 342, in gather_requirements
File "micropip/_micropip.py", line 346, in add_requirement
File "micropip/_micropip.py", line 457, in add_requirement_inner
File "micropip/_micropip.py", line 472, in add_wheel
File "micropip/_micropip.py", line 342, in gather_requirements
File "micropip/_micropip.py", line 346, in add_requirement
File "micropip/_micropip.py", line 444, in add_requirement_inner
File "micropip/_micropip.py", line 312, in find_wheel
ValueError: Can't find a pure Python 3 wheel for 'contourpy>=1'.
See: https://pyodide.org/en/stable/usage/faq.html#micropip-can-t-find-a-pure-python-wheel
You can use `micropip.install(..., keep_going=True)`to get a list of all packages with missing wheels.
It does not look like you have 1.3.6 since the URL it's trying to fetch from is:
https://cdn.holoviz.org/panel/1.2.1/dist/wheels/bokeh-3.1.1-py3-none-any.whl
and the 1.2.1 indicates that you have version 1.2.1 installed.
Would suggest running which panel to figure out where it's getting Panel from.
Thanks for the suggestion -- here is what I find:
brentgunderson@Brents-Air panel % which panel
/Users/brentgunderson/.pyenv/shims/panel
brentgunderson@Brents-Air panel % panel --version
1.3.6
Error message (do I need to clear something from browser?):
[Error] Failed to load resource: the server responded with a status of 403 () (bokeh-3.1.1-py3-none-any.whl, line 0)
[Log] PythonError: Traceback (most recent call last): (script.js, line 33)
File "micropip/_micropip.py", line 160, in _fetch_bytes
File "micropip/_compat_in_pyodide.py", line 29, in fetch_bytes
File "pyodide/http.py", line 201, in bytes
File "pyodide/http.py", line 125, in _raise_if_failed
OSError: Request for https://cdn.holoviz.org/panel/1.2.1/dist/wheels/bokeh-3.1.1-py3-none-any.whl failed with status 403:
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "_pyodide/_base.py", line 540, in eval_code_async
File "_pyodide/_base.py", line 365, in run_async
File "<exec>", line 3, in <module>
File "micropip/_micropip.py", line 576, in install
File "micropip/_micropip.py", line 342, in gather_requirements
File "micropip/_micropip.py", line 355, in add_requirement
File "micropip/_micropip.py", line 470, in add_wheel
File "micropip/_micropip.py", line 176, in download
File "micropip/_micropip.py", line 168, in _fetch_bytes
ValueError: Can't fetch wheel from 'https://cdn.holoviz.org/panel/1.2.1/dist/wheels/bokeh-3.1.1-py3-none-any.whl'. One common reason for this is when the server blocks Cross-Origin Resource Sharing (CORS). Check if the server is sending the correct 'Access-Control-Allow-Origin' header.
Here is pyodide/script.js:
importScripts("https://cdn.jsdelivr.net/pyodide/v0.24.1/full/pyodide.js");
function sendPatch(patch, buffers, msg_id) {
self.postMessage({
type: 'patch',
patch: patch,
buffers: buffers
})
}
async function startApplication() {
console.log("Loading pyodide!");
self.postMessage({type: 'status', msg: 'Loading pyodide'})
self.pyodide = await loadPyodide();
self.pyodide.globals.set("sendPatch", sendPatch);
console.log("Loaded!");
await self.pyodide.loadPackage("micropip");
const env_spec = ['https://cdn.holoviz.org/panel/wheels/bokeh-3.3.2-py3-none-any.whl', 'https://cdn.holoviz.org/panel/1.3.6/dist/wheels/panel-1.3.6-py3-none-any.whl', 'pyodide-http==0.2.1', 'scikit-learn', 'xgboost', 'pandas']
for (const pkg of env_spec) {
let pkg_name;
if (pkg.endsWith('.whl')) {
pkg_name = pkg.split('/').slice(-1)[0].split('-')[0]
} else {
pkg_name = pkg
}
self.postMessage({type: 'status', msg: `Installing ${pkg_name}`})
try {
await self.pyodide.runPythonAsync(`
import micropip
await micropip.install('${pkg}');
`);
} catch(e) {
console.log(e)
self.postMessage({
type: 'status',
msg: `Error while installing ${pkg_name}`
});
}
}
console.log("Packages loaded!");
self.postMessage({type: 'status', msg: 'Executing code'})
const code = `
import asyncio
from panel.io.pyodide import init_doc, write_doc
init_doc()
import panel as pn
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
from xgboost import XGBClassifier
pn.extension(sizing_mode="stretch_width", template="fast")
pn.state.template.param.update(site="Panel in the Browser", title="XGBoost Example")
iris_df = load_iris(as_frame=True)
trees = pn.widgets.IntSlider(start=2, end=30, name="Number of trees")
def pipeline(trees):
model = XGBClassifier(max_depth=2, n_estimators=trees)
model.fit(iris_df.data, iris_df.target)
accuracy = round(
accuracy_score(iris_df.target, model.predict(iris_df.data)) * 100, 1
)
return pn.indicators.Number(
name="Test score",
value=accuracy,
format="{value}%",
colors=[(97.5, "red"), (99.0, "orange"), (100, "green")],
)
pn.Column(
"Simple example of training an XGBoost classification model on the small Iris dataset.",
iris_df.data.head(),
"Move the slider below to change the number of training rounds for the XGBoost classifier. The training accuracy score will adjust accordingly.",
trees,
pn.bind(pipeline, trees),
).servable()
await write_doc()
`
try {
const [docs_json, render_items, root_ids] = await self.pyodide.runPythonAsync(code)
self.postMessage({
type: 'render',
docs_json: docs_json,
render_items: render_items,
root_ids: root_ids
})
} catch(e) {
const traceback = `${e}`
const tblines = traceback.split('\n')
self.postMessage({
type: 'status',
msg: tblines[tblines.length-2]
});
throw e
}
}
self.onmessage = async (event) => {
const msg = event.data
if (msg.type === 'rendered') {
self.pyodide.runPythonAsync(`
from panel.io.state import state
from panel.io.pyodide import _link_docs_worker
_link_docs_worker(state.curdoc, sendPatch, setter='js')
`)
} else if (msg.type === 'patch') {
self.pyodide.globals.set('patch', msg.patch)
self.pyodide.runPythonAsync(`
state.curdoc.apply_json_patch(patch.to_py(), setter='js')
`)
self.postMessage({type: 'idle'})
} else if (msg.type === 'location') {
self.pyodide.globals.set('location', msg.location)
self.pyodide.runPythonAsync(`
import json
from panel.io.state import state
from panel.util import edit_readonly
if state.location:
loc_data = json.loads(location)
with edit_readonly(state.location):
state.location.param.update({
k: v for k, v in loc_data.items() if k in state.location.param
})
`)
}
}
startApplication()
Interesting. Is it possible that your browser is caching the app? Could you try in a incognito window?
Success!! Seems to work fine in incognito window.
I'm using Safari Version 17.2.1 (19617.1.17.11.12)
Okay, yes, you have to be quite cognizant of the browser caching here, especially when you're using the pyodide-worker convert target because it'll cache the worker script. We should probably add an warning admonition to the docs about this.
Right on. Indeed, I did do this:
panel convert script.py --to pyodide-worker --out pyodide
probably the wrong place for this question, but any suggestion as to what would I need to clear from my browser cache? I had a look but it was not immediately clear to me what to delete, and I was not sure I wanted to delete everything.
I really like panel, very useful package!