Build Yourself a PyScript

What we'll cover:

  1. Get Python
  2. Python's context
  3. Interacting with the browser

1. Get Python


<!DOCTYPE html>
<html lang="en">
<head>
  <title>A simple PyScript example</title>
  <script defer src="pyscript.js"></script>
</head>
<body>
  <py-script>print("Hello, world")</py-script>
</body>
</html>
          
View

pyscript.js


/*
Create a new custom tag by inheriting from the
HTMLElement class.
*/

class PyScript extends HTMLElement {
    connectedCallback() {
        /*
        Called when the element is first encountered in
        the DOM.
        */
        // Grab the source code.
        const code = this.textContent;
        // Instantiate a "Python interpreter". ;-)
        const re = /"(.*?)"/;
        // Evaluate and emit to STDOUT ;-)
        const output = code.match(re)[0].slice(1, -1);
        this.textContent = output;
    }
}

// Register the class for the given element name.
customElements.define("py-script", PyScript);
          

😲


<!DOCTYPE html>
<html lang="en">
<head>
  <title>A simple PyScript example</title>
  <script defer src="pyscript.js"></script>
</head>
<body>
  <py-script>
def hello(name="world!"):
  """
  Return a friendly greeting to the named entity.
  """
  return f"Hello, {name} (from MicroPython)."

print(hello())
  </py-script>
</body>
</html>
          
View

pyscript.js


class PyScript extends HTMLElement {
    connectedCallback() {
        // grab the source code.
        const code = this.textContent;  
        // Remove the code from the DOM.
        this.textContent = "";  
        // JavaScript oh my..! 🤦
        const self = this;
        // Handle STDOUT events.
        document.addEventListener('micropython-print', 
            function(e) {
                // Just append event data to the textual
                // content of this element.
                const output = self.textContent + e.data;
                self.textContent = output;
            }, 
            false
        );
        // Eval the code.
        mp_js_do_str(code);
    }
}


// Inject MicroPython compiled to WASM into the page, via
// a script tag.
const pyElement = document.createElement("script");
pyElement.src = "micropython.js";
pyElement.onload = function(e) {
    // Start up MicroPython
    let mp_js_startup = Module['onRuntimeInitialized'];
    Module["onRuntimeInitialized"] = async function() {
        mp_js_startup();
        mp_js_init(1024*1024);
        // Register the class for the given element name,
        // only after MicroPython is configured.
        customElements.define("py-script", PyScript);
    }
}
const head = document.getElementsByTagName('head')[0];
head.appendChild(pyElement);
          

😬😲🤔😱

2. Python's context

3. Interacting with the browser

Quickfire round


# js is globalThis (the browser window).
from js import document
# ffi is foreign function interface.
from pyodide import ffi


def handler(event):
  """
  Handle an event. Append something to the DOM.
  """
  output = document.createElement("span")
  output.innerHTML = "🖱️"
  document.body.appendChild(output)


# Wrap the handler in a JS proxy.
handler_proxy = ffi.create_proxy(handler)
# Find the button, add the event listener.
button = document.querySelector("button#click-me")
button.addEventListener("click", handler_proxy)
          
View

🛑 Slow your roll 🛑

Final thoughts

  • PyScript is a platform.
  • Write code and frameworks on PyScript (ask me about PyperCard).
  • It's open source... come play!
  • For the 99% (not just coders).

Other stuff at PyCon!

  • PyScript for Education.
    Blake Rayfield (Sat, 10:45am)
  • The CPU in your browser: WASM demystified.
    Antonio Cuni (Sat, 12:15pm)
  • PyScript and the magic of Python in the browser.
    Fabio Pliger (Sat, 1:30pm)
  • Anaconda booth. (PyScript info, demos & swag!)
  • An open space. (Sunday - see the board)
  • Sprint with us! (Monday to Thursday)

Questions..?

TL;DR:

👉pyscript.com👈 - IDE 💻

pyscript.net - docs 📖

discord.gg/HxvBtukrg2 - chat 💬

ntoll.org/presentations/ - slides 🖥️

Image credits

Photo by Becca Tapert on Unsplash

Photo by Christian Wiediger on Unsplash

Photo by Valery Sysoev on Unsplash

Photo by Mathew Schwartz on Unsplash

Photo by Lia Trevarthen on Unsplash

Photo by Eric Wang on Unsplash