Skip to content

Commit e3c26f1

Browse files
authored
Merge pull request #123 from pyscript/release-notes
Updates around latest changes and docs
2 parents 7521c23 + 1553cbe commit e3c26f1

File tree

10 files changed

+241
-18
lines changed

10 files changed

+241
-18
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ of this repository).
3232
# example of a simple virtual environment
3333
# creation from the root of this project
3434
python -m venv .
35+
./bin/pip install --upgrade setuptools
3536
./bin/pip install -r requirements.txt
3637
```
3738

docs/beginning-pyscript.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ module in the document's `<head>` tag:
112112
<meta charset="utf-8" />
113113
<meta name="viewport" content="width=device-width,initial-scale=1" />
114114
<title>🦜 Polyglot - Piratical PyScript</title>
115-
<link rel="stylesheet" href="https://pyscript.net/releases/2024.5.2/core.css">
116-
<script type="module" src="https://pyscript.net/releases/2024.5.2/core.js"></script>
115+
<link rel="stylesheet" href="https://pyscript.net/releases/2024.6.1/core.css">
116+
<script type="module" src="https://pyscript.net/releases/2024.6.1/core.js"></script>
117117
</head>
118118
<body>
119119

@@ -163,8 +163,8 @@ In the end, our HTML should look like this:
163163
<meta charset="utf-8" />
164164
<meta name="viewport" content="width=device-width,initial-scale=1" />
165165
<title>🦜 Polyglot - Piratical PyScript</title>
166-
<link rel="stylesheet" href="https://pyscript.net/releases/2024.5.2/core.css">
167-
<script type="module" src="https://pyscript.net/releases/2024.5.2/core.js"></script>
166+
<link rel="stylesheet" href="https://pyscript.net/releases/2024.6.1/core.css">
167+
<script type="module" src="https://pyscript.net/releases/2024.6.1/core.js"></script>
168168
</head>
169169
<body>
170170
<h1>Polyglot 🦜 💬 🇬🇧 ➡️ 🏴‍☠️</h1>

docs/faq.md

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,7 @@ automatically install packages for you](user-guide/configuration/#packages).
708708
Yet [packaging can be a complicated beast](#python-packages), so here are some
709709
hints for a painless packaging experience with PyScript.
710710

711-
There are essentially four ways in which a third party package can become
711+
There are essentially five ways in which a third party package can become
712712
available in PyScript.
713713

714714
1. The module is already part of either the Pyodide or MicroPython
@@ -724,9 +724,11 @@ available in PyScript.
724724
3. Reference hosted Python source files, to be included on the file
725725
system, via the [`files` setting](../user-guide/configuration/#files).
726726
4. Create a folder containing the package's files and sub folders, and create
727-
a hosted `.zip` or `.tgz`/`.tar.gz` archive to be decompressed into the file
728-
system (again, via the
727+
a hosted `.zip` or `.tgz`/`.tar.gz`/`.whl` archive to be decompressed into
728+
the file system (again, via the
729729
[`files` setting](../user-guide/configuration/#files)).
730+
5. Provide your own `.whl` package and reference it via a URL in the
731+
`packages = [...]` list.
730732

731733
#### Host a package
732734

@@ -768,7 +770,7 @@ packages onto the Python path:
768770
</script>
769771
```
770772

771-
#### Code archive (`zip`/`tgz`)
773+
#### Code archive (`zip`/`tgz`/`whl`)
772774

773775
Compress all the code you want into an archive (using either either `zip` or
774776
`tgz`/`tar.gz`). Host the resulting archive and use the
@@ -1206,14 +1208,25 @@ js.callback(
12061208
)
12071209
)
12081210
```
1211+
!!! info
1212+
1213+
Thanks to a
1214+
[recent change in Pyodide](https://github.com/pyodide/pyodide/pull/4576),
1215+
such `Map` instances are
1216+
[duck-typed](https://en.wikipedia.org/wiki/Duck_typing) to behave like
1217+
object literals. Conversion may not be needed anymore, and `to_js` may just
1218+
work without the need of the `dict_converter`. Please check.
12091219

1210-
In addition, MicroPython's version of `to_js` takes the opposite approach (for
1220+
MicroPython's version of `to_js` takes the opposite approach (for
12111221
many of the reasons stated above) and converts Python dictionaries to object
12121222
literals instead of `Map` objects.
12131223

12141224
As a result, **the PyScript `pyscript.ffi.to_js` ALWAYS returns a JavaScript
12151225
object literal by default when converting a Python dictionary** no matter if
1216-
you're using Pyodide or MicroPython as your interpreter.
1226+
you're using Pyodide or MicroPython as your interpreter. Furthermore, when
1227+
using MicroPython, because things are closer to idiomatic JavaScript behaviour,
1228+
you may not even need to use `to_js` unless you want to ensure
1229+
cross-interpreter compatibility.
12171230

12181231
#### Caveat
12191232

docs/user-guide/builtins.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,52 @@ from pyscript import sync
571571
sync.hello("PyScript")
572572
```
573573
574+
### `pyscript.py_import`
575+
576+
!!! warning
577+
578+
**This is an experimental feature.**
579+
580+
Feedback and bug reports are welcome!
581+
582+
If you have a lot of Python packages referenced in your configuration, startup
583+
performance may be degraded as these are downloaded.
584+
585+
If a Python package is only needed under certain circumstances, we provide an
586+
asynchronous way to import packages that were not originally referenced in your
587+
configuration.
588+
589+
```html title="A pyscript.py_import example."
590+
<script type="py" async>
591+
from pyscript import py_import
592+
593+
matplotlib, regex, = await py_import("matplotlib", "regex")
594+
595+
print(matplotlib, regex)
596+
</script>
597+
```
598+
599+
The `py_import` call returns an asynchronous tuple containing the Python
600+
modules provided by the packages referenced as string arguments.
601+
602+
### `pyscript.js_import`
603+
604+
If a JavaScript module is only needed under certain circumstances, we provide
605+
an asynchronous way to import packages that were not originally referenced in
606+
your configuration.
607+
608+
```html title="A pyscript.js_import example."
609+
<script type="py" async>
610+
from pyscript import js_import, window
611+
612+
escaper, = await js_import("https://esm.run/html-escaper")
613+
614+
window.console.log(escaper)
615+
```
616+
617+
The `js_import` call returns an asynchronous tuple containing the JavaScript
618+
modules referenced as string arguments.
619+
574620
## HTML attributes
575621
576622
As a convenience, and to ensure backwards compatibility, PyScript allows the

docs/user-guide/editor.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ or `mpy-editor` (for MicroPython), the plugin creates a visual code editor,
1616
with code highlighting and a "run" button to execute the editable code
1717
contained therein in a non-blocking worker.
1818

19+
!!! info
20+
21+
Once clicked, the "run" button will show a spinner until the code is
22+
executed. This may not be visible if the code evaluation completed quickly.
23+
24+
1925
The interpreter is not loaded onto the page until the run button is clicked. By
2026
default each editor has its own independent instance of the specified
2127
interpreter:
@@ -61,6 +67,8 @@ The outcome of these code fragments should look something like this:
6167

6268
Hovering over the Python editor reveals the "run" button.
6369

70+
### Setup
71+
6472
Sometimes you need to create a pre-baked Pythonic context for a shared
6573
environment used by an editor. This need is especially helpful in educational
6674
situations where boilerplate code can be run, with just the important salient
@@ -128,6 +136,43 @@ not expect the same behavior regular *PyScript* elements follow, most notably:
128136
* There is no special reference to the underlying editor instance, while
129137
there is both `script.terminal` or `__terminal__` in the terminal.
130138

139+
## Read / Write / Execute
140+
141+
Sometimes you need to programatically read, write or execute code in an
142+
editor. Once PyScript has started, every py-editor/mpy-editor script tag gets
143+
a `code` accessor attached to it.
144+
145+
```python
146+
from pyscript import document
147+
148+
# Grab the editor script reference.
149+
editor = document.querySelector('#editor')
150+
151+
# Output the live content of the editor.
152+
print(editor.code)
153+
154+
# Update the live content of the editor.
155+
editor.code = """
156+
a = 1
157+
b = 2
158+
print(a + b)
159+
"""
160+
161+
# Evaluate the live code in the editor.
162+
# This could be any arbitrary code to evaluate in the editor's Python context.
163+
editor.process(editor.code)
164+
```
165+
166+
## Configuration
167+
168+
Unlike `<script type="py">` or `<py-script>` (and the `mpy` equivalents), a
169+
PyEditor is not influenced by the presence of `<py-config>` elements in the
170+
page: it requires an explicit `config="..."` attribute.
171+
172+
If a `setup` editor is present, that's the only PyEditor that needs a config.
173+
Any subsequent related editor will reuse the config parsed and bootstrapped for
174+
the `setup` editor.
175+
131176
## Still missing
132177

133178
The PyEditor is currently under active development and refinement, so features

docs/user-guide/first-steps.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ CSS:
2020
<meta charset="UTF-8">
2121
<meta name="viewport" content="width=device-width,initial-scale=1.0">
2222
<!-- PyScript CSS -->
23-
<link rel="stylesheet" href="https://pyscript.net/releases/2024.5.2/core.css">
23+
<link rel="stylesheet" href="https://pyscript.net/releases/2024.6.1/core.css">
2424
<!-- This script tag bootstraps PyScript -->
25-
<script type="module" src="https://pyscript.net/releases/2024.5.2/core.js"></script>
25+
<script type="module" src="https://pyscript.net/releases/2024.6.1/core.js"></script>
2626
</head>
2727
<body>
2828
<!-- your code goes here... -->

docs/user-guide/plugins.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ For example, this will work because all references are contained within the
9999
registered function:
100100

101101
```js
102-
import { hooks } from "https://pyscript.net/releases/2024.5.2/core.js";
102+
import { hooks } from "https://pyscript.net/releases/2024.6.1/core.js";
103103

104104
hooks.worker.onReady.add(() => {
105105
// NOT suggested, just an example!
@@ -113,7 +113,7 @@ hooks.worker.onReady.add(() => {
113113
However, due to the outer reference to the variable `i`, this will fail:
114114

115115
```js
116-
import { hooks } from "https://pyscript.net/releases/2024.5.2/core.js";
116+
import { hooks } from "https://pyscript.net/releases/2024.6.1/core.js";
117117

118118
// NO NO NO NO NO! ☠️
119119
let i = 0;
@@ -146,7 +146,7 @@ the page.
146146

147147
```js title="log.js - a plugin that simply logs to the console."
148148
// import the hooks from PyScript first...
149-
import { hooks } from "https://pyscript.net/releases/2024.5.2/core.js";
149+
import { hooks } from "https://pyscript.net/releases/2024.6.1/core.js";
150150

151151
// The `hooks.main` attribute defines plugins that run on the main thread.
152152
hooks.main.onReady.add((wrap, element) => {
@@ -196,8 +196,8 @@ hooks.worker.onAfterRun.add(() => {
196196
<!-- JS plugins should be available before PyScript bootstraps -->
197197
<script type="module" src="./log.js"></script>
198198
<!-- PyScript -->
199-
<link rel="stylesheet" href="https://pyscript.net/releases/2024.5.2/core.css">
200-
<script type="module" src="https://pyscript.net/releases/2024.5.2/core.js"></script>
199+
<link rel="stylesheet" href="https://pyscript.net/releases/2024.6.1/core.css">
200+
<script type="module" src="https://pyscript.net/releases/2024.6.1/core.js"></script>
201201
</head>
202202
<body>
203203
<script type="mpy">

docs/user-guide/terminal.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,39 @@ terminal automatically become links). Behind the scenes is the example code
150150
shown above, and this approach will work for
151151
[any other addon](https://github.com/xtermjs/xterm.js/tree/master/addons/) you
152152
may wish to use.
153+
154+
### MicroPython
155+
156+
MicroPython has a
157+
[very complete REPL](https://docs.micropython.org/en/latest/reference/repl.html)
158+
already built into it.
159+
160+
* All `Ctrl+X` strokes are handled, including paste mode and kill switches.
161+
* History works out of the box. Access this via the up and down arrows to
162+
view your command history.
163+
* Tab completion works like a charm. Use the `tab` key to see available
164+
variables or objects in `globals`.
165+
* Copy and paste is much improved. This is true for a single terminal entry,
166+
or a
167+
[paste mode](https://docs.micropython.org/en/latest/reference/repl.html#paste-mode)
168+
enabled variant.
169+
170+
As a bonus, the MicroPython terminal works on both the main thread and in
171+
web workers, with the following caveats:
172+
173+
* **Main thread:**
174+
* Calls to the blocking `input` function are delegated to the native browser
175+
based
176+
[prompt](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt)
177+
utility.
178+
* There are no guards against blocking code (e.g. `while True:` loops).
179+
Such blocking code _could freeze your page_.
180+
* **Web worker:**
181+
* Conventional support for the `input` function, without blocking the main
182+
thread.
183+
* Blocking code (e.g. `while True:` loops) does not block the main thread
184+
and your page will remain responsive.
185+
186+
We encourage the usage of `worker` attribute to bootstrap a MicroPython
187+
terminal. But now you have an option to run the terminal in the main thread.
188+
Just remember not to block!

docs/user-guide/workers.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,85 @@ into the DOM and access some `window` based APIs.
146146
and produce unforeseen problematic results**. Remember, with great power
147147
comes great responsibility... and we've given you a bazooka (so please
148148
remember not to shoot yourself in the foot with it).
149+
150+
## Common Use Case
151+
152+
While it is possible to start a MicroPython or Pyodide worker from either
153+
MicroPython or Pyodide running on the main thread, the most common use case
154+
we have encountered is MicroPython on the main thread starting a Pyodide
155+
worker.
156+
157+
Here's how:
158+
159+
**index.html**
160+
```HTML title="Evaluate main.py via MicroPython on the main thread"
161+
<!DOCTYPE html>
162+
<html lang="en">
163+
<head>
164+
<meta charset="utf-8">
165+
<meta name="viewport" content="width=device-width,initial-scale=1">
166+
<!-- PyScript CSS -->
167+
<link rel="stylesheet" href="https://pyscript.net/releases/2024.6.1/core.css">
168+
<!-- This script tag bootstraps PyScript -->
169+
<script type="module" src="https://pyscript.net/releases/2024.6.1/core.js"></script>
170+
<title>PyWorker - mpy bootstrapping pyodide example</title>
171+
<!-- the async attribute is useful but not mandatory -->
172+
<script type="mpy" src="main.py" async></script>
173+
</head>
174+
</html>
175+
```
176+
177+
**main.py**
178+
```Python title="MicroPython's main.py: bootstrapping a Pyodide worker."
179+
from pyscript import PyWorker, document
180+
181+
# Bootstrap the Pyodide worker, with optional config too.
182+
# The worker is:
183+
# * Owned by this script, no JS or Pyodide code in the same page can access
184+
# it.
185+
# * It allows pre-sync methods to be exposed.
186+
# * It has a ready Promise to await for when Pyodide is ready in the worker.
187+
# * It allows the use of post-sync (methods exposed by Pyodide in the
188+
# worker).
189+
worker = PyWorker("worker.py", type="pyodide")
190+
191+
# Expose a utility that can be immediately invoked in the worker.
192+
worker.sync.greetings = lambda: print("Pyodide bootstrapped")
193+
194+
print("before ready")
195+
# Await until Pyodide has completed its bootstrap, and is ready.
196+
await worker.ready
197+
print("after ready")
198+
199+
# Await any exposed methods exposed via Pyodide in the worker.
200+
result = await worker.sync.heavy_computation()
201+
print(result)
202+
203+
# Show the result at the end of the body.
204+
document.body.append(result)
205+
206+
# Free memory and get rid of everything in the worker.
207+
worker.terminate()
208+
```
209+
210+
**worker.py**
211+
```Python title="The worker.py script runs in the Pyodide worker."
212+
from pyscript import sync
213+
214+
# Use any methods from main.py on the main thread.
215+
sync.greetings()
216+
217+
# Expose any methods meant to be used from main.
218+
sync.heavy_computation = lambda: 6 * 7
219+
```
220+
221+
Save these files in a `tmp` folder, ensure [your headers](#http-headers) (just
222+
use `npx mini-coi ./tmp` to serve via localhost) then see the following
223+
outcome in the browser's devtools.
224+
225+
```
226+
before ready
227+
Pyodide bootstrapped
228+
after ready
229+
42
230+
```

version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "2024.5.2"
2+
"version": "2024.6.1"
33
}

0 commit comments

Comments
 (0)