-
-
Notifications
You must be signed in to change notification settings - Fork 525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add panel-lite-editor #5812
Add panel-lite-editor #5812
Conversation
@@ -0,0 +1,24 @@ | |||
<!DOCTYPE html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI. This is the document iframe
startswith. Currently its set via the src
attribute. Instead of serving this externally, we should see if we could insert it via the srcdoc
attribute. I have not tried with this specific document. But I've tried the srcdoc
attribute with another doc in #4279 and could not get it working.
@@ -0,0 +1,26 @@ | |||
<!DOCTYPE html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo
- Make it easy for Panel, awesome-panel and any user to host a Panel
panel-lite-editor
containing some examples.- Style the editor
- Put the
panel-lite-editor
in an easy to use js library that can be loaded from a CDN. - Make it possible to provide a dictionary of examples to the
panel-lite-lite
editor - Make it possible to run the
panel-lite-editor
as a PanelPanelLiteEditor
widget. - Make it possible to toggle the editor part such that you can display the result but users can click some button and editor the code to update the result.
- Add a console to make it easier to understand what goes on.
const appContainer = "app-container" | ||
const codeEditor = "code-editor" | ||
|
||
const welcomeExample=`\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo
- Refactor the examples to an external
panel-lite-examples.json
orpanel-lite-examples.js
file.
pn.pane.Perspective(df, width=1000).servable() | ||
` | ||
|
||
const fastTemplateExample=`\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo:
Get the fastTemplateExample
working
- When rendering the template I see
Error raised while processing Document events: Error: reference ... isn't known
. See panel convert: Error raised while processing Document events: Error: reference ... isn't known #5830 - Clicking button raises an exception `ModuleNotFoundError: no module named 'tornado'.
- I can only run this example once then I can run no other example. See Make Pyodide init_doc + write_doc idempotent #5810
- script_to_html not working in pyodide when input is containing template #5831
- I work around it here by setting
bk_settings.simple_ids.set_value(True)
.
- I work around it here by setting
- I have seen this example render in different ways. For example sometimes there is an extra button in the header. Solved by not prerendering.
ModuleNotFoundError: no module named 'tornado'
Uncaught PythonError: Traceback (most recent call last):
File "/lib/python3.11/site-packages/panel/io/pyodide.py", line 255, in jssync
pydoc.apply_json_patch(json_patch.to_py(), setter='js')
File "/lib/python3.11/site-packages/bokeh/document/document.py", line 391, in apply_json_patch
DocumentPatchedEvent.handle_event(self, event, setter)
File "/lib/python3.11/site-packages/bokeh/document/events.py", line 245, in handle_event
event_cls._handle_event(doc, event)
File "/lib/python3.11/site-packages/bokeh/document/events.py", line 280, in _handle_event
cb(event.msg_data)
File "/lib/python3.11/site-packages/bokeh/document/callbacks.py", line 390, in trigger_event
model._trigger_event(event)
File "/lib/python3.11/site-packages/bokeh/util/callback_manager.py", line 113, in _trigger_event
self.document.callbacks.notify_event(cast(Model, self), event, invoke)
File "/lib/python3.11/site-packages/bokeh/document/callbacks.py", line 260, in notify_event
invoke_with_curdoc(doc, callback_invoker)
File "/lib/python3.11/site-packages/bokeh/document/callbacks.py", line 443, in invoke_with_curdoc
return f()
^^^
File "/lib/python3.11/site-packages/bokeh/util/callback_manager.py", line 109, in invoke
cast(EventCallbackWithEvent, callback)(event)
File "/lib/python3.11/site-packages/panel/reactive.py", line 494, in _server_event
self._comm_event(doc, event)
File "/lib/python3.11/site-packages/panel/reactive.py", line 481, in _comm_event
state._handle_exception(e)
File "/lib/python3.11/site-packages/panel/io/state.py", line 441, in _handle_exception
raise exception
File "/lib/python3.11/site-packages/panel/reactive.py", line 479, in _comm_event
self._process_bokeh_event(doc, event)
File "/lib/python3.11/site-packages/panel/reactive.py", line 413, in _process_bokeh_event
state._busy_counter += 1
^^^^^^^^^^^^^^^^^^^
File "/lib/python3.11/site-packages/param/parameterized.py", line 525, in _f
instance_param.__set__(obj, val)
File "/lib/python3.11/site-packages/param/parameterized.py", line 527, in _f
return f(self, obj, val)
^^^^^^^^^^^^^^^^^
File "/lib/python3.11/site-packages/param/parameters.py", line 542, in __set__
super().__set__(obj,val)
File "/lib/python3.11/site-packages/param/parameterized.py", line 527, in _f
return f(self, obj, val)
^^^^^^^^^^^^^^^^^
File "/lib/python3.11/site-packages/param/parameterized.py", line 1545, in __set__
obj.param._call_watcher(watcher, event)
File "/lib/python3.11/site-packages/param/parameterized.py", line 2486, in _call_watcher
self_._execute_watcher(watcher, (event,))
File "/lib/python3.11/site-packages/param/parameterized.py", line 2468, in _execute_watcher
watcher.fn(*args, **kwargs)
File "/lib/python3.11/site-packages/param/parameterized.py", line 781, in _sync_caller
return function()
^^^^^^^^^^
File "/lib/python3.11/site-packages/param/depends.py", line 41, in _depends
return func(*args, **kw)
^^^^^^^^^^^^^^^^^
File "/lib/python3.11/site-packages/panel/io/state.py", line 273, in _update_busy_counter
self.busy = self._busy_counter >= 1
^^^^^^^^^
File "/lib/python3.11/site-packages/param/parameterized.py", line 525, in _f
instance_param.__set__(obj, val)
File "/lib/python3.11/site-packages/param/parameterized.py", line 527, in _f
return f(self, obj, val)
^^^^^^^^^^^^^^^^^
File "/lib/python3.11/site-packages/param/parameterized.py", line 1545, in __set__
obj.param._call_watcher(watcher, event)
File "/lib/python3.11/site-packages/param/parameterized.py", line 2486, in _call_watcher
self_._execute_watcher(watcher, (event,))
File "/lib/python3.11/site-packages/param/parameterized.py", line 2468, in _execute_watcher
watcher.fn(*args, **kwargs)
File "/lib/python3.11/site-packages/param/parameterized.py", line 781, in _sync_caller
return function()
^^^^^^^^^^
File "/lib/python3.11/site-packages/param/depends.py", line 41, in _depends
return func(*args, **kw)
^^^^^^^^^^^^^^^^^
File "/lib/python3.11/site-packages/panel/io/state.py", line 278, in _update_busy
indicator.value = self.busy
^^^^^^^^^^^^^^^
File "/lib/python3.11/site-packages/param/parameterized.py", line 525, in _f
instance_param.__set__(obj, val)
File "/lib/python3.11/site-packages/param/parameterized.py", line 527, in _f
return f(self, obj, val)
^^^^^^^^^^^^^^^^^
File "/lib/python3.11/site-packages/param/parameterized.py", line 1545, in __set__
obj.param._call_watcher(watcher, event)
File "/lib/python3.11/site-packages/param/parameterized.py", line 2486, in _call_watcher
self_._execute_watcher(watcher, (event,))
File "/lib/python3.11/site-packages/param/parameterized.py", line 2468, in _execute_watcher
watcher.fn(*args, **kwargs)
File "/lib/python3.11/site-packages/panel/reactive.py", line 374, in _param_change
self._apply_update(named_events, properties, model, ref)
File "/lib/python3.11/site-packages/panel/reactive.py", line 307, in _apply_update
doc.add_next_tick_callback(cb)
File "/lib/python3.11/site-packages/bokeh/document/document.py", line 268, in add_next_tick_callback
from ..server.callbacks import NextTickCallback
File "/lib/python3.11/site-packages/bokeh/server/callbacks.py", line 29, in <module>
from ..util.tornado import _CallbackGroup
File "/lib/python3.11/site-packages/bokeh/util/tornado.py", line 37, in <module>
import tornado
ModuleNotFoundError: No module named 'tornado'
at new_error (pyodide.asm.js:9:12519)
at VM17 pyodide.asm.wasm:1:1411112
at VM17 pyodide.asm.wasm:1:1411373
at Module._pythonexc2js (pyodide.asm.js:9:640895)
at Module.callPyObjectKwargs (pyodide.asm.js:9:81856)
at Module.callPyObject (pyodide.asm.js:9:82066)
at Function.apply (pyodide.asm.js:9:97147)
at Object.apply (pyodide.asm.js:9:95381)
at S._trigger_on_change (VM621 bokeh-3.3.0.min.js:165:4949)
at z.send_event (VM621 bokeh-3.3.0.min.js:165:408)
at a._process_event (VM621 bokeh-3.3.0.min.js:215:892)
at z.trigger (VM621 bokeh-3.3.0.min.js:165:545)
at a.trigger_event (VM621 bokeh-3.3.0.min.js:215:987)
at r.click (VM623 bokeh-widgets-3.3.0.min.js:56:117)
at HTMLButtonElement.<anonymous> (VM623 bokeh-widgets-3.3.0.min.js:46:898)
new_error @ pyodide.asm.js:9
$wrap_exception @ VM17 pyodide.asm.wasm:1
$pythonexc2js @ VM17 pyodide.asm.wasm:1
Module._pythonexc2js @ pyodide.asm.js:9
Module.callPyObjectKwargs @ pyodide.asm.js:9
Module.callPyObject @ pyodide.asm.js:9
apply @ pyodide.asm.js:9
apply @ pyodide.asm.js:9
_trigger_on_change @ VM621 bokeh-3.3.0.min.js:165
send_event @ VM621 bokeh-3.3.0.min.js:165
_process_event @ VM621 bokeh-3.3.0.min.js:215
trigger @ VM621 bokeh-3.3.0.min.js:165
trigger_event @ VM621 bokeh-3.3.0.min.js:215
click @ VM623 bokeh-widgets-3.3.0.min.js:56
(anonymous) @ VM623 bokeh-widgets-3.3.0.min.js:46
` | ||
|
||
// See https://github.com/holoviz/panel/blob/8579e5cf322604e61b95bb1e10dcc57466298df1/panel/io/convert.py#L87 | ||
const pyoidideScript = ` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI. We need to override the PYODIDE_SCRIPT
to
- not reload pyodide, micropip and python packages
- listen to a message for the parent window to run some new code.
const pyoidideScript = ` | ||
<script type="text/javascript"> | ||
async function main() { | ||
let envSpec = [{{ env_spec }}] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI. I check if python packages have already been loaded before loading them again.
] | ||
await window.micropip.install(window.envSpec) | ||
// Todo: https://github.com/holoviz/panel/issues/5811 | ||
window.envSpec = window.envSpec.concat(["panel", "bokeh", "datetime", "random"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo
- make sure
find_requirements
do not finddatetime
orrandom
#find_requirements includes datetime and random #5811.
from panel.io.convert import script_to_html | ||
|
||
code = \"\"\" | ||
${fixPanel} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo:
- Allow
srcdoc
Add support for iframe srcdoc to Location #5774. - Remove
fixPanel
when fix released..
try: | ||
html, _ = script_to_html(file) | ||
except Exception as ex: | ||
html = f"Exception: {ex}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo
- Add much better error handling.
print(ex) | ||
|
||
|
||
return html.replace("v0.23.4", "v0.24.1") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo
- Get Panel updated to use latest version of Pyodide
- Remove
.replace
when released.
|
||
async function runCode(code){ | ||
// Todo: panel.io.convert.find_requirements does not find these? | ||
await installIfMissing(code, 'plotly') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo:
- Get
plotly
andmatplotlib
provided by{{ env_spec }}
. It does not when running the examples.- I've not been able to reproduce this outside this application.
await runCode(event.data) | ||
} | ||
|
||
window.handleMessage = handleMessage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo:
- Remove
window.handleMessage
if possible.
<div id="loading-spinner" style="width:100%">Loading Pyodide...</div> | ||
<script> | ||
async function main(){ | ||
window.pyodide = await loadPyodideAndPackages(jsglobals=window) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo
- Load and run pyodide as efficiently as possible. Probably using service worker.
<body> | ||
<img src="https://panel.holoviz.org/_static/logo_horizontal_light_theme.png" style="height:50px"></img></br> | ||
<span>Code Editor</span><br/> | ||
<textarea id="code-editor" style="height:200px;width:800px"></textarea><br/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo
- Run code on
CTRL+Save
.
@@ -0,0 +1,131 @@ | |||
const appContainer = "app-container" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo
Add more features
- Ability to add list of requirements
- Ability to add list of environment variables. For example
OPENAI_API_KEY
. The environment variables should be added toos.environ
. - Separate
PanelLiteEditor
andPanelLiteExamples
. You might want to use thePanelLiteEditor
seperately. - Add ability to hide
PanelLiteEditor
for example if embedded on web page. - Add better code editor. Like Ace or Monaco.
- Layout Examples, Editor and App components in grid that orients it self nicely depending on screen size.
- Add console to editor.
Maybe
- Support multiple files.
- Add linting via
jedi
. See https://github.com/maxwrlr/monaco-python. - Add black autoformatting via https://ryanking13.github.io/black-playground-pyodide/.
- Add chat interface as https://aijs.io/editor?userId=cz17TtyVkAcSHjvSaag1RO3ry5L2&project=1698954552496_PythonTemplate
pn.pane.Matplotlib(fig0, dpi=144).servable() | ||
` | ||
|
||
const perspectiveExample=` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo
- Fix sporadic
pyodide.ffi.JsException: Error: Error rendering Bokeh model: could not find ... HTML tag
- I've experienced this when click my way through the examples from left to right.
pyodide.ffi.JsException: ... could not find ... HTML tag`
Uncaught (in promise) PythonError: Traceback (most recent call last):
File "/lib/python311.zip/_pyodide/_base.py", line 571, in eval_code_async
await CodeRunner(
File "/lib/python311.zip/_pyodide/_base.py", line 396, in run_async
await coroutine
File "<exec>", line 45, in <module>
File "/lib/python3.11/site-packages/panel/io/pyodide.py", line 519, in write_doc
views = await Bokeh.embed.embed_items(JSON.parse(docs_json), JSON.parse(render_items))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pyodide.ffi.JsException: Error: Error rendering Bokeh model: could not find #e97f9bbb-8b5e-42a7-b685-b355a0ee7b92 HTML tag
at new_error (pyodide.asm.js:9:12519)
at pyodide.asm.wasm:0x158827
at pyodide.asm.wasm:0x15fcd5
at _PyCFunctionWithKeywords_TrampolineCall (pyodide.asm.js:9:123052)
at pyodide.asm.wasm:0x1a3091
at pyodide.asm.wasm:0x289e4d
at pyodide.asm.wasm:0x1e3f77
at pyodide.asm.wasm:0x1a3579
at pyodide.asm.wasm:0x1a383a
at pyodide.asm.wasm:0x1a38dc
at pyodide.asm.wasm:0x2685c5
at pyodide.asm.wasm:0x26e3d0
at pyodide.asm.wasm:0x1a3a04
at pyodide.asm.wasm:0x1a3694
at pyodide.asm.wasm:0x15f45e
at Module.callPyObjectKwargs (pyodide.asm.js:9:81732)
at Module.callPyObject (pyodide.asm.js:9:82066)
at wrapper (pyodide.asm.js:9:58562)
@@ -0,0 +1,159 @@ | |||
const welcome=`\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todo
- Wrap this into an easy to use class
PanelLiteIframe
that takescode
,requirements
and either settings as arguments. It creates the iframe and provides arun
function to update thecode
and other settings.
Maybe
- Enable rendering non-Panel components by wrapping the last output in a
pn.panel
?
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #5812 +/- ##
==========================================
+ Coverage 72.37% 82.35% +9.98%
==========================================
Files 290 290
Lines 42235 42235
==========================================
+ Hits 30566 34783 +4217
+ Misses 11669 7452 -4217
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
…panel-lite-playground
Like it! But would it not need to support some form of Intellisense to be easier to use? As for code <-> output, @ahuang11 made a great example with code-editor + Panel / Holoviz + AI that does something similar. Would that be of use? |
I believe this has been superseeded by time. For now I hope something really easy to use shows up based on the best ideas from PY.CAFE and PY.CAFE
Py-Script
Besides the a Panel editor html element I hope FYI. @WebReflection |
Implements #5768. In #5769 I made a lot of experiments. I learned that to create a general panel-lite playground we need to
iframe
withpyodide
loaded oncehtml
template from the code on the fly to support js extensions and templatesVideo
panel-lite-editor.mp4
Resources