Skip to content

Commit

Permalink
Merge pull request #99 from pyscript/2024-5-2
Browse files Browse the repository at this point in the history
Update docs to 2024.5.2 version
  • Loading branch information
ntoll committed May 13, 2024
2 parents 46b0b9b + 0b5c593 commit dee2add
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 43 deletions.
23 changes: 16 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@

Welcome to the PyScript documentation repository.

This source code becomes the official PyScript documentation hosted here:

[https://docs.pyscript.net](https://docs.pyscript.net/)

Contribute prose and participate in discussions about the written support of
PyScript and related topics.

## Getting started

Before you start contributing to the documentation, it's worthwhile to
take a look at the general contributing guidelines for the PyScript project. You can find these guidelines here
take a look at the general contributing guidelines for the PyScript project.
You can find these guidelines here
[Contributing Guidelines](https://github.com/pyscript/pyscript/blob/main/CONTRIBUTING.md)

## Setup

The `docs` directory in the pyscript repository contains a
[Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) documentation project. Material is a system
that takes plaintext files containing documentation written in Markdown, along with
static files like templates and themes, to build the static end result.
[Material for MkDocs](https://squidfunk.github.io/mkdocs-material/)
documentation project. Material is a system that takes plaintext files
containing documentation written in Markdown, along with static files like
templates and themes, to build the static end result.

To setup the documentation development environment simply create a new
virtual environment, then `pip install -r requirements.txt` (from in the root
Expand All @@ -35,19 +41,22 @@ Simply run `mkdocs serve` or `./bin/mkdocs serve`.

## Cross-referencing

You can link to other pages in the documentation by using the `{doc}` role. For example, to link to the `docs/README.md` file, you would use:
Link to other pages in the documentation by using the `{doc}` role. For
example, to link to the `docs/README.md` file, you would use:

```markdown
{doc}`docs/README.md`
```

You can also cross-reference the python glossary by using the `{term}` role. For example, to link to the `iterable` term, you would use:
Cross-reference the Python glossary by using the `{term}` role. For example, to
link to the `iterable` term, you would use:

```markdown
{term}`iterable`
```

You can also cross-reference functions, methods or data attributes by using the `{attr}` for example:
Cross-reference functions, methods or data attributes by using the `{attr}` for
example:

```markdown
{py:func}`repr`
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.1/core.css">
<script type="module" src="https://pyscript.net/releases/2024.5.1/core.js"></script>
<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>
</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.1/core.css">
<script type="module" src="https://pyscript.net/releases/2024.5.1/core.js"></script>
<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>
</head>
<body>
<h1>Polyglot 🦜 💬 🇬🇧 ➡️ 🏴‍☠️</h1>
Expand Down
81 changes: 80 additions & 1 deletion docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ solution. (These requirements are explored
workers are limited to one way calls from the main thread to methods
exposed by workers.

If `sync_main_only = True`, the following caveats apply:
If `sync_main_only = true`, the following caveats apply:

* It is not possible to manipulate the DOM or do anything meaningful on the
main thread **from a worker**. This is because Atomics cannot guarantee
Expand Down Expand Up @@ -376,6 +376,85 @@ obsolete standards.
While such legacy code exists, be aware that JavaScript code may require
special care.

### Possible deadlock

Users may encounter an error message similar to the following:

!!! failure

```
💀🔒 - Possible deadlock if proxy.xyz(...args) is awaited
```

#### When

This error happens when your code on a worker and in the main thread are
[in a deadlock](https://en.wikipedia.org/wiki/Deadlock). Put simply, neither
fragment of code can proceed without waiting for the other.

#### Why

Let's assume a worker script contains the following Python code:

```python title="worker: a deadlock example"
from pyscript import sync

sync.worker_task = lambda: print('🔥 this is fine 🔥')

# deadlock 💀🔒
sync.main_task()
```

On the main thread, let's instead assume this code:

```html title="main: a deadlock example"
<script type="mpy">
from pyscript import PyWorker
def async main_task():
# deadlock 💀🔒
await pw.sync.worker_task()
pw = PyWorker("./worker.py", {"type": "pyodide"})
pw.sync.main_task = main_task
</script>
```

When the worker bootstraps and calls `sync.main_task()` on the main thread, it
blocks until the result of this call is returned. Hence it cannot respond to
anything at all. However, in the code on the main thread, the
`sync.worker_task()` in the worker is called, but the worker is blocked! Now
the code on both the main thread and worker are mutually blocked and waiting
on each other. We are in a classic
[deadlock](https://en.wikipedia.org/wiki/Deadlock) situation.

The moral of the story? Don't create such circular deadlocks!

How?

The mutually blocking calls cause the deadlock, so simply don't block.

For example, on the main thread, let's instead assume this code:

```html title="main: avoiding deadlocks"
<script type="mpy">
from pyscript import window, PyWorker
async def main_task():
# do not await the worker,
# just schedule it for later (as resolved)
window.Promise.resolve(pw.sync.worker_task())
pw = PyWorker("./worker.py", {"type": "pyodide"})
pw.sync.main_task = main_task
</script>
```

By scheduling the call to the worker (rather than awaiting it), it's possible
for the main thread to call functions defined in the worker in a non-blocking
manner, thus allowing the worker to also work in an unblocked manner and react
to such calls. We have resolved the mutual deadlock.

## Helpful hints

This section contains common hacks or hints to make using PyScript easier.
Expand Down
80 changes: 57 additions & 23 deletions docs/user-guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ ensure the packages [arrr](https://arrr.readthedocs.io/en/latest/) and
[numberwang](https://numberwang.readthedocs.io/en/latest/) are installed from
PyPI (the [Python Packaging Index](https://pypi.org/)):

```TOML title="Configuration via TOML"
```TOML title="Configuration via TOML."
packages = ["arrr", "numberwang" ]
```

```JSON title="Configuration via JSON"
```JSON title="Configuration via JSON."
{
"packages": ["arrr", "numberwang"]
}
Expand All @@ -56,15 +56,15 @@ reference it from the tag used to specify the Python code:

If you use JSON, you can make it the value of the `config` attribute:

```HTML title="JSON as the value of the config attribute"
```HTML title="JSON as the value of the config attribute."
<script type="mpy" src="main.py" config='{"packages":["arrr", "numberwang"]}'></script>
```

For historical and convenience reasons we still support the inline
specification of configuration information via a _single_ `<py-config>` or
`<mpy-config>` tag in your HTML document:

```HTML title="Inline configuration via the &lt;py-config&gt; tag"
```HTML title="Inline configuration via the &lt;py-config&gt; tag."
<py-config>
{
"packages": ["arrr", "numberwang" ]
Expand All @@ -79,10 +79,10 @@ specification of configuration information via a _single_ `<py-config>` or

## Options

There are four core options ([`interpreter`](#interpreter), [`files`](#files),
[`packages`](#packages), and
[`js_modules`](#javascript-modules)) and an experimental flag
([experimental_create_proxy](#experimental_create_proxy)) that can be used in
There are five core options ([`interpreter`](#interpreter), [`files`](#files),
[`packages`](#packages), [`js_modules`](#javascript-modules) and
[`sync_main_only`](#sync_main_only)) and an experimental flag
([`experimental_create_proxy`](#experimental_create_proxy)) that can be used in
the configuration of PyScript. The user is also free to define
arbitrary additional configuration options that plugins or an app may require
for their own reasons.
Expand All @@ -100,11 +100,11 @@ a custom version of the interpreter.

The following two examples are equivalent:

```TOML title="Specify the interpreter version in TOML"
```TOML title="Specify the interpreter version in TOML."
interpreter = "0.23.4"
```

```JSON title="Specify the interpreter version in JSON"
```JSON title="Specify the interpreter version in JSON."
{
"interpreter": "0.23.4"
}
Expand All @@ -113,7 +113,7 @@ interpreter = "0.23.4"
The following JSON fragment uses a fully qualified URL to point to the same
version of Pyodide as specified in the previous examples:

```JSON title="Specify the interpreter via a fully qualified URL"
```JSON title="Specify the interpreter via a fully qualified URL."
{
"interpreter": "https://cdn.jsdelivr.net/pyodide/v0.23.4/full/pyodide.mjs"
}
Expand All @@ -127,7 +127,7 @@ destination filesystem path.

The following JSON and TOML are equivalent:

```json title="Fetch files onto the filesystem with JSON"
```json title="Fetch files onto the filesystem with JSON."
{
"files": {
"https://example.com/data.csv": "./data.csv",
Expand All @@ -136,7 +136,7 @@ The following JSON and TOML are equivalent:
}
```

```toml title="Fetch files onto the filesystem with TOML"
```toml title="Fetch files onto the filesystem with TOML."
[files]
"https://example.com/data.csv" = "./data.csv"
"/code.py" = "./subdir/code.py"
Expand All @@ -147,7 +147,7 @@ URL becomes the destination filename, in the root of the filesystem, to which
the content is copied. As a result, the `data.csv` entry from the previous
examples could be equivalently re-written as:

```json title="JSON implied filename in the root directory"
```json title="JSON implied filename in the root directory."
{
"files": {
"https://example.com/data.csv": "",
Expand All @@ -156,7 +156,7 @@ examples could be equivalently re-written as:
}
```

```toml title="TOML implied filename in the root directory"
```toml title="TOML implied filename in the root directory."
[files]
"https://example.com/data.csv" = ""
... etc ...
Expand Down Expand Up @@ -202,7 +202,7 @@ their name is replaced with their associated value.

The following JSON and TOML are equivalent:

```json title="Using the template language in JSON"
```json title="Using the template language in JSON."
{
"files": {
"{DOMAIN}": "https://my-server.com",
Expand All @@ -218,7 +218,7 @@ The following JSON and TOML are equivalent:
}
```

```toml title="Using the template language in TOML"
```toml title="Using the template language in TOML."
[files]
"{DOMAIN}" = "https://my-server.com"
"{PATH}" = "a/path"
Expand Down Expand Up @@ -287,11 +287,11 @@ to be installed onto the Python path.

The following two examples are equivalent:

```TOML title="A packages list in TOML"
```TOML title="A packages list in TOML."
packages = ["arrr", "numberwang", "snowballstemmer>=2.2.0" ]
```

```JSON title="A packages list in JSON"
```JSON title="A packages list in JSON."
{
"packages": ["arrr", "numberwang", "snowballstemmer>=2.2.0" ]
}
Expand Down Expand Up @@ -338,13 +338,13 @@ To specify such modules, simply provide a list of source/module name pairs.
For example, to use the excellent [Leaflet](https://leafletjs.com/) JavaScript
module for creating interactive maps you'd add the following lines:

```TOML title="JavaScript main thread modules defined in TOML"
```TOML title="JavaScript main thread modules defined in TOML."
[js_modules.main]
"https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet-src.esm.js" = "leaflet"
"https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.css" = "leaflet" # CSS
```

```JSON title="JavaScript main thread modules defined in JSON"
```JSON title="JavaScript main thread modules defined in JSON."
{
"js_modules": {
"main": {
Expand Down Expand Up @@ -386,12 +386,12 @@ Some JavaScript modules (such as
access to the DOM and, for efficiency reasons, can be included in the worker
context:

```TOML title="A JavaScript worker module defined in TOML"
```TOML title="A JavaScript worker module defined in TOML."
[js_modules.worker]
"https://cdn.jsdelivr.net/npm/html-escaper" = "html_escaper"
```

```JSON title="A JavaScript worker module defined in JSON"
```JSON title="A JavaScript worker module defined in JSON."
{
"js_modules": {
"worker": {
Expand All @@ -404,6 +404,40 @@ context:
However, `from pyscript.js_modules import html_escaper` would then only work
within the context of Python code **running on a worker**.

### sync_main_only

Sometimes you just want to start an expensive computation on a web worker
without the need for the worker to interact with the main thread. You're simply
awaiting the result of a method exposed from a worker.

This has the advantage of not requiring the use of `SharedArrayBuffer` and
[associated CORS related header configuration](../workers/#http-headers).

If the `sync_main_only` flag is set, then **interactions between the main thread
and workers are limited to one way calls from the main thread to methods
exposed by the workers**.

```TOML title="Setting the sync_main_only flag in TOML."
sync_main_only = true
```

```JSON title="Setting the sync_main_only flag in JSON."
{
"sync_main_only": true
}
```

If `sync_main_only` is set, the following caveats apply:

* It is not possible to manipulate the DOM or do anything meaningful on the
main thread **from a worker**. This is because Atomics cannot guarantee
sync-like locks between a worker and the main thread.
* Only a worker's `pyscript.sync` methods are exposed, and **they can only be
awaited from the main thread**.
* The worker can only `await` main thread references one after the other, so
developer experience is degraded when one needs to interact with the
main thread.

### experimental_create_proxy

Knowing when to use the `pyscript.ffi.create_proxy` method when using Pyodide
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.1/core.css">
<link rel="stylesheet" href="https://pyscript.net/releases/2024.5.2/core.css">
<!-- This script tag bootstraps PyScript -->
<script type="module" src="https://pyscript.net/releases/2024.5.1/core.js"></script>
<script type="module" src="https://pyscript.net/releases/2024.5.2/core.js"></script>
</head>
<body>
<!-- your code goes here... -->
Expand Down
Loading

0 comments on commit dee2add

Please sign in to comment.