Pyodideを試す

Pyodideは、CPythonをWebAssembly(WASM)/Emscriptenにポーティングしたソフトウェア。

PythonがWASMとして動作するので、ブラウザ上でPythonを動かせる。

pyodide.org

ドキュメントには実際に動作するREPLのリンクがある。

https://pyodide.org/en/stable/console.html

Pyodideをウェブサイト上で動かす

PyodideはWASMなので、JavaScriptから呼び出して利用可能。

また、CDNでホストされたバージョンもあるため、少し組み込んで使うくらいであれば、少量のコードでできる。

https://pyodide.org/en/stable/usage/quickstart.html

サンプルコード(ドキュメントより抜粋):

<!doctype html>
<html>
  <head>
      <script src="https://cdn.jsdelivr.net/pyodide/v0.24.1/full/pyodide.js"></script>
  </head>
  <body>
    Pyodide test page <br>
    Open your browser console to see Pyodide output
    <script type="text/javascript">
      async function main(){
        let pyodide = await loadPyodide();
        console.log(pyodide.runPython(`
            import sys
            sys.version
        `));
        pyodide.runPython("print(1 + 2)");
      }
      main();
    </script>
  </body>
</html>

CDNからスクリプトをロードし、 loadPyodide() でWASMをロード、初期化。その後は runPython()Pythonコードを実行できる。

サードパーティ製パッケージを動かす

Pyodideでは、micropipというAPIを使って、外部のPythonパッケージを動かすことができる。

Pyodideが標準モジュールをある程度サポートしていることもあり、Pure Pythonで書かれたパッケージであれば、動かすハードルは低め。

標準モジュールの互換性についてもドキュメントに記載がある。

pyodide.org

JS側、Python側どちらからでもmicropipを使える。柔軟性は高いように見える。

<script type="text/javascript">
  async function main(){
    const pyodide = await loadPyodide();
    await pyodide.loadPackage("micropip");
    const micropip = pyodide.pyimport("micropip");
    await micropip.install("regex")
  }
</script>

DjangoのIt works画面をうごかしてみる

では、Djangoを無理矢理うごかしてみる。

<!doctype html>
<html>
  <head>
    <script src="https://cdn.jsdelivr.net/pyodide/v0.24.1/full/pyodide.js"></script>
  </head>
  <body>
    <script type="text/javascript">
      async function main(){
        // setup
        const pyodide = await loadPyodide();
        await pyodide.FS.writeFile("/home/pyodide/urls.py", "urlpatterns=[]");
        await pyodide.loadPackage("micropip");
        const micropip = pyodide.pyimport("micropip");
        await micropip.install("Django")
        // run django app
        const output = pyodide.runPython(`
            import io
            import sys
            import django
            from wsgiref.handlers import BaseCGIHandler
            from django.conf import settings
            from django.core.handlers.wsgi import WSGIHandler

            settings.configure(
                ROOT_URLCONF="urls",
                SECRET_KEY="dummy",
                DEBUG=True,
            )
            django.setup()
            app = WSGIHandler()
            output = io.BytesIO()
            env = {
                "REQUEST_METHOD": "GET",
                "SERVER_NAME": "pyodide",
                "SERVER_PORT": "8000",
            }
            BaseCGIHandler(
                sys.stdin.buffer,
                output,
                sys.stderr,
                env,
                multithread=False
            ).run(app)
            response = output.getvalue().decode("utf-8")
            "".join(response.splitlines()[2:])
        `);
        document.open();
        document.write(output);
        document.close();
      }
      main();
    </script>
  </body>
</html>

Pyodideを初期化してからDjangoをインストール、その後WSGIハンドラを実行している。

実行すると、ブラウザ上でDjangoを実行して、It worksの画面が表示される。