PyScript is tool that allows Python code to run directly in the browser via web assembly (Wasm).
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>
We start by linking PyScript and you you can do that in two ways:
- Download a copy of the latest version of PyScript, and add the required files to
head
in your HTML document: - 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>
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
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>
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!")
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>
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.
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)
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.
Good Work