Files
Nicholas Tollervey a02ff691d2 pyscript API/docstring refactor with comprehensive tests (#2414)
* Revise display module. TODO: more comprehensive tests. Especially around mimebundles.

* Markdown corrections in example code in display.py docstrings.

* Minor adjustments and a much more comprehensive test-suite for the display module.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Updated docstring in __init__.py.

* Remove unused imports and black-ify the source.

* Refactor, docs and tests for the Event class in events.py.

* Refactored, simplified and documented @when decorator.

* Extensive test suite for @when decorator.

* Documentation and minor refactoring of the fetch.py module. TODO: Check tests.

* Refactored and more comprehensive tests for the fetch module.

* Add/clarify Event related interactions. Thanks @Neon22 for the suggestion.

* Refactor, document ffi.py module.

* More complete passing tests for ffi.py.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Add docstrings to flatted.py. Since this is actually an external(ish) module, tests for it should be in the external repository from which this code is derived.

* Minor docstring cleanup in ffi.py.

* Added docstrings and clarifications to fs.py.

* Add very limited test suite for fs.py.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Rename magic_js.py to context.py, add comprehensive docstrings, and rename certain internal things for readability and comprehension.

* Fix dict check in ffi.py.

* Rename test_js_modules to test_context.

* Fix test configuration aftert rename.

* Docs and refactor of media.py.

* Comprehensive tests for media.py.

* Refactor and docstrings for storage.py

* Appease the ruff gods.

* Further storage.py changes and a more complete test suite for storage.

* Refactor and docstrings for the util.py module. Fixed a problem with is_awaitable not handling async bound methods.

* More comprehensive test suite for util.py. Updated to latest upytest.

* A major refactoring, documenting and simplification of the web.py module substantially reducing it in size and complexity with only a few minor (edge) behavioural changes.

Softly breaking changes include:

- An element's classes are just a set.
- An element's styles are just a dict.
- Explicitly use `update_all` with ElementCollections (simpler and greater flexibility).
- Extract a child element by id with `my_container["#an-id"]`

* Updates and additions for a more comprehensive test suite for the web.py module. All code paths are exercised and checked.

* Black tidy-ups in test suite.

* Refactor and documentation for websocket.py module.

* Tests for websocket.py. Disabled due to playwright flakiness, but they all pass in a local browser.

* Refactor and documentation of workers.py module.

* Added tests for workers.py module. Updated related test suite to account for the new named worker in the test HTML.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Refactor away remaining "is not None" not caught before.

* Remove check-docstring-first because it interferes with the auto-generated documentation (where triple quoted strings are used to document module attributes).

* Careful Markdown changes so the docstrings render properly in the PyScript docs.

* Typo correction.

* More typo corrections and clarifications.

* Add clarification about SVG handling to _render_image docstring.

* Add DOM event options to the @when decorator (with new tests to exercise this functionality).

* Fixes default value for options if no options passed into @when.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-12-11 17:19:24 +00:00
..

@pyscript/core

PyScript brings two Python interpreters to the browser:

  • MicroPython - a lean and efficient implementation of the Python 3 programming language that includes a small subset of the Python standard library and is optimised to run on microcontrollers and in constrained environments (like the browser).
  • Pyodide) - a port of all CPython to WebAssembly.

These interpreters are compiled to WebAssembly (shortened to WASM). The browser provides a secure WASM computing sandbox. Both interpreters are compiled to web assembly with Emscripten. PyScript core maintainers work closely with the core maintainers of both MicroPython and Pyodide (and CPython). We work hard to ensure PyScript works efficiently in browsers on all platforms: desktop, mobile, or elsewhere.

Our technical documentation for using this project can be found here.

PyScript sits on two further projects (both written in JavaScript):

  1. polyscript - used to bootstrap WASM compiled interpreters in a browser.
  2. coincident - used to simplify worker based tasks.

PyScript itself is mostly written in JavaScript. The test suite for JavaScript is in two parts: automated tests run in playwright, and manual tests you have to run in a browser and check yourself. PyScript also has a plugin system so third parties can extend its capabilities with JavaScript. Our built-in core plugins can be found in the src/plugins directory. We describe how to write third party plugins in our developer documentation.

We provide a pyscript namespace containing Python modules for common browser based APIs and features (i.e. you can import pyscript in Python code running inside PyScript, to access these features). The Python code for the pyscript namespace is in src/stdlib/pyscript with the associated test suite in tests/python. The tests use the browser friendly uPyTest test framework for checking Python code running within PyScript. All the Python tests are run in each each available interpreter in both the main thread and a web worker (i.e. the test suite is run four times, accounting for each combination of interpreter and main/worker context).

When you create a local build all the automated tests (JavaScript and Python) are run.

Developer Guide

Full instructions for setting up a working development environment, how to build PyScript and how to test it can be found in our official docs.

The short version is:

  • Ensure you have Python, node and npm installed.
  • Create a Python virtual environment.
  • In the root of this repository make setup.
  • make build to build PyScript.
  • As dependencies change over time, make update to keep in sync.

To start using the locally built version of PyScript, you'll need an HTML page something like this (note the relative paths to assets in the dist directory, in the <head> of the document):

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Pure Python PyScript tests</title>
        <link rel="stylesheet" href="../../dist/core.css" />
        <script type="module" src="../../dist/core.js"></script>
    </head>
    <body>
        <script type="mpy" src="./main.py" config="./conf.toml"></script>
    </body>
</html>

Once set up, you should be able to run the most common activities via the make command:

$ make

There is no default Makefile target right now. Try:

make setup - check your environment and install the dependencies.
make update - update dependencies.
make clean - clean up auto-generated assets.
make build - build PyScript.
make precommit-check - run the precommit checks (run eslint).
make test - run all automated tests in playwright.
make fmt - format the code.
make fmt-check - check the code formatting.

Artifacts

There are two main artifacts in this project:

  • stdlib and its content: src/stdlib/pyscript.js exposes, as a JavaScript object literal, all the Python content within the folder (recursively).
  • plugins and its content: src/plugins.js exposes all available dynamic imports, and is able to instrument the bundler to create files apart from the _dist/_ folder, so that by default core remains as small as possible.

Accordingly, whenever a file contains this warning at its first line, please do not change such file directly before submitting a merge request, as that file will be overwritten at the next npm run build command, either here or in CI:

// ⚠️ This file is an artifact: DO NOT MODIFY

Plugins

While community or third party plugins don't need to be part of this repository and can be added just importing @pyscript/core as module, there are a few plugins that we would like to make available by default and these are considered core plugins.

To add a core plugin to this project define the plugin entry-point and name in the src/plugins folder (see the error.js example) and create, if necessary, a folder with the same name where extra files or dependencies can be added.

The build command will include plugins by name as artifacts so that the bundler can create ad-hoc files within the dist/ folder.

Python

The pyscript package available in Python lives in the folder src/stdlib/pyscript/.

All Python files will be embedded automatically whenever npm run build happens and reflected into the src/stdlib/pyscript.js file.

Its core responsibility is to ensure those files will be available through the filesystem in either the main thread, or any worker.

Release

To cut a new release of PyScript simply add a new release while remembering to write a comprehensive changelog. A GitHub action will kick in and ensure the release is described and deployed to a URL with the pattern: https://pyscript.net/releases/YYYY.M.v/ (year/month/version - as per our CalVer versioning scheme).

Then, the following three separate repositories need updating:

  • Documentation - Change the version.json file in the root of the directory and then node version-update.js.
  • Homepage - Ensure the version referenced in index.html is the latest version.
  • PSDC - Use discord or Anaconda Slack (if you work at Anaconda) to let the PSDC team know there's a new version, so they can update their project templates.