DenoであらゆるPythonライブラリが使えるようになったらしいので試す

Denoからあらゆるpythonライブラリを呼び出すことができる、その名も「python」というライブラリが公開されました。

https://deno.land/x/python@0.1.0

これは面白そう…！ということで、使ってみようと思います。

## 使い方

### 1. Pythonのインストール

最初にPythonをインストールする必要があります。
自分の場合は最初からPythonが入っていたので、この手順は必要ありませんでした。
Pythonが入っていない人は適宜ググってください。

### 2. Pythonを呼び出すJSコードの作成

まずはfizzbazzを実行してみます。コードは以下のような感じになりました。

```ts
import { python } from "https://deno.land/x/python@0.1.0/mod.ts";

// `python.runModule`メソッドは、引数のpythonコードをモジュールとして実行する
const fizzbuzzModule = python.runModule(`
def fizzbuzz(len):
	return [
		"fizz" if i%6==0
		else "buzz" if i%3==0
		else "fizzfizz" if i%2==0
		else "bazzbazz"
		for i in range(len)
	]
`);

// `fizzbuzz(10)`の結果はPythonオブジェクトのラッパー
// JSで使える値に変換するには`.valueOf()`メソッドを呼ぶ
for (const i of fizzbuzzModule.fizzbuzz(10).valueOf()) {
  console.log(i);
}
```

ポイントは、

- pythonのコードを`python.runModule`に与えて実行する
  - `python.runModule`の返り値はimportしたpythonモジュールのように扱える
- pythonモジュールからimportした値や、pythonの関数の返り値をJSで扱うには`valueOf()`メソッドを呼ぶ
  - `valueOf()`自体はJSが暗黙の型変換で呼び出すことが多いので、手動で呼ぶことは少ないかも

### 3. 実行する

実行するのですが、要求されるパーミッションが大きく、`--allow-env`/`--allow-run`/`--allow-read`/`--allow-ffi`/`--unstable`フラグが必要です。

使用するPythonのdllファイルを指定するために、環境変数`DENO_PYTHON_PATH`を指定します。この変数は指定しなくてもいいのですが、指定しない場合は色々なフォルダを読みに行ってdllファイルを探すようで、その場合`--allow-read`フラグで大量のフォルダを指定する必要があります。
セキュリティ的にもよくないので、`DENO_PYTHON_PATH`を指定してしまったほうがよさそうです。

以下は自分の環境の場合を示します。`DENO_PYTHON_PATH`は各自環境に合わせた値を設定してください

```shell:実行（windowsのコマンドプロンプトの場合）
# pythonのdllファイルへのパスを環境変数に設定
> set DENO_PYTHON_PATH=C:/Users/azusa/AppData/Local/Programs/Python/Python38/python38.dll
# 実行
> deno run --unstable --allow-env=DENO_PYTHON_PATH --allow-read=DENO_PYTHON_PATH --allow-ffi ./test.ts            
```


```:output
fizz
bazzbazz
fizzfizz
buzz
fizzfizz
bazzbazz
fizz
bazzbazz
fizzfizz
buzz
```

無事、fizzbazzできました。

:::note warn
pythonコードに日本語が含まれているとエラーが出ました。
日本語が含まれているとコードの一部が欠けた状態で実行される？ことがあるようで、奇妙なエラーが発生します。
今後のアップデートで修正されることを期待しましょう。
:::
:::note warn
自分の場合はエディタのプラグイン経由で実行した時に標準出力が受け取れない事がありました。自分の環境に問題があるのかもしれませんが、python内でprint関数を使うときには正しく出力されるか確認したほうがいいかもしれません。
:::

## Pythonモジュールを使う

pythonモジュールを直接importすることもできます。

```ts
import { python } from "https://deno.land/x/python@0.1.0/mod.ts";

const { print, str } = python.builtins;
const { version } = python.import("sys");

print(str("Hello, World!").lower());
print(`Python version: ${version}`);
```

```shell
> deno run --unstable --allow-env=DENO_PYTHON_PATH --allow-read=DENO_PYTHON_PATH --allow-ffi ./private_check.ts
hello, world!
Python version: 3.8.6 (tags/v3.8.6:db45529, Sep 23 2020, 15:52:53) [MSC v.1927 64 bit (AMD64)]
```

-----

公式expamleによると、numpyやmatplotlibなども動作するようです。

```ts
import { python } from "https://deno.land/x/python@0.1.0/mod.ts";

const np = python.import("numpy");
const plt = python.import("matplotlib.pyplot");

const xpoints = np.array([1, 8]);
const ypoints = np.array([3, 10]);

plt.plot(xpoints, ypoints);
plt.show();
```

しかし、これを実行したところエラーが発生しました。

```
error: Uncaught (in promise) PythonError: No module named 'numpy'
  throw new PythonError(errorMessage);
        ^
    at maybeThrowError (https://deno.land/x/python@0.1.0/src/python.ts:641:9)
    at Python.importObject (https://deno.land/x/python@0.1.0/src/python.ts:717:7)
    at Python.import (https://deno.land/x/python@0.1.0/src/python.ts:727:17)
```

詳しく検証したいところですが、眠いので寝たいと思います
おやすみなさい～