🐍

PyScript試してみた

2022/06/29に公開

先日Anaconda社から発表されたPyScriptを少し触ってみたので、調べたことと実際に触ってみた部分についてまとめてみました。

既に色んな方が記事にされてますが、自分用の備忘録として置いておきます。

PyScriptとは?

https://pyscript.net/

PyScriptとは、JavaScriptのようにHTMLファイル内にPythonのコードを記述し、その処理を実行できるようになるフレームワークです。

2022/4/27~に開催されたPyCon 2022でAnaconda社が発表しました。

https://twitter.com/anacondainc/status/1520447158603890691

PyConでのニュースを聞いていただけましたか?PyScriptは、Pythonと標準的なHTMLを組み合わせて、リッチなPythonアプリケーションをブラウザで作成できるフレームワークです!


PyScriptによるPythonコードの実行は、WebAssemlby[1]化されたPythonインタプリタによってWebブラウザ上で実行される形になっているので、サーバ側に特別な仕組みを持つ必要はありません。
この仕組みにはpyodideが使用されていて、後述するPyScript内で使用できる外部モジュールの一覧もこのpyodideに依存しています。

使い方

インストール

インストールは不要で、HTMLファイルのheadタグ内にCDN情報[2]をコピーするだけです。

余談ですが、トップページのInstallを押すと、下記のように「冗談だよ、インストールする必要ないよ」と言われます。お茶目。

基本の書き方(py-scriptタグ)

pythonで記述したい箇所を<py-script>タグで囲んで、コードを記述します。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>Hello World With PyScript</title>

    <!--CDN情報を記述-->
    <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
    <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
  </head>

  <body>
    Hello World! <br>
    このページは、<span id="time"></span>に開かれました。
    <py-script>
        from datetime import datetime
        now = datetime.now()
        pyscript.write("time", now.strftime("%Y/%m/%d %H:%M:%S"))
        print("printなどの標準出力もページに表示されます。")
    </py-script>
  </body>
</html>


webページでの確認結果:

pythonなのでタグ内はインデントを揃える必要がありますが、この時基準になるインデントはpy-scriptタグ内に記述した最初の行のインデントになります。どんなにネストした要素の中でも0インデントで始めないといけない、という縛りがないのは嬉しいなと思いました。

ただし、py-scriptタグと同じ行に最初の行を書くと0インデント扱いになるようで、その場合は次の行からの記述も0インデント基準にしないとエラーになります。

    <!-- これはOK -->
    ...
    <py-script> from datetime import datetime
now = datetime.now()
now.strftime("%Y/%m/%d %H:%M:%S")
    </py-script>
    ...

    <!-- これはダメ(インデントエラー) -->
    ...
    <py-script> from datetime import datetime
        now = datetime.now()
        now.strftime("%Y/%m/%d %H:%M:%S")
    </py-script>
    ...

外部ライブラリを使う(py-envタグ)

PyScriptでは前述のようにPyodide[3]を使っていて、Pyodideに組み込まれているライブラリは使用することができます。一覧は下記のサイトで確認できます:

https://pyodide.org/en/stable/usage/packages-in-pyodide.html

制約として、Pyodide自体がCpythonのWebAssembly移植版なので、使用できる(この一覧に載っている/載る可能性がある)のはC拡張機能を持った外部ライブラリだけみたいです。NumPy、pandas、SciPy、Matplotlib、scikit-learnなどを使用することができます。

これらの外部ライブラリを使いたい場合は、headタグ内に<py-env>タグを使って記述します。
モジュール名を書く以外にも、ローカルのwhlファイル[4]へのリンクも使用できます。

下記は公式ドキュメントより引用:

<html>
    <head>
      <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
      <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
      <py-env>
        - numpy
        - matplotlib
      </py-env>
    </head>

  <body>
    <h1>Let's plot random numbers</h1>
    <div id="plot"></div>
    <py-script output="plot">
      import matplotlib.pyplot as plt
      import numpy as np

      x = np.random.randn(1000)
      y = np.random.randn(1000)

      fig, ax = plt.subplots()
      ax.scatter(x, y)
      fig
    </py-script>
  </body>
</html>

ローカルのモジュール

ローカルで作成した.pyファイルもモジュールとして読み込むことができます。その場合は、前述の<py-env>タグの一覧にpaths:キーでリンクを記述します。
.pyファイル内でimportしているライブラリがある場合、それらもpy-envタグ内に記述が必要です。

例:./greeting.pyファイル

def say_hello(name=None):
    greeting = "Hello"
    greeting = greeting + f", {name}" if name else greeting
    print(greeting) 

htmlファイル

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>Hello World With PyScript</title>

    <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
    <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
    <py-env>
        - paths:
            - ./greeting.py
    </py-env>
  </head>

  <body>
    <py-script>
        from greeting import say_hello
        say_hello("hoge")
    </py-script>
  </body>
</html>

python側の環境設定(py-configタグ)

<py-config>タグを使用して、PyScriptアプリケーションに関する一般的なメタデータをYAML形式で設定できます。
サポートしている設定について、詳しくは公式ドキュメントを参照してください。

https://github.com/pyscript/pyscript/blob/main/docs/tutorials/getting-started.md#the-py-config-tag

触ってみた感想

  • 正直フロントのファイルの中にインデントが命なpythonのコードが入ってくるのはちょっと違和感があります。ただ、最初の行のインデント数を基準にしてくれるのは嬉しいなと思いました。
    • ローカルモジュールが使えるので、実際に使うってなったらpythonのロジック部分はpythonファイルに書き出しちゃってhtmlファイルからは呼び出すだけ、みたいな感じになりそうな気がします。
  • 公式サイトにはっきりとThere are many known issues, from usability to loading timesと書かれているように、実際現状は読み込み時間が結構長いと感じました。他にもこれから何とかなりそうだけどこれどうなんだろう?みたいな部分はありました。
    • TypeScriptとの兼ね合い
    • 外部パッケージのバージョンがpyodideに依存する
  • とはいえ、手軽にpython叩けるのは夢があるなと思ったので、今後の展開が楽しみです。
脚注
  1. WebAssemlby: ブラウザでプログラムを高速実行するために制定された、ブラウザ上で動くバイナリコードの新しいフォーマット ↩︎

  2. CDN(Content Delivery Network): デジタルコンテンツをインターネット上で効率的かつスピーディに配信するためのネットワークのこと。 ↩︎

  3. WebAssemblyに基づくブラウザーおよびNode.js用のPythonディストリビューション。ブラウザにpythonパッケージをインストールして実行できる。 ↩︎

  4. Pythonで利用されるパッケージの形式(フォーマット)。拡張子はwhlで、実態はZIPフォーマットのアーカイブファイルのこと。オフライン環境でパッケージインストールを行う際などに使用する。pipでパッケージをインストールする時も、このwheel形式のファイルをダウンロードするところから始まっている。 ↩︎

Discussion