Open12

Deno + Python

nikogolinikogoli

エラー対策その1 in 導入

公式の "Python Installation" にあるように、deno_python の利用には deno がpython310.dllなどのライブラリにアクセスできることが必要。

とりあえず↓を実行してみる

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

以下のようなメッセージが出る場合は deno がライブラリにアクセスできていない。

Could not find Python library!
Tried searching for these versions:
 (略)
However, if your Python distribution is not in search
path, you can set DENO_PYTHON_PATH env variable pointing
to dll/dylib/so file for Python library.

この場合、メッセージにあるように環境変数にDENO_PYTHON_PATHとして dll までのパス(C:\Users\*****\anaconda3\python39.dllなど)を設定する。

Deno.env.get('DENO_PYTHON_PATH')でこのパスが取得できるようになればOK[1]

脚注
  1. 実際にはOKとは限らない。Anaconda Prompt から deno を起動して deno_python を利用した場合、Deno.env.get('DENO_PYTHON_PATH')でパスが取得できてもこのエラーが出る。 ↩︎

nikogolinikogoli

エラー対策その2 in 導入

DENO_PYTHON_PATH設定後、あるいは設定前に(細かい部分は違うかもしれないが)以下のような書式のエラーが出る場合がある。

Python path configuration:
  PYTHONHOME = (not set)
  PYTHONPATH = (not set)
  program name = 'python'
  isolated = 0
  environment = 1
  user site = 1
  (略)
Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named 'encodings'

これは python 側のエラーで、PYTHONHOMEPYTHONPATHが未設定であることが原因。

↓の回答にあるように、環境変数PYTHONHOMEとしてpython.exeがあるディレクトリ(C:\Users\*****\anaconda3など)を、PYTHONPATHとしてsite-packagesのディレクトリ(C:\Users\*****\anaconda3\Lib\site-packagesなど)を設定すればOK。

https://stackoverflow.com/questions/69550830/init-fs-encoding-failed-to-get-the-python-codec-of-the-filesystem-encoding

ざっと検索したところ、python 自体はこの情報をほぼ使わないので未設定でも問題ないが、外部?から python を使おうとすると問題になる要素らしい

nikogolinikogoli

エラー対策 in 利用

公式の例にあるように、python の各ライブラリは python.import()で読み込んで利用する。

注意点として、書式が似ているからと言ってimport {} from ...を使ってはいけない。

これはダメ
// python: from PIL import Image, ImageOps
const { Image, ImageOps } = python.import("PIL")

const img = Image.open("image.png")
// → Uncaught TypeError: Cannot read properties of undefined (reading 'open')

公式の例(python.import("matplotlib.pyplot"))が示すように、ファイルを指定する形式で読み込みを行う必要がある。

これならOK
// python: from PIL import Image, ImageDraw, ImageOps
const Image = python.import("PIL.Image")
const ImageDraw = python.import("PIL.ImageDraw")

const img = Image.open("image.png")
nikogolinikogoli

ハマりがちなポイントその1

↓の場合、Imageが undefined になるだけでエラーにはならないので、気づきにくい。

const { Image, ImageOps } = python.import("PIL")

console.log()を使うと、明示的に読み込み結果を確認できる。

const Image = python.import("PIL.Image")
console.log(Image)
// <module 'PIL.Image' from 'C:\\Users\\*****\\anaconda3\\Lib\\site-packages\\PIL\\Image.py'>
nikogolinikogoli

ハマりがちなポイントその2

これは Anaconda Prompt を利用している場合のみの現象かもしれない。

import だけに限らないが、python の関数の実行中にエラーが発生した場合、エラー処理(≒エラー表示)に移行せずそのままスクリプト実行が強制終了することがある。

例えば、読み込むファイル名を間違えている以下のスクリプトにおいて、deno run -A --unstable deno_py.tsを実行すると、コンソールには何も表示されないままスクリプト実行が終了する。

deno_py.ts
const Image = python.import("PIL.image") // 正しくは "PIL.Image"
console.log(Image)

厄介なのが エラーになった時点で強制終了される点で、Error が throw すらされないのでtry {} catch {}を使っても失敗箇所を特定することができない。そのため、一文ごとに消したりconsole.log()を挟んだりして地道に調べることが必要になって辛い。

nikogolinikogoli

その他情報

nikogolinikogoli

pythonから使える機能

  • 文字列:python.str( {name: "Bob"} ) → "{'name': 'Bob'}"
  • タプル:python.tuple( [0,1,2] ) → (0, 1, 2)、配列を渡すことが必要
  • ブーリアン:
  • 辞書:
  • Ellipsis (...):
  • 整数:
  • 浮動小数点数:
  • リスト:
  • None:
  • set:
  • ビルトイン関数:const { print } = python.builtins or python.builtins.print("PIYO")
    python のドキュメントに記載があるもの全てを呼び出すことができる[1]
  • kw:python 関数にキーワード付き引数を与えるためのヘルパー (詳細は以下に)
脚注
  1. もちろん python39.dll にアクセスしている場合は 3.10 の関数は呼び出せない ↩︎

nikogolinikogoli

python.kw()

kw の後ろにname=${value}の書式で記述すると、関数にname=valueとして変数が渡される。

// python: Image.save(image, format="PNG")
// ↓↑
Image.save(image, python.kw`format=${"PNG"}`)
nikogolinikogoli

その他注意点

nikogolinikogoli

バイナリシーケンス型

組み込み型において、バイナリシーケンス型 (bytes)はサポートされていない。
https://docs.python.org/ja/3/library/stdtypes.html#binary-sequence-types-bytes-bytearray-memoryview

  • そのため、バイトオブジェクトを作ることはできない。が、array を読み込んでarray.array()を利用することで、 bytes-like object を作ることはできる
  • バイトオブジェクトそのものはサポートされている。なので、python 関数が返してくるbytesは普通にその機能を利用することができる。