Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Sep 21, 2023. It is now read-only.
/MicroPyScriptPublic archive

MicroPyScript: A test harness for multiple runtimes in PyScript

License

NotificationsYou must be signed in to change notification settings

pyscript/MicroPyScript

Repository files navigation

A small, simple kernel of PyScript, made for testing purposes in the spirit ofacode spike.

This is the way:

  • Obvious code.
  • Simple is good.
  • No dependencies.
  • Vanilla JavaScript.
  • Pluggable.
  • Comments.
  • (Some) tests.
  • Build for change.

This is a foundation for lightweight testing of Python interpreters thattarget WASM. Inspired by code in the "real" PyScript website and our plans forplugins and simple event based coordination.

Complexity, edge cases and customization is (hopefully) confined to plugins andbespoke interpreters.

That is all.

Developer setup

In order to compile MicroPython you'll need to ensure you have the expecteddev tools described here:

https://docs.micropython.org/en/latest/develop/gettingstarted.html

Otherwise, common tasks are scripted by a Makefile (tested on Linux):

$ makeThere's no default Makefile target right now. Try:make setup - clone the required repositories.make update - update the emsdk compiler.make mp - compile MicroPython for WASM into the mpbuild directory.make serve - serve the project at: http://0.0.0.0:8000/make test - while serving the app, run the test suite in browser.

To get a working development environment with MicroPython run:

$ make setup$ make update$ make mp

To check things are working:

$ make serve

Then point your browser tohttp://0.0.0.0:8000/ to see the first page of aninteractive technical report about using MicroPython. You should be able tochange the interpreter frommicropython topyodide and things should justwork as before, but with a different interpreter at the bottom of the PyScriptstack.

Running the tests

TESTS ARE CURRENTLY BROKEN

For the sake of simplicity (and familiarity) we use theJasmine test framework to exercise theJavaScript aspects of our code.

Ensure the project is being served (make serve) and in a different shell, inthe root of this project, typemake test. Your default browser should openand run the Jasmine based test suite.

How it works

The PyScript core only loads configuration, starts the Python interpreter,allows the registration of plugins and adds files to the interpreter'sfilesystem. All other logic, capabilities and features are contained in theplugins.

Currently, only two plugins are provided:

  • One built into PyScript that implements the core<py-script> tag.
  • The other (incustomtags.js) implements the<py-repl> tag to demonstratea "third party" plugin.

The story of PyScript's execution is roughly as follows:

  1. Configuration is loaded from the<py-config> tag. Once complete thepy-configured event is dispatched, containing theconfig object basedupon default values overridden by the content of the<py-config> tag.
  2. When thepy-configured event is dispatched three things happen:
    • The interpreter is loaded via injecting a<script> tag that references theinterpreter's URL. Once loaded thepy-interpreter-loaded event is dispatched.
    • Plugins are registered and have theirconfigure function called. For eachplugin registered apy-plugin-registered event is dispatched, containingthe (potentially changed)config, and a reference to the newly registeredplugin.
    • The content of the files to be added to the interpreter's filesystem arefetched. Once downloaded each file causes apy-file-fetched event to bedispatched with the path and content of the file attached to it.
  3. Whenpy-interpreter-loaded is dispatched two things happen:
    • The interpreter is instantiated / started. Once complete thepy-interpreter-readyevent is dispatched.
    • All registered plugins have theirstart function called and apy-plugin-started event is dispatched for each plugin.
  4. When thepy-interpreter-ready event is dispatched all plugins have theironInterpreterReady function called with theconfig andinterpreterobjects. At this point all files are copied onto the interpreter'sfilesystem. When all the files are copied thepy-files-loaded event isdispatched.
  5. When both the interpreter and filesystem are finished setting up and in aready state, thepy-finished-setup event is dispatched to signal PyScriptis ready to evaluate user's code.
  6. Any plugins registered after the interpreter is ready immediately have theirconfigure,start andonInterpreterReady functions called, with thepy-plugin-registered andpy-plugin-started events being dispatched.

That's it!

Whenpyscript.js is run, it creates awindow.PyScript object that containsread-only references to theconfig, registeredplugins,availableInterpreters, theinterpreter used on the page, anisInterpreterReady flag, aregisterPlugin function (see below) and arunPython(code) function that takes a string of Python.

There are copious comments in thepyscript.js file. My intention is forsimplicity, lack of onerous dependencies (bye-byenpm), andunderstandability. This code is good if it's easy to understand what's goingon. To this end, it's laid out in a "literate" manner, so the code "tells thestory" of this implementation of PyScript by reading it from top to bottom.

Plugins

Plugins are inspired by Antonio's suggestionfound here,and should be relatively self explanatory.

Since simplicity is the focus, plugins are simply JavaScript objects.

Such objects are expected they have aname attribute referencing a stringnaming the plugin (useful for logging purposes). Plugins should also provideone or more of the following functions attached to them, called in thefollowing order (as the lifecycle of the plugin):

  • configure(config) - Gives the plugin early access to theconfig object.Potentially, the plugin can modify it, and modifications will be visible tolater steps and other plugins. Plugins must only modify the config at thispoint in their life-cycle. Examples of things which plugins might want to doat this point:
    • Early sanity check about their own options.
    • Rename/remap some options.
    • Add new packages to install.
    • Modify options for other plugins (e.g. a debugger plugin might set theoptionshow_terminal).
  • start(config) - The main entry point for plugins. At this point, configshould not be modified by the plugin. Example use cases:
    • Define custom HTML elements.
    • Start fetching external resources.
  • onInterpreterReady(config, interpreter) - Called once the interpreter isready to evaluate Python code. Example use cases:
    • pip install packages.
    • Import/initialize Python plugins.

The following events, dispatched by PyScript itself, are related to plugins:

  • py-plugin-registered - Dispatched when a plugin is registered (and theevent contains a reference to the newly registered plugin). This happensimmediately after the plugin'sconfigure function is called.
  • py-plugin-started - Dispatched immediately after a plugin'sstartfunction is called. The event contains a reference to the started plugin.
  • py-interpreter-ready - causes each plugin'sonInterpreterReady functionto be called.

If a plugin is registeredafter the interpreter is ready, all three functionsare immediately called in the expected sequence, one after the other.

The recommended way to create and register plugins is:

constmyPlugin=function(e){/*    Private and internal logic, event handlers and event dispatch can happen    within the closure defined by this function.    e.g.    const FOO = "bar";    function foo() {        const myEvent = new CustomEvent("my-event", {detail: {"foo": FOO}});        document.dispatchEvent(myEvent);    }    function onFoo(e) {        console.log(e.detail);    }    document.addEventListener("my-event", onFoo);    ...    */constplugin={name:"my-plugin",configure:function(config){// ...},start:function(config){// ...foo();},onInterpreterReady:function(config,interpreter){// ...}};window.pyScript.registerPlugin(plugin);}();document.addEventListener("py-configured",myPlugin);

Then in your HTML file:

<scriptsrc="myplugin.js"></script><scriptsrc="pyscript.js"type="module"></script>

Interpreters

TheInterpreter class abstracts away all the implementation details of thevarious Python interpreters we might use.

To see a complete implementation see theMicroPythonInterpreter class thatinherits fromInterpreter. There is also an incompletePyodideInterpreterclass so I was able to compare and contrast the differences betweenimplementations and arrive at a general abstraction (still very much a work inprogress). Comments in the code should explain what's going on in terms of thelife-cycle and capabilities of a "interpreter".

The afore mentionedMicroPythonInterpreter,CPythonInterpreter andPyodideInterpreter all, to a greater or lesser extent, define a uniform shimaround their respective interpreter. The MicroPython one is most complete, butstill needs work as I make changes to how MicroPython itself exposesstdout,stderr and consumesstdin.

The future

Who knows..? But this is a good scaffold for testing different Pythoninterpreters.

Next steps:

  • More comprehensive tests.
  • CPythonInterpreter fully implemented.
  • PyodideInterpreter finished.
  • MicroPythonInterpreter refactored after making MicroPython play nicer withstdout andstderr.
  • A uniform way topip install packages in each interpreter.
  • A uniform JavaScript gateway from within each interpreter.
  • A uniformnavigator object through which to access the DOM from within eachinterpreter.
  • Running in web-workers (and associated message passing work), for eachinterpreter.

That's it..! ;-)

About

MicroPyScript: A test harness for multiple runtimes in PyScript

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp