From ccf6c6a213728ebe55738863a4b6d10fa65d3e66 Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Tue, 25 Nov 2025 09:43:44 +0000 Subject: [PATCH 1/5] Ensure setuptools. --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 84debdfc..3eaa631d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ mkdocs-material==9.3.1 mike==1.1.2 +setuptools From 5133a9ececce9112566c89aecbff5e82f7aac42d Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Tue, 25 Nov 2025 09:43:58 +0000 Subject: [PATCH 2/5] Bump version to 2025.11.2 --- docs/beginning-pyscript.md | 8 ++++---- docs/user-guide/first-steps.md | 4 ++-- docs/user-guide/plugins.md | 10 +++++----- docs/user-guide/pygame-ce.md | 4 ++-- docs/user-guide/workers.md | 4 ++-- version.json | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/beginning-pyscript.md b/docs/beginning-pyscript.md index fb4956f5..bafd91a3 100644 --- a/docs/beginning-pyscript.md +++ b/docs/beginning-pyscript.md @@ -117,8 +117,8 @@ module in the document's `` tag: 🦜 Polyglot - Piratical PyScript - - + + @@ -168,8 +168,8 @@ In the end, our HTML should look like this: 🦜 Polyglot - Piratical PyScript - - + +

Polyglot 🦜 💬 🇬🇧 ➡️ 🏴‍☠️

diff --git a/docs/user-guide/first-steps.md b/docs/user-guide/first-steps.md index af2bf592..b1d74423 100644 --- a/docs/user-guide/first-steps.md +++ b/docs/user-guide/first-steps.md @@ -20,9 +20,9 @@ CSS: - + - + diff --git a/docs/user-guide/plugins.md b/docs/user-guide/plugins.md index 8b513d26..e6727b3e 100644 --- a/docs/user-guide/plugins.md +++ b/docs/user-guide/plugins.md @@ -100,7 +100,7 @@ For example, this will work because all references are contained within the registered function: ```js -import { hooks } from "https://pyscript.net/releases/2025.11.1/core.js"; +import { hooks } from "https://pyscript.net/releases/2025.11.2/core.js"; hooks.worker.onReady.add(() => { // NOT suggested, just an example! @@ -114,7 +114,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/2025.11.1/core.js"; +import { hooks } from "https://pyscript.net/releases/2025.11.2/core.js"; // NO NO NO NO NO! ☠️ let i = 0; @@ -147,7 +147,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/2025.11.1/core.js"; +import { hooks } from "https://pyscript.net/releases/2025.11.2/core.js"; // The `hooks.main` attribute defines plugins that run on the main thread. hooks.main.onReady.add((wrap, element) => { @@ -197,8 +197,8 @@ hooks.worker.onAfterRun.add(() => { - - + + + + diff --git a/docs/user-guide/workers.md b/docs/user-guide/workers.md index 9fdf0234..970e0244 100644 --- a/docs/user-guide/workers.md +++ b/docs/user-guide/workers.md @@ -286,9 +286,9 @@ Here's how: - + - + PyWorker - mpy bootstrapping pyodide example diff --git a/version.json b/version.json index f784750b..4bf3a420 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "2025.11.1" + "version": "2025.11.2" } From 28918d583d64d4218838d25c8c3e612079cac934 Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Tue, 25 Nov 2025 10:25:37 +0000 Subject: [PATCH 3/5] Add details about offline.zip and IDE configuration with Python stubs. --- .gitignore | 1 + docs/beginning-pyscript.md | 41 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/.gitignore b/.gitignore index bf99dd2b..8fc8808d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ bin lib lib64 pyvenv.cfg +*.swp diff --git a/docs/beginning-pyscript.md b/docs/beginning-pyscript.md index bafd91a3..71b4545e 100644 --- a/docs/beginning-pyscript.md +++ b/docs/beginning-pyscript.md @@ -231,6 +231,41 @@ points to the `div` element with the id "output". Finally, we assign the That's it! +## Editing you app + +If you use an IDE (like VSCode or PyCharm) then you'll probably want them to +auto-suggest and introspect aspects of the Python code you're writing. The +problem is that the `pyscript` namespace *we provide* isn't installed anywhere +(because it's in your browser, not your IDE's context) so such information +isn't, by default, picked up. + +Thankfully Python stubs come to the rescue. + +Members of our community have +[created Python stub files for PyScript](https://github.com/pyscript/pyscript-stubs). +You should clone the linked-to repository and configure your IDE to consume the +stub files. + +For example, let's say you +[cloned the repository](https://github.com/pyscript/pyscript-stubs) into: +`~/src/stubs/pyscript-stubs`, then in VSCode, you'd create, in your PyScript +project, a file called `.vscode/settings.json` and add the following: + +```js +{ + "python.analysis.stubPath": "~/src/stubs/pyscript-stubs/src/pyscript-stubs" +} +``` + +Then restart the Python language server in VSCode (Press `Ctrl+Shift+P` (or +`Cmd+Shift+P` on Mac) to open the Command Palette and type: +`Python: Restart Language Server`. + +!!! note + + The stubs themselves are found within the `src/pyscript-stubs` directory + in the git repository, hence the longer path in the configuration file. + ## Sharing your app ### PyScript.com @@ -263,6 +298,12 @@ To run PyScript offline, without the need of a CDN or internet connection, read the [Run PyScript Offline](user-guide/offline.md) section of the user guide. +We also provide an `offline.zip` file with +[each release](https://pyscript.net/releases/2025.11.2/). This file contains +everything you need for an offline version of PyScript: PyScript itself, +versions of Pyodide and MicroPython, and an index.html page from which you +could create your offline-first PyScript work. + ## Conclusion Congratulations! From f072e2b68d1547ce9ff282a3675f68e773c3d1e4 Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Tue, 25 Nov 2025 11:04:02 +0000 Subject: [PATCH 4/5] Add docs about unsticking web workers stuck in infinite loops. --- docs/api.md | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/docs/api.md b/docs/api.md index 8a992d38..0e1fc2fd 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1100,6 +1100,61 @@ PyWorker("worker.py", type="micropython")
``` +!!! info + + Sometimes code running on a worker gets stuck in an infinite loop and + becomes unresponsive. There are many complicated reasons why this might + happen, but when it does happen you likely want to break out of this + loop. This is where the `isStuck` and `notStuck` features come into play. + + If you have code in the worker that could end up in an unresponsive + infinite loop, for example: + + ```python + import time + + while True: + time.sleep(1) + print("Stuck in a loop") + ``` + + ...then you only need wrap this code in the worker like this: + + ```python + import time + from pyscript import sync + is_stuck = sync.isStuck + break_loop = sync.notStuck + + def is_not_stuck(condition): + if is_stuck(): + # this is a must to reset the "stuck" state + break_loop() + # throw an error to get out of the loop + raise RuntimeError('Worker was stuck, but now it is unstuck') + return condition + + while is_not_stuck(True): + time.sleep(1) + print("Stuck in a loop") + ``` + + From your code on the main thread you may have something like this: + + ```python + from pyscript import PyWorker + + w = PyWorker("sticky_code.py", type="micropython") + + @when("click", "unstick_button") + def handle_unstick(): + w.unstuck() + ``` + + This starts the worker with you code that could get into an infinite loop, + then defines a function that calls the `unstuck()` function on the worker + when a button on the UI is clicked. + ### `pyscript.workers` The `pyscript.workers` reference allows Python code in the main thread to From 51e3d673a894ade620a4631709ad71665682372d Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Tue, 25 Nov 2025 11:27:02 +0000 Subject: [PATCH 5/5] Minor edit to improve stuck conditional check. --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index 0e1fc2fd..21327b02 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1127,7 +1127,7 @@ PyWorker("worker.py", type="micropython") break_loop = sync.notStuck def is_not_stuck(condition): - if is_stuck(): + if not condition and is_stuck(): # this is a must to reset the "stuck" state break_loop() # throw an error to get out of the loop