2025年3月19日水曜日

flask-sqlalchemy で pyright 用のスタブファイルを作成してみた

flask-sqlalchemy で pyright 用のスタブファイルを作成してみた

概要

flask-sqlalchemy + pyright を使っているとデータベースのモデルからインスタンスを生成する際に pyright のエラーになります
回避方法はいろいろありますが今回は pyright 用のスタブ情報を手動で作成することで対応してみました

環境

  • Python 3.12.9
    • flask-sqlalchemy 3.1.1
    • pyright 1.1.396

エラーの出るファイル

  • vim my_libs/schema.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False)


# インスタンス作成
user = User(id=1, name="Alice")

これで pyright を実行すると以下のえらーになります
これをスタブを作成することで回避します

  • pipenv run pyright my_libs/schema.py
/path/to/my_libs/schema.py
  /path/to/my_libs/schema.py:12:13 - error: No parameter named "id" (reportCallIssue)
  /path/to/my_libs/schema.py:12:19 - error: No parameter named "name" (reportCallIssue)
2 errors, 0 warnings, 0 informations

スタブファイルの自動生成

  • pipenv run pyright --createstub flask_sqlalchemy

これで typings 配下に以下のファイルが自動で生成されます

ls -ltR typings                                   
total 0
drwxr-xr-x  12 user01  staff  384  3 18 10:22 flask_sqlalchemy

typings/flask_sqlalchemy:
total 120
-rw-r--r--  1 user01  staff    171  3 18 10:22 track_modifications.pyi
-rw-r--r--  1 user01  staff    710  3 18 10:22 table.pyi
-rw-r--r--  1 user01  staff   1428  3 18 10:22 session.pyi
-rw-r--r--  1 user01  staff   1870  3 18 10:22 record_queries.pyi
-rw-r--r--  1 user01  staff   3024  3 18 10:22 query.pyi
-rw-r--r--  1 user01  staff   5279  3 18 10:22 pagination.pyi
-rw-r--r--  1 user01  staff   5297  3 18 10:22 model.pyi
-rw-r--r--  1 user01  staff  14197  3 18 10:22 extension.pyi
-rw-r--r--  1 user01  staff    321  3 18 10:22 cli.pyi
-rw-r--r--  1 user01  staff    180  3 18 10:22 __init__.pyi

動作確認

スタブファイルを作成した状態で再度 pyright を実行しましょう
先のほどまで出ていた No parameter named "name" などのエラーが出ないことが確認できると思います

おまけ: その他の解決方法

__init__ メソッドを User モデルクラスに実装する

この方法でも pyright のエラー自体は出なくなりますがコンストラクタを生成することで初期化時の処理が変わる可能性があるのであまりおすすめはしないです

dict を使い変数展開する

User 生成時にキーワード引数ではなく辞書の展開を使ってもエラーを回避できます

params = {
  "id": 1,
  "name": "hawk"
}
user = User(**params)

最後に

flask-sqlalchemy の pyright エラーに対応してみました
typings/ ディレクトリは今回は自動生成しているので git には含めないほうがいいです
手動で作成している場合は含めたほうがいいです

CI などで typings が必要な場合は毎回生成してあげるようにしましょう

おまけ: スタブファイルの手動作成(失敗編)

以下試したけどダメだったパターンです

スタブファイルはプロジェクトルートの typings というディレクトリ配下に作成します
またパッケージの階層も同じにする必要がありかつファイル名は pyi ファイルにします

  • mkdir typings
  • mkdir typings/my_libs
  • vim typings/my_libs/schema.pyi
from flask_sqlalchemy import SQLAlchemy

db: SQLAlchemy

class User():
    id: int
    name: str

    def __init__(self, id: int, name: str) -> None: ...

0 件のコメント:

コメントを投稿