diff --git a/README.md b/README.md index 5824a7fd..c0f8517e 100644 --- a/README.md +++ b/README.md @@ -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 ``` diff --git a/docs/beginning-pyscript.md b/docs/beginning-pyscript.md index de6098be..cb292e72 100644 --- a/docs/beginning-pyscript.md +++ b/docs/beginning-pyscript.md @@ -112,8 +112,8 @@ module in the document's `` tag: 🦜 Polyglot - Piratical PyScript - - + + @@ -163,8 +163,8 @@ In the end, our HTML should look like this: 🦜 Polyglot - Piratical PyScript - - + +

Polyglot 🦜 💬 🇬🇧 ➡️ 🏴‍☠️

diff --git a/docs/faq.md b/docs/faq.md index 5b75b94d..cb43451c 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -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 @@ -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 @@ -768,7 +770,7 @@ packages onto the Python path: ``` -#### 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 @@ -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 diff --git a/docs/user-guide/builtins.md b/docs/user-guide/builtins.md index b3de20ee..7025a317 100644 --- a/docs/user-guide/builtins.md +++ b/docs/user-guide/builtins.md @@ -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." + +``` + +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." + + diff --git a/docs/user-guide/plugins.md b/docs/user-guide/plugins.md index 84ee9854..fbf256d6 100644 --- a/docs/user-guide/plugins.md +++ b/docs/user-guide/plugins.md @@ -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! @@ -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; @@ -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) => { @@ -196,8 +196,8 @@ hooks.worker.onAfterRun.add(() => { - - + + + PyWorker - mpy bootstrapping pyodide example + + + + +``` + +**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 +``` diff --git a/version.json b/version.json index d3d8baf1..b73d3891 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "2024.5.2" + "version": "2024.6.1" }