Skip to content

Updates around latest changes and docs #123

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

Merged
merged 7 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ of this repository).
# example of a simple virtual environment
# creation from the root of this project
python -m venv .
./bin/pip install --upgrade setuptools
./bin/pip install -r requirements.txt
```

Expand Down
8 changes: 4 additions & 4 deletions docs/beginning-pyscript.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ module in the document's `<head>` tag:
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>🦜 Polyglot - Piratical PyScript</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2024.5.2/core.css">
<script type="module" src="https://pyscript.net/releases/2024.5.2/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2024.6.1/core.css">
<script type="module" src="https://pyscript.net/releases/2024.6.1/core.js"></script>
</head>
<body>

Expand Down Expand Up @@ -163,8 +163,8 @@ In the end, our HTML should look like this:
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>🦜 Polyglot - Piratical PyScript</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2024.5.2/core.css">
<script type="module" src="https://pyscript.net/releases/2024.5.2/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2024.6.1/core.css">
<script type="module" src="https://pyscript.net/releases/2024.6.1/core.js"></script>
</head>
<body>
<h1>Polyglot 🦜 💬 🇬🇧 ➡️ 🏴‍☠️</h1>
Expand Down
25 changes: 19 additions & 6 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ automatically install packages for you](user-guide/configuration/#packages).
Yet [packaging can be a complicated beast](#python-packages), so here are some
hints for a painless packaging experience with PyScript.

There are essentially four ways in which a third party package can become
There are essentially five ways in which a third party package can become
available in PyScript.

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

#### Host a package

Expand Down Expand Up @@ -768,7 +770,7 @@ packages onto the Python path:
</script>
```

#### Code archive (`zip`/`tgz`)
#### Code archive (`zip`/`tgz`/`whl`)

Compress all the code you want into an archive (using either either `zip` or
`tgz`/`tar.gz`). Host the resulting archive and use the
Expand Down Expand Up @@ -1206,14 +1208,25 @@ js.callback(
)
)
```
!!! info

Thanks to a
[recent change in Pyodide](https://github.com/pyodide/pyodide/pull/4576),
such `Map` instances are
[duck-typed](https://en.wikipedia.org/wiki/Duck_typing) to behave like
object literals. Conversion may not be needed anymore, and `to_js` may just
work without the need of the `dict_converter`. Please check.

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

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

#### Caveat

Expand Down
46 changes: 46 additions & 0 deletions docs/user-guide/builtins.md
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,52 @@ from pyscript import sync
sync.hello("PyScript")
```

### `pyscript.py_import`

!!! warning

**This is an experimental feature.**

Feedback and bug reports are welcome!

If you have a lot of Python packages referenced in your configuration, startup
performance may be degraded as these are downloaded.

If a Python package is only needed under certain circumstances, we provide an
asynchronous way to import packages that were not originally referenced in your
configuration.

```html title="A pyscript.py_import example."
<script type="py" async>
from pyscript import py_import

matplotlib, regex, = await py_import("matplotlib", "regex")

print(matplotlib, regex)
</script>
```

The `py_import` call returns an asynchronous tuple containing the Python
modules provided by the packages referenced as string arguments.

### `pyscript.js_import`

If a JavaScript module is only needed under certain circumstances, we provide
an asynchronous way to import packages that were not originally referenced in
your configuration.

```html title="A pyscript.js_import example."
<script type="py" async>
from pyscript import js_import, window

escaper, = await js_import("https://esm.run/html-escaper")

window.console.log(escaper)
```

The `js_import` call returns an asynchronous tuple containing the JavaScript
modules referenced as string arguments.

## HTML attributes

As a convenience, and to ensure backwards compatibility, PyScript allows the
Expand Down
45 changes: 45 additions & 0 deletions docs/user-guide/editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ or `mpy-editor` (for MicroPython), the plugin creates a visual code editor,
with code highlighting and a "run" button to execute the editable code
contained therein in a non-blocking worker.

!!! info

Once clicked, the "run" button will show a spinner until the code is
executed. This may not be visible if the code evaluation completed quickly.


The interpreter is not loaded onto the page until the run button is clicked. By
default each editor has its own independent instance of the specified
interpreter:
Expand Down Expand Up @@ -61,6 +67,8 @@ The outcome of these code fragments should look something like this:

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

### Setup

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

## Read / Write / Execute

Sometimes you need to programatically read, write or execute code in an
editor. Once PyScript has started, every py-editor/mpy-editor script tag gets
a `code` accessor attached to it.

```python
from pyscript import document

# Grab the editor script reference.
editor = document.querySelector('#editor')

# Output the live content of the editor.
print(editor.code)

# Update the live content of the editor.
editor.code = """
a = 1
b = 2
print(a + b)
"""

# Evaluate the live code in the editor.
# This could be any arbitrary code to evaluate in the editor's Python context.
editor.process(editor.code)
```

## Configuration

Unlike `<script type="py">` or `<py-script>` (and the `mpy` equivalents), a
PyEditor is not influenced by the presence of `<py-config>` elements in the
page: it requires an explicit `config="..."` attribute.

If a `setup` editor is present, that's the only PyEditor that needs a config.
Any subsequent related editor will reuse the config parsed and bootstrapped for
the `setup` editor.

## Still missing

The PyEditor is currently under active development and refinement, so features
Expand Down
4 changes: 2 additions & 2 deletions docs/user-guide/first-steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ CSS:
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<!-- PyScript CSS -->
<link rel="stylesheet" href="https://pyscript.net/releases/2024.5.2/core.css">
<link rel="stylesheet" href="https://pyscript.net/releases/2024.6.1/core.css">
<!-- This script tag bootstraps PyScript -->
<script type="module" src="https://pyscript.net/releases/2024.5.2/core.js"></script>
<script type="module" src="https://pyscript.net/releases/2024.6.1/core.js"></script>
</head>
<body>
<!-- your code goes here... -->
Expand Down
10 changes: 5 additions & 5 deletions docs/user-guide/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ For example, this will work because all references are contained within the
registered function:

```js
import { hooks } from "https://pyscript.net/releases/2024.5.2/core.js";
import { hooks } from "https://pyscript.net/releases/2024.6.1/core.js";

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

```js
import { hooks } from "https://pyscript.net/releases/2024.5.2/core.js";
import { hooks } from "https://pyscript.net/releases/2024.6.1/core.js";

// NO NO NO NO NO! ☠️
let i = 0;
Expand Down Expand Up @@ -146,7 +146,7 @@ the page.

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

// The `hooks.main` attribute defines plugins that run on the main thread.
hooks.main.onReady.add((wrap, element) => {
Expand Down Expand Up @@ -196,8 +196,8 @@ hooks.worker.onAfterRun.add(() => {
<!-- JS plugins should be available before PyScript bootstraps -->
<script type="module" src="./log.js"></script>
<!-- PyScript -->
<link rel="stylesheet" href="https://pyscript.net/releases/2024.5.2/core.css">
<script type="module" src="https://pyscript.net/releases/2024.5.2/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2024.6.1/core.css">
<script type="module" src="https://pyscript.net/releases/2024.6.1/core.js"></script>
</head>
<body>
<script type="mpy">
Expand Down
36 changes: 36 additions & 0 deletions docs/user-guide/terminal.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,39 @@ terminal automatically become links). Behind the scenes is the example code
shown above, and this approach will work for
[any other addon](https://github.com/xtermjs/xterm.js/tree/master/addons/) you
may wish to use.

### MicroPython

MicroPython has a
[very complete REPL](https://docs.micropython.org/en/latest/reference/repl.html)
already built into it.

* All `Ctrl+X` strokes are handled, including paste mode and kill switches.
* History works out of the box. Access this via the up and down arrows to
view your command history.
* Tab completion works like a charm. Use the `tab` key to see available
variables or objects in `globals`.
* Copy and paste is much improved. This is true for a single terminal entry,
or a
[paste mode](https://docs.micropython.org/en/latest/reference/repl.html#paste-mode)
enabled variant.

As a bonus, the MicroPython terminal works on both the main thread and in
web workers, with the following caveats:

* **Main thread:**
* Calls to the blocking `input` function are delegated to the native browser
based
[prompt](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt)
utility.
* There are no guards against blocking code (e.g. `while True:` loops).
Such blocking code _could freeze your page_.
* **Web worker:**
* Conventional support for the `input` function, without blocking the main
thread.
* Blocking code (e.g. `while True:` loops) does not block the main thread
and your page will remain responsive.

We encourage the usage of `worker` attribute to bootstrap a MicroPython
terminal. But now you have an option to run the terminal in the main thread.
Just remember not to block!
82 changes: 82 additions & 0 deletions docs/user-guide/workers.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,85 @@ into the DOM and access some `window` based APIs.
and produce unforeseen problematic results**. Remember, with great power
comes great responsibility... and we've given you a bazooka (so please
remember not to shoot yourself in the foot with it).

## Common Use Case

While it is possible to start a MicroPython or Pyodide worker from either
MicroPython or Pyodide running on the main thread, the most common use case
we have encountered is MicroPython on the main thread starting a Pyodide
worker.

Here's how:

**index.html**
```HTML title="Evaluate main.py via MicroPython on the main thread"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<!-- PyScript CSS -->
<link rel="stylesheet" href="https://pyscript.net/releases/2024.6.1/core.css">
<!-- This script tag bootstraps PyScript -->
<script type="module" src="https://pyscript.net/releases/2024.6.1/core.js"></script>
<title>PyWorker - mpy bootstrapping pyodide example</title>
<!-- the async attribute is useful but not mandatory -->
<script type="mpy" src="main.py" async></script>
</head>
</html>
```

**main.py**
```Python title="MicroPython's main.py: bootstrapping a Pyodide worker."
from pyscript import PyWorker, document

# Bootstrap the Pyodide worker, with optional config too.
# The worker is:
# * Owned by this script, no JS or Pyodide code in the same page can access
# it.
# * It allows pre-sync methods to be exposed.
# * It has a ready Promise to await for when Pyodide is ready in the worker.
# * It allows the use of post-sync (methods exposed by Pyodide in the
# worker).
worker = PyWorker("worker.py", type="pyodide")

# Expose a utility that can be immediately invoked in the worker.
worker.sync.greetings = lambda: print("Pyodide bootstrapped")

print("before ready")
# Await until Pyodide has completed its bootstrap, and is ready.
await worker.ready
print("after ready")

# Await any exposed methods exposed via Pyodide in the worker.
result = await worker.sync.heavy_computation()
print(result)

# Show the result at the end of the body.
document.body.append(result)

# Free memory and get rid of everything in the worker.
worker.terminate()
```

**worker.py**
```Python title="The worker.py script runs in the Pyodide worker."
from pyscript import sync

# Use any methods from main.py on the main thread.
sync.greetings()

# Expose any methods meant to be used from main.
sync.heavy_computation = lambda: 6 * 7
```

Save these files in a `tmp` folder, ensure [your headers](#http-headers) (just
use `npx mini-coi ./tmp` to serve via localhost) then see the following
outcome in the browser's devtools.

```
before ready
Pyodide bootstrapped
after ready
42
```
2 changes: 1 addition & 1 deletion version.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"version": "2024.5.2"
"version": "2024.6.1"
}