```
+!!! 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 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
+ 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
diff --git a/docs/beginning-pyscript.md b/docs/beginning-pyscript.md
index fb4956f..71b4545 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 🦜 💬 🇬🇧 ➡️ 🏴☠️
@@ -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!
diff --git a/docs/user-guide/first-steps.md b/docs/user-guide/first-steps.md
index af2bf59..b1d7442 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 8b513d2..e6727b3 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 9fdf023..970e024 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/requirements.txt b/requirements.txt
index 84debdf..3eaa631 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,3 @@
mkdocs-material==9.3.1
mike==1.1.2
+setuptools
diff --git a/version.json b/version.json
index f784750..4bf3a42 100644
--- a/version.json
+++ b/version.json
@@ -1,3 +1,3 @@
{
- "version": "2025.11.1"
+ "version": "2025.11.2"
}