Compare commits

..

5 Commits

Author SHA1 Message Date
Peter W
39725c1384 Use latest instead 2023-11-21 11:11:57 -06:00
Peter W
48c5158b46 Fix 404 in main README.md 2023-11-21 11:09:48 -06:00
Antonio Cuni
4b89c84692 use UTC time (#1859) 2023-11-15 16:00:09 +01:00
Antonio Cuni
df68449b82 Improve README and and mention the community calls (#1858)
Improve the readme in two ways:

- remove the mention to <py-repl>, and shows a quick summary of the various ways of running Python code

- add a link to the google calendar which contains the community calls
2023-11-15 12:10:52 +01:00
Andrea Giammarchi
48e3383f66 Fix #1841 - Provide a better error when input is used (#1857) 2023-11-14 15:25:17 +01:00
7 changed files with 77 additions and 162 deletions

View File

@@ -4,9 +4,9 @@
### Summary ### Summary
PyScript is a framework that allows users to create rich Python applications in the browser using HTML's interface and the power of [Pyodide](https://pyodide.org/en/stable/), [WASM](https://webassembly.org/), and modern web technologies. PyScript is a framework that allows users to create rich Python applications in the browser using HTML's interface and the power of [Pyodide](https://pyodide.org/en/stable/), [MicroPython](https://micropython.org/) and [WASM](https://webassembly.org/), and modern web technologies.
To get started see the [getting started tutorial](docs/tutorials/getting-started.md). To get started see the [getting started tutorial](https://pyscript.github.io/docs/latest/beginning-pyscript/).
For examples see [here](examples). For examples see [here](examples).
@@ -16,7 +16,7 @@ PyScript is a meta project that aims to combine multiple open technologies into
## Try PyScript ## Try PyScript
To try PyScript, import the appropriate pyscript files into the `<head>` tag of your html page with: To try PyScript, import the appropriate pyscript files into the `<head>` tag of your html page:
```html ```html
<head> <head>
@@ -29,14 +29,25 @@ To try PyScript, import the appropriate pyscript files into the `<head>` tag of
src="https://pyscript.net/releases/2023.11.1/core.js" src="https://pyscript.net/releases/2023.11.1/core.js"
></script> ></script>
</head> </head>
<body>
<script type="py" terminal>
from pyscript import display
display("Hello World!") # this goes to the DOM
print("Hello terminal") # this goes to the terminal
</script>
</body>
``` ```
You can then use PyScript components in your html page. PyScript currently implements the following elements: You can then use PyScript components in your html page. PyScript currently offers various ways of running Python code:
- `<py-script>`: can be used to define python code that is executable within the web page. The element itself is not rendered to the page and is only used to add logic - `<script type="py">`: can be used to define python code that is executable within the web page.
- `<py-repl>`: creates a REPL component that is rendered to the page as a code editor and allows users to write executable code - `<script type="py" src="hello.py">`: same as above, but the python source is fetched from the given URL.
- `<script type="py" terminal>`: same as above, but also creates a terminal where to display stdout and stderr (e.g., the output of `print()`); `input()` does not work.
- `<script type="py" terminal worker>`: run Python inside a web worker: the terminal if fully functional and `input()` works.
- `<py-script>`: same as `<script type="py">`, but it is not recommended because if the code contains HTML tags, they could be parsed wrongly.
- `<script type="mpy">`: same as above but use MicroPython instead of Python.
Check out the [the examples directory](examples) folder for more examples on how to use it, all you need to do is open them in Chrome. Check out the [official docs](https://docs.pyscript.net) for more detailed documentation.
## How to Contribute ## How to Contribute
@@ -44,6 +55,17 @@ Read the [contributing guide](CONTRIBUTING.md) to learn about our development pr
Check out the [developing process](https://docs.pyscript.net/latest/contributing) documentation for more information on how to setup your development environment. Check out the [developing process](https://docs.pyscript.net/latest/contributing) documentation for more information on how to setup your development environment.
## Community calls and events
Every Tuesday at 15:30 UTC there is the _PyScript Community Call_ on zoom, where we can talk about PyScript development in the open. Most of the maintainers regularly participate in the call, and everybody is welcome to join.
Every other Thursday at 16:00 UTC there is the _PyScript FUN_ call: this is a call in which everybody is encouraged to show what they did with PyScript.
For more details on how to join the calls and up to date schedule, consult the official calendar:
- [Google calendar](https://calendar.google.com/calendar/u/0/embed?src=d3afdd81f9c132a8c8f3290f5cc5966adebdf61017fca784eef0f6be9fd519e0@group.calendar.google.com&ctz=UTC) in UTC time;
- [iCal format](https://calendar.google.com/calendar/ical/d3afdd81f9c132a8c8f3290f5cc5966adebdf61017fca784eef0f6be9fd519e0%40group.calendar.google.com/public/basic.ics).
## Resources ## Resources
- [Official docs](https://docs.pyscript.net) - [Official docs](https://docs.pyscript.net)

View File

@@ -45,6 +45,19 @@ export const createFunction = (self, name) => {
const SetFunction = typedSet({ typeof: "function" }); const SetFunction = typedSet({ typeof: "function" });
const SetString = typedSet({ typeof: "string" }); const SetString = typedSet({ typeof: "string" });
const inputFailure = `
import builtins
def input(prompt=""):
raise Exception("\\n ".join([
"input() doesn't work when PyScript runs in the main thread.",
"Consider using the worker attribute: https://docs.pyscript.net/2023.11.1/user-guide/workers/"
]))
builtins.input = input
del builtins
del input
`;
export const hooks = { export const hooks = {
main: { main: {
/** @type {Set<function>} */ /** @type {Set<function>} */
@@ -60,7 +73,7 @@ export const hooks = {
/** @type {Set<function>} */ /** @type {Set<function>} */
onAfterRunAsync: new SetFunction(), onAfterRunAsync: new SetFunction(),
/** @type {Set<string>} */ /** @type {Set<string>} */
codeBeforeRun: new SetString(), codeBeforeRun: new SetString([inputFailure]),
/** @type {Set<string>} */ /** @type {Set<string>} */
codeBeforeRunAsync: new SetString(), codeBeforeRunAsync: new SetString(),
/** @type {Set<string>} */ /** @type {Set<string>} */

View File

@@ -0,0 +1,21 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PyScript Next</title>
<script>
addEventListener("py:ready", console.log);
</script>
<link rel="stylesheet" href="../dist/core.css">
<script type="module" src="../dist/core.js"></script>
</head>
<body>
<py-script>
input("what's your name?")
</py-script>
<mpy-script>
input("what's your name?")
</mpy-script>
</body>
</html>

View File

@@ -1,78 +0,0 @@
import json
import js
import panel as pn
from js import JSON
from panel.io.pyodide import init_doc, write_doc
from polyscript import xworker
from pyodide.ffi import create_once_callable, create_proxy, to_js
from pyscript import document, window
js.document = document
init_doc()
print("Hello from panel.py")
slider = pn.widgets.FloatSlider(start=0, end=10, name="Amplitude")
def callback(new):
print(f"Amplitude is: {new}")
return f"Amplitude is: {new}"
print("made this far...")
pn.Row(slider, pn.bind(callback, slider)).servable(target="simple_app")
# ------ END OF PANEL CODE ------
docs_json_str, render_items_str, root_ids_str = await write_doc()
docs_json = JSON.parse(docs_json_str) # .as_object_map()
# render_items = to_js(JSON.parse(render_items_str), depth=-1, pyproxies=None, create_pyproxies=False, dict_converter=js.Object.fromEntries)#.as_object_map()
root_ids = JSON.parse(root_ids_str) # .as_object_map()
# docs_json = json.loads(docs_json_str)
render_items = json.loads(render_items_str)
# root_ids = json.loads(root_ids_str)
print(type(render_items))
root_elements = document.querySelectorAll("[data-root-id]")
data_roots = []
for el in root_elements:
el.innerHTML = ""
data_roots.append([el.getAttribute("data-root-id"), el.id])
roots = {root_ids[i]: root for i, root in enumerate(data_roots)}
print("Quick check")
print(roots)
print(root_ids)
print(render_items)
# render_items[0]['roots'] = roots
# render_items[0]['root_ids'] = root_ids
# render_items[0].roots = to_js(roots)
# render_items[0].root_ids = to_js(root_ids)
# print(roots)
# print(data_roots)
print(docs_json)
print(render_items)
print("here....")
# views = await window.Bokeh.embed.embed_items(to_js(docs_json), to_js(render_items))
views = await window.Bokeh.embed.embed_items(
docs_json, # to_js(docs_json, depth=-1, pyproxies=None, create_pyproxies=False, dict_converter=js.Object.fromEntries),
to_js(
render_items,
depth=-1,
pyproxies=None,
create_pyproxies=False,
dict_converter=js.Object.fromEntries,
),
)
# Experiments back to main thread
# await xworker.sync.render_full(docs_json_str, render_items_str, root_ids_str)
print("made it to the end")
print(docs_json)

View File

@@ -1,5 +0,0 @@
packages = [
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
"numpy",
"panel==0.14.1"
]

View File

@@ -1,71 +0,0 @@
<html>
<head>
<title>Panel Example</title>
<meta charset="iso-8859-1" />
<link rel="icon" type="image/x-icon" href="./favicon.png" />
</head>
<body>
<section class="pyscript">
<div id="simple_app"></div>
<py-tutor>
<script defer src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.js"></script>
<script defer src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js"></script>
<script defer src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.14.1/dist/panel.min.js"></script>
<script type="module" src="../../core.js"></script>
<!-- <script
type="module"
src="https://esm.sh/@pyscript/core@latest/core.js"
></script> -->
<script type="py" worker="./panel.py" config="./panel.toml" async></script>
<!-- Code below borrowed for reference from example working on polyscript directly -->
<!-- <script type="micropython">
from pyscript import PyWorker
import json
import js
w = PyWorker('./panel.py', **{'type': 'pyodide', 'async': True, 'config': './panel.toml'})
# xworker.window made the following completely unnecessary
document = js.document
async def render_full(docs_json_str, render_items_str, root_ids_str):
docs_json = json.loads(docs_json_str)
render_items = json.loads(render_items_str)
root_ids = json.loads(root_ids_str)
print(type(render_items))
root_elements = document.querySelectorAll('[data-root-id]')
data_roots = []
for el in root_elements:
el.innerHTML = ''
data_roots.append([el.getAttribute('data-root-id'), el.id])
roots = {root_ids[i]: root for i, root in enumerate(data_roots)}
print("Quick check")
render_items[0]['roots'] = roots
render_items[0]['root_ids'] = root_ids
print("here....")
views = await js.Bokeh.embed.embed_items(docs_json, render_items)
def render(docs_json, render_items):
print(f"GOT DATA: {docs_json}")
print(f"GOT ITEMS: {render_items}")
await js.Bokeh.embed.embed_items(json.loads(docs_json), json.loads(render_items))
# views = await xworker.window.Bokeh.embed.embed_items(create_proxy(docs_json), create_proxy(render_items))
w.sync.render = render
w.sync.render_full = render_full
</script> -->
</py-tutor>
</section>
</body>
</html>

View File

@@ -93,6 +93,19 @@ class TestBasic(PyScriptTest):
) )
assert self.console.log.lines[-1] == "hello pyscript" assert self.console.log.lines[-1] == "hello pyscript"
@only_main
def test_input_exception(self):
self.pyscript_run(
"""
<script type="py">
input("what's your name?")
</script>
"""
)
self.check_py_errors(
"Exception: input() doesn't work when PyScript runs in the main thread."
)
@skip_worker("NEXT: exceptions should be displayed in the DOM") @skip_worker("NEXT: exceptions should be displayed in the DOM")
def test_python_exception(self): def test_python_exception(self):
self.pyscript_run( self.pyscript_run(