PyScript: Second Impressions
Tags: python, javascript
Published: 2022-12-24 14:32:52

PyScript lets you run Python directly in the browser.

I tried PyScript once before, [but back then it didn't even run](https://dev.to/taw/open-source-adventures-episode-58-pyscript-first-impressions-4684). Fortunately it got over this issue, and now it runs.

### Installation

There's probably some way to get it through npm or pip, but PyScript is intended to be used with just plain JS and CSS files.
As it's still pre-1.0, and API can change anytime, let's get local copy of these two files:

* https://pyscript.net/latest/pyscript.js
* https://pyscript.net/latest/pyscript.css

### Hello, World!

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Hello World</title>
  <link rel="stylesheet" href="./pyscript.css" />
  <script defer src="./pyscript.js"></script>
  <style>
    body {
      margin: 0;
    }
  </style>
</head>
<body>
  <py-script>
    print("Hello World")
  </py-script>
</body>
</html>
```

[You can view it here](https://taw.github.io/open-source-adventures/pyscript/hello/index.html).

### FizzBuzz

Of course we can do a FizzBuzz:

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>FizzBuzz</title>
  <link rel="stylesheet" href="./pyscript.css" />
  <script defer src="./pyscript.js"></script>
  <style>
    body {
      margin: 0;
    }
  </style>
</head>
<body>
  <py-script>
    for i in range(1, 101):
      if i % 15 == 0:
        print("FizzBuzz")
      elif i % 3 == 0:
        print("Fizz")
      elif i % 5 == 0:
        print("Buzz")
      else:
        print(i)
  </py-script>
</body>
</html>
```

[You can view it here](https://taw.github.io/open-source-adventures/pyscript/fizzbuzz/index.html).

### Prompt Input

So we got it running in the browser, but it did nothing exciting.

Interaction is extremely limited. For an obvious approach, we could use `input` function:

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Prompt Input</title>
  <link rel="stylesheet" href="./pyscript.css" />
  <script defer src="./pyscript.js"></script>
  <style>
    body {
      margin: 0;
    }
  </style>
</head>
<body>
  <py-script>
    name = input("What is your name? ")
    print(f"Hello, {name}")
  </py-script>
</body>
</html>
```

But it will use browser prompt without showing the prompt question, and with the page being totally blank! You only see the prompt after you answered it. So that's pretty much useless.

[You can view it here](https://taw.github.io/open-source-adventures/pyscript/prompt/index.html).

### Interacting with DOM

PyScript has extremely minimal set of DOM bindings.

You can select DOM elements with `pyscript.Element`, and you can read and write from them, but there are no event bindings, so it's not possible to have some button that calls your Python code when clicked, or to have Python track when some form input field changes. Even worse, there's no way to create elements, either by DOM APIs or even through innerHtml. You can clone elements, so you could write a template somewhere and copy that, but that would be far more painful than even IE4 coding.

This is not even close to being minimally usable API, which would need at least `.addEventListener` and at least one of `.innerHtml=` or `.createElement`.

There are also no HTTP requests either.

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>DOM</title>
  <link rel="stylesheet" href="./pyscript.css" />
  <script defer src="./pyscript.js"></script>
  <style>
    body {
      margin: 0;
    }
    div {
      white-space: pre-wrap;
    }
  </style>
</head>
<body>
  <div id="output"></div>
  <py-script>
    from pyscript import Element
    def fizzbuzz(i):
      if i % 15 == 0:
        return "FizzBuzz"
      elif i % 3 == 0:
        return "Fizz"
      elif i % 5 == 0:
        return "Buzz"
      else:
        return str(i)
    list = Element("output")
    list.write("\n".join([fizzbuzz(i) for i in range(1, 101)]) )
  </py-script>
</body>
</html>
```

[You can view it here](https://taw.github.io/open-source-adventures/pyscript/dom/index.html).

### Should you use PyScript?

The answer changed slightly in the sense that you can at least run it, but it's not even a legitimate proof-of-concept.

It's sort of impressive that you can get Python code running in the browser, sort of, but lack of any way to interact with the page makes it unusuable even for a demo.

Still, maybe it will turn into a real thing at some point.

### Code

[All code for this post is available on GitHub](https://github.com/taw/open-source-adventures/tree/master/pyscript).