mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-20 02:37:41 -05:00
Compare commits
8 Commits
2023.11.1
...
fix-404-ge
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39725c1384 | ||
|
|
48c5158b46 | ||
|
|
4b89c84692 | ||
|
|
df68449b82 | ||
|
|
48e3383f66 | ||
|
|
e750fa7393 | ||
|
|
5a15199a3a | ||
|
|
1801472fc4 |
36
README.md
36
README.md
@@ -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)
|
||||||
|
|||||||
@@ -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>} */
|
||||||
|
|||||||
27
pyscript.core/src/plugins/deprecations-manager.js
Normal file
27
pyscript.core/src/plugins/deprecations-manager.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// PyScript Derepcations Plugin
|
||||||
|
import { hooks } from "../core.js";
|
||||||
|
import { notify } from "./error.js";
|
||||||
|
|
||||||
|
// react lazily on PyScript bootstrap
|
||||||
|
hooks.main.onReady.add(checkDeprecations);
|
||||||
|
hooks.main.onWorker.add(checkDeprecations);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that there are no scripts loading from pyscript.net/latest
|
||||||
|
*/
|
||||||
|
function checkDeprecations() {
|
||||||
|
const scripts = document.querySelectorAll("script");
|
||||||
|
for (const script of scripts) checkLoadingScriptsFromLatest(script.src);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if src being loaded from pyscript.net/latest and display a notification if true
|
||||||
|
* * @param {string} src
|
||||||
|
*/
|
||||||
|
function checkLoadingScriptsFromLatest(src) {
|
||||||
|
if (/\/pyscript\.net\/latest/.test(src)) {
|
||||||
|
notify(
|
||||||
|
"Loading scripts from latest is deprecated and will be removed soon. Please use a specific version instead.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,8 +6,6 @@ from typing import Any
|
|||||||
from pyodide.ffi import JsProxy
|
from pyodide.ffi import JsProxy
|
||||||
from pyscript import display, document, window
|
from pyscript import display, document, window
|
||||||
|
|
||||||
# from pyscript import when as _when
|
|
||||||
|
|
||||||
alert = window.alert
|
alert = window.alert
|
||||||
|
|
||||||
|
|
||||||
@@ -177,9 +175,6 @@ class Element(BaseElement):
|
|||||||
def show_me(self):
|
def show_me(self):
|
||||||
self._js.scrollIntoView()
|
self._js.scrollIntoView()
|
||||||
|
|
||||||
def when(self, event, handler):
|
|
||||||
document.when(event, selector=self)(handler)
|
|
||||||
|
|
||||||
|
|
||||||
class StyleProxy(dict):
|
class StyleProxy(dict):
|
||||||
def __init__(self, element: Element) -> None:
|
def __init__(self, element: Element) -> None:
|
||||||
@@ -319,8 +314,8 @@ class PyDom(BaseElement):
|
|||||||
self.body = Element(document.body)
|
self.body = Element(document.body)
|
||||||
self.head = Element(document.head)
|
self.head = Element(document.head)
|
||||||
|
|
||||||
def create(self, type_, parent=None, classes=None, html=None):
|
def create(self, type_, classes=None, html=None):
|
||||||
return super().create(type_, is_child=False)
|
return super().create(type_, is_child=False, classes=classes, html=html)
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
if isinstance(key, int):
|
if isinstance(key, int):
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
def on_click(event):
|
def on_click(event):
|
||||||
print(f"Hello from Python! {dt.now()}")
|
print(f"Hello from Python! {dt.now()}")
|
||||||
display(f"Hello from Python! {dt.now()}", append=False, target='eresult')
|
display(f"Hello from Python! {dt.now()}", append=False, target='result')
|
||||||
|
|
||||||
add_event_listener(element, "click", on_click)
|
add_event_listener(element, "click", on_click)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
21
pyscript.core/test/input.html
Normal file
21
pyscript.core/test/input.html
Normal 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>
|
||||||
@@ -545,7 +545,9 @@ class PyScriptTest:
|
|||||||
- wait until pyscript has been fully loaded
|
- wait until pyscript has been fully loaded
|
||||||
"""
|
"""
|
||||||
doc = self._pyscript_format(
|
doc = self._pyscript_format(
|
||||||
snippet, execution_thread=self.execution_thread, extra_head=extra_head
|
snippet,
|
||||||
|
execution_thread=self.execution_thread,
|
||||||
|
extra_head=extra_head,
|
||||||
)
|
)
|
||||||
if not wait_for_pyscript and timeout is not None:
|
if not wait_for_pyscript and timeout is not None:
|
||||||
raise ValueError("Cannot set a timeout if wait_for_pyscript=False")
|
raise ValueError("Cannot set a timeout if wait_for_pyscript=False")
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -1,13 +1,35 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from .support import PyScriptTest
|
from .support import PyScriptTest, skip_worker
|
||||||
|
|
||||||
pytest.skip(reason="NEXT: Restore the banner", allow_module_level=True)
|
|
||||||
|
|
||||||
|
|
||||||
class TestWarningsAndBanners(PyScriptTest):
|
class TestWarningsAndBanners(PyScriptTest):
|
||||||
# Test the behavior of generated warning banners
|
# Test the behavior of generated warning banners
|
||||||
|
|
||||||
|
def test_deprecate_loading_scripts_from_latest(self):
|
||||||
|
# Use a script tag with an invalid output attribute to generate a warning, but only one
|
||||||
|
self.pyscript_run(
|
||||||
|
"""
|
||||||
|
<script type="py">
|
||||||
|
print("whatever..")
|
||||||
|
</script>
|
||||||
|
""",
|
||||||
|
extra_head='<script type="ignore-me" src="https://pyscript.net/latest/any-path-triggers-the-warning-anyway.js"></script>',
|
||||||
|
)
|
||||||
|
|
||||||
|
# wait for the banner to appear (we could have a page.locater call but for some reason
|
||||||
|
# the worker takes to long to render on CI, since it's a test we can afford 2 calls)
|
||||||
|
loc = self.page.wait_for_selector(".py-error")
|
||||||
|
assert (
|
||||||
|
loc.inner_text()
|
||||||
|
== "Loading scripts from latest is deprecated and will be removed soon. Please use a specific version instead."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Only one banner should appear
|
||||||
|
loc = self.page.locator(".py-error")
|
||||||
|
assert loc.count() == 1
|
||||||
|
|
||||||
|
@pytest.mark.skip("NEXT: To check if behaviour is consistent with classic")
|
||||||
def test_create_singular_warning(self):
|
def test_create_singular_warning(self):
|
||||||
# Use a script tag with an invalid output attribute to generate a warning, but only one
|
# Use a script tag with an invalid output attribute to generate a warning, but only one
|
||||||
self.pyscript_run(
|
self.pyscript_run(
|
||||||
|
|||||||
1
pyscript.core/types/plugins.d.ts
vendored
1
pyscript.core/types/plugins.d.ts
vendored
@@ -1,4 +1,5 @@
|
|||||||
declare const _default: {
|
declare const _default: {
|
||||||
|
"deprecations-manager": () => Promise<typeof import("./plugins/deprecations-manager.js")>;
|
||||||
error: () => Promise<typeof import("./plugins/error.js")>;
|
error: () => Promise<typeof import("./plugins/error.js")>;
|
||||||
"py-terminal": () => Promise<typeof import("./plugins/py-terminal.js")>;
|
"py-terminal": () => Promise<typeof import("./plugins/py-terminal.js")>;
|
||||||
};
|
};
|
||||||
|
|||||||
1
pyscript.core/types/plugins/deprecations-manager.d.ts
vendored
Normal file
1
pyscript.core/types/plugins/deprecations-manager.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export {};
|
||||||
Reference in New Issue
Block a user