Python editor
The PyEditor is a core plugin.
Warning
Work on the Python editor is in its early stages. We have made it available in this version of PyScript to give the community an opportunity to play, experiment and provide feedback.
Future versions of PyScript will include a more refined, robust and perhaps differently behaving version of the Python editor.
If you specify the type of a <script>
tag as either py-editor
(for Pyodide)
or mpy-editor
(for MicroPython), the plugin creates a visual code editor,
with code highlighting and a "run" button to execute the editable code
contained therein in a non-blocking worker.
Info
Once clicked, the "run" button will show a spinner until the code is executed. This may not be visible if the code evaluation completed quickly.
The interpreter is not loaded onto the page until the run button is clicked. By default each editor has its own independent instance of the specified interpreter:
<script type="py-editor">
import sys
print(sys.version)
</script>
<script type="mpy-editor">
import sys
print(sys.version)
a = 42
print(a)
</script>
However, different editors can share the same interpreter if they share the
same env
attribute value.
<script type="mpy-editor" env="shared">
if not 'a' in globals():
a = 1
else:
a += 1
print(a)
</script>
<script type="mpy-editor" env="shared">
# doubled a
print(a * 2)
</script>
The outcome of these code fragments should look something like this:
Info
Notice that the interpreter type, and optional environment name is shown at the top right above the Python editor.
Hovering over the Python editor reveals the "run" button.
Setup
Sometimes you need to create a pre-baked Pythonic context for a shared environment used by an editor. This need is especially helpful in educational situations where boilerplate code can be run, with just the important salient code available in the editor.
To achieve this end use the setup
attribute within a script
tag. The
content of this editor will not be shown, but will bootstrap the referenced
environment automatically before any following editor within the same
environment is evaluated.
<script type="mpy-editor" env="test_env" setup>
# This code will not be visible, but will run before the next editor's code is
# evaluated.
a = 1
</script>
<script type="mpy-editor" env="test_env">
# Without the "setup" attribute, this editor is visible. Because it is using
# the same env as the previous "setup" editor, the previous editor's code is
# always evaluated first.
print(a)
</script>
Finally, the target
attribute allows you to specify a node into which the
editor will be rendered:
<script type="mpy-editor" target="editor">
import sys
print(sys.version)
</script>
<div id="editor"></div> <!-- will eventually contain the Python editor -->
Editor VS Terminal
The editor and terminal are commonly used to embed interactive Python code into a website. However, there are differences between the two plugins, of which you should be aware.
The main difference is that a py-editor
or mpy-editor
is an isolated
environment (from the rest of PyScript that may be running on the page) and
its code always runs in a web worker. We do this to prevent accidental blocking
of the main thread that would freeze your browser's user interface.
Because an editor is isolated from regular py or mpy scripts, one should not expect the same behavior regular PyScript elements follow, most notably:
- The editor's user interface is based on CodeMirror and not on XTerm.js as it is for the terminal.
- Code is evaluated all at once and asynchronously when the Run button is pressed (not each line at a time, as in the terminal).
- The editor has listeners for
Ctrl-Enter
orCmd-Enter
, andShift-Enter
to shortcut the execution of all the code. These shortcuts make no sense in the terminal as each line is evaluated separately. - There is a clear separation between the code and any resulting output.
- You may not use blocking calls (like
input
) with the editor, whereas these will work if running the terminal via a worker. - It's an editor! So simple or complex programs can be fully written without running the code until ready. In the terminal, code is evaluated one line at a time as it is typed in.
- There is no special reference to the underlying editor instance, while
there is both
script.terminal
or__terminal__
in the terminal.
Read / Write / Execute
Sometimes you need to programatically read, write or execute code in an
editor. Once PyScript has started, every py-editor/mpy-editor script tag gets
a code
accessor attached to it.
from pyscript import document
# Grab the editor script reference.
editor = document.querySelector('#editor')
# Output the live content of the editor.
print(editor.code)
# Update the live content of the editor.
editor.code = """
a = 1
b = 2
print(a + b)
"""
# Evaluate the live code in the editor.
# This could be any arbitrary code to evaluate in the editor's Python context.
editor.process(editor.code)
Configuration
Unlike <script type="py">
or <py-script>
(and the mpy
equivalents), a
PyEditor is not influenced by the presence of <py-config>
elements in the
page: it requires an explicit config="..."
attribute.
If a setup
editor is present, that's the only PyEditor that needs a config.
Any subsequent related editor will reuse the config parsed and bootstrapped for
the setup
editor.
Run via keyboard
Depending on your operating system, a combination of either Ctrl-Enter
,
Cmd-Enter
or Shift-Enter
will execute the code in the editor (no need to
move the mouse to click the run button).
Override run
Sometimes you just need to override the way the editor runs code.
The editor's handleEvent
can be overridden to achieve this:
<script type="mpy-editor" id="foreign">
print(6 * 7)
</script>
<script type="mpy">
from pyscript import document
def handle_event(event):
# will log `print(6 * 7)`
print(event.code)
# prevent default execution
return False
# Grab reference to the editor
foreign = document.getElementById("foreign")
# Override handleEvent with your own customisation.
foreign.handleEvent = handle_event
</script>
This live example shows how the editor can be used to execute code via a USB serial connection to a connected MicroPython microcontroller.
Tab behavior
We currently trap the tab
key in a way that reflects what a regular code
editor would do: the code is simply indented, rather than focus moving to
another element.
We are fully aware of the implications this might have around accessibility so
we followed
this detailed advice from Codemirror's documentation
We have an escape hatch to move focus outside the editor. Press esc
before
tab
to move focus to the next focusable element. Otherwise tab
indents
code.
Still missing
The PyEditor is currently under active development and refinement, so features may change (depending on user feedback). For instance, there is currently no way to stop or kill a web worker that has got into difficulty from the editor (hint: refreshing the page will reset things).