DEV Community

Cover image for PyScript: Python in the Browser
PGzlan
PGzlan

Posted on

PyScript: Python in the Browser

PyScript is tool that allows Python code to run directly in the browser via web assembly (Wasm).

WebAssemMeme

This opens up opportunities to use Python for frontend web development and interact with JavaScript environments from Python. In this blog post, we'll explore what PyScript is, how to use it, and provide some code examples.

What is PyScript?

PyScript is a framework that allows users to create rich Python applications in the browser using HTMLโ€™s interface and the power of Pyodide, WASM, and modern web technologies. The PyScript framework provides users at every experience level with access to an expressive, easy-to-learn programming language with countless applications. [It enables users to run Python code directly in their browser, giving anyone the ability to program without infrastructure barriers. You can add an interactive Python REPL directly to your website, share an interactive dashboard with a colleague as an HTML file, or create a client-side Python-powered web application.

Some of the key features of PyScript include:

  • It allows users to write and run Python code in HTML.
  • It allows users to build web applications using Python
  • It allows sharing machine learning models in an HTML file so that others can run those models in their browsers
  • It helps to avoid setup
  • It allows using UI components such as buttons, containers, text boxes, etc

So in summary, PyScript allows writing frontend code with the Python programming language and interacting seamlessly with JavaScript environments, all running natively in the browser via WebAssembly.

How do I use PyScript?

To use PyScript, you do not require any development environment other than a web browser (Chrome is recommended. Long Live ๐Ÿ”ฅ๐ŸฆŠ) and a text editor, even though using your IDE of choice might be convenient

That's it. There is no installation required. The PyScript assets served on pyscript.net which makes the process of getting up and running pretty easy.

Our first PyScript file

Using your favorite editor, create a new file called with the html extension (This ideally should be in the same directory as your support Python Script(s), JavaScript, and CSS files with the following content, and open the file in your web browser.

For the sake of brevity, let's assume the file you created is called index.html

<html>
  <head>
    <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css"/>
    <script defer src="https://pyscript.net/latest/pyscript.js"></script>
  </head>
  <body>
    <input type="color" id="color-picker">
    <div id="text" style="font-size: 48px">Hello World!</div>
    <py-script>
from js import document
from pyodide.ffi import create_proxy
color_picker = document.getElementById("color-picker")
text = document.getElementById("text")
def on_color_change(event):
    text.style.color = event.target.value
color_picker.addEventListener("change", create_proxy(on_color_change))
    </py-script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

We start by linking PyScript and you you can do that in two ways:

  1. Download a copy of the latest version of PyScript, and add the required files to head in your HTML document:
  2. Add the CDN version of PyScript's JS and CSS files to head in your HTML document:

This script is an HTML file that uses PyScript to create a color picker and change the color of the text based on the selected color. The logic is present inside the <py-script> tag

<html>
  <head>
      ...
  </head>
  <body>
    <input type="color" id="color-picker">
    <div id="text" style="font-size: 48px">Hello World!</div>
    <py-script>
from js import document
from pyodide.ffi import create_proxy

color_picker = document.getElementById("color-picker")
text = document.getElementById("text")

def on_color_change(event):
    text.style.color = event.target.value

color_picker.addEventListener("change", create_proxy(on_color_change))
    </py-script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

When you open this file in a web browser, you will see an input element of type color that allows you to select a color, and a div element containing the text โ€œHello World!โ€ in a large font size.

The script uses PyScript to select the color picker and the div element using their IDs, and defines a function on_color_change that is called whenever the value of the color picker changes.

In this function, the style.color property of the div element is set to the value of the color picker.

The script also attaches an event listener to the color picker to call the on_color_change function whenever its value changes. As a result, when you select a color using the color picker, the color of the text will change accordingly.

If you take a closer look at the addEventListener, you'll notice a function called create_proxy that wraps the on_color_change function.

This purpose of this function comes from the fact that Pyodide needs to briefly proxy the Python function on_color_change so the JS function addEventListener knows how to interact with it. But once addEventListener terminates, that proxy is no longer needed, it gets destroyed... and then when an event comes around to trigger your function, the proxy it should be using is gone. This will cause the script to return the following error

Uncaught Error: This borrowed proxy was automatically destroyed at the end of a function call. Try using create_proxy or create_once_callable.
The object was of type "function" and had repr
Enter fullscreen mode Exit fullscreen mode

The two functions that are mentioned in the error create a PyProxy (a JS object) of your Python object that you, the user, are supposed to manage the lifetime of, by calling PyProxy.destroy() on it when you're done with it. Or, if you use create_once_callable(), the proxy will destroy() itself after the first time it's called.

For an object such as an event listener, destroying the proxy for the lifetime of your page may not be a desirable thing, so you can just leave it hanging around. It's worth noting that if you remove that event listener or the element attached to it, you should plan to track and destroy the PyProxy, to avoid taking up memory.

Interacting with JavaScript

A major benefit of PyScript is being able to directly interact with JavaScript from Python code. This enables full integration with frontend frameworks and libraries.

PyScript provides a js module that exposes JavaScript functions and objects to Python. For example:

<html>
  <head>
    <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css"/>
    <script defer src="https://pyscript.net/latest/pyscript.js"></script>
    <script>
    name = "๐ŸฆŠ";
    function sayMyName(name){
        console.log(name);
    }
    </script>
  </head>
  <body>
    <py-script>
from js import name, sayMyName

print(f"Hello {name}")
print("Saying your name in Javascript: " + str(sayMyName('Dev.to')))
    </py-script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Image description

Here we define a Python function that calls out to JavaScript's console.log(). When compiled and run, it will print the passed name. It can also be seen in the console of the web browser.

We can also access global JavaScript objects. For example, to display a alert popup:

import js

js.alert("Hello from Python!")
Enter fullscreen mode Exit fullscreen mode

So PyScript provides full interoperability between Python and JavaScript for building hybrid applications.

Async/Await Support

Another key feature of PyScript is built-in support for asyncio and async/await syntax. This enables writing asynchronous Python code that integrates cleanly with async-based JavaScript code and event loops.

For example, we can write an async function that performs a simulated async task:

<html>
  <head>
    <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css"/>
    <script defer src="https://pyscript.net/latest/pyscript.js"></script>
  </head>
  <body>
    <py-script>
import asyncio
import js
from pyodide.ffi import create_proxy

async def do_task():
  await asyncio.sleep(1)
  print("Task finished!")

async def main():
  await do_task()
  print("Done!")

js.setTimeout(create_proxy(main), 0)  
    </py-script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Here we define an async function do_task() that sleeps for 1 second, and call it from the main function main(). We schedule main() to run asynchronously after 0 seconds using JavaScript's setTimeout().

When compiled and run, this will output the lines with a 1 second delay in between, demonstrating asyncio integration with the browser's event loop.

Image description

Conclusion

PyScript provides an intriguing new way to use Python for frontend web development by compiling it to WebAssembly. It maintains the core Python syntax and semantics while enabling seamless interoperability with JavaScript.

Some key advantages it offers include:

  • Familiar Python syntax for writing frontend code
  • Full asyncio/await support for asynchronous programming
  • Interactive usage directly in browsers via debugging tools
  • Performance comparable to JavaScript with WebAssembly compilation
  • Reuse of Python skills, libraries and frameworks

PyScript is a powerful tool for building frontend apps with Python. I'm excited to see where the project goes and do intend to play around with it a little more

Top comments (2)

Collapse
 
usamaa profile image
Osama B.Sassi • Edited

Hey PGzlan, just wanted to drop a big thanks your way! Your tutorial on PyScript framework was a lifesaver. It caught me up on things I'd forgotten and even introduced me to the whole Async/Await Support thing.

I'm feeling inspired now and I've got something to add to your awesome post. I'm sharing a link to my GitHub where I've got this little PyScript project from my past. It's also a PWA, which I think could be a real game-changer for newbies diving into the world of PyScript. Your tutorial got my gears turning, and I'm all about helping this PyScript community grow. Thanks again!

Installable PyScript application that runs offline.

Collapse
 
robinamirbahar profile image
Robina

Good Work