始めに
※ 自宅で検証した際には実装できなかったので詳細は不明です。
テスト実装中に次のエラーが発生しました。
E sqlalchemy.exc.NoInspectionAvailable: No inspection system is available for object of type <class 'models.User'>
発生原因が不明ですが、発生しないように対応できたのでその件を記事にします。
環境
- Python
- 3.12.3
- SQLAlchemy
- 2.0.27
- 発生したバージョン
- 2.0.31
- 再現できず
- 2.0.27
対応
インスタンスをcopy
して対応しました。または、commit
でも対応はできそうです。
もともとやりたかったことはDBの値をHTTPリクエストで更新できるかどうかをチェックすることでしたが、項目数が多かったのでDBにinsertしたインスタンスを元に加工していました。その加工方法が誤っており、エラーが発生した模様です。
import copy deftest_01(session: AsyncSession) user = User(name="test") session.add(user) await session.flush() # NOTE: この処理が非常に重要だった# DBを元に入力値で更新するテストのために加工 copied_user = copy.copy(user.__dict__) _ = copied_user.pop("_sa_instance_state") copied_user['name'] = "testUpd"# copied_userをJSON化したりして、なんやかんやで入力用に加工# DBからuserを取得しようとしてエラー query: select = select(User).where(User.name == "test") actual = (await db.execute(query)).scalars().first()
原因
自宅で再現できなかったので想像です。
次のエラーはmodels.User
を操作したときにSQLAlchemyのメタデータが正しく取得できず、インスタンスとDBを紐づける操作ができなかった時に発生します。
E sqlalchemy.exc.NoInspectionAvailable: No inspection system is available for object of type <class 'models.User'>
今回、DBに登録したインスタンスを元に入力値を加工しようとしたので、HTTPリクエスト時のJSONBodyに不要だと判断したSQLAlchemyのMetadataの_sq_instance_state
を削除しています。
copied_user = user.__dict__
_ = copied_user.pop("_sa_instance_state")
SQLAlchemyを使用して同一トランザクション内で処理する場合、処理結果をキャッシュに保持していて、処理結果に紐づいたインスタンスを返却します。今回の例でいうと、user
とactual
が別名ですが同一インスタンスを指しています。
user = User(name="test") session.add(user) ... query: select = select(User).where(User.name == "test") actual = (await db.execute(query)).scalars().first()
そして、__dict__
を使用したらインスタンスをDeepCopyできていると勘違いしたので、このcopied_user
も同じインスタンスです。
copied_user = user.__dict__
_ = copied_user.pop("_sa_instance_state")
そのため、次のタイミングでインスタンスにマッピングしようとしたところ、本来マッピングできるはずのuser
インスタンスが存在せずにメタデータのエラーが発生したと思われます。
query: select = select(User).where(User.name == "test") actual = (await db.execute(query)).scalars().first()
だからこそ、copy
でインスタンスをDeepCopyしたことにより、今回の事象を回避できたと推測してます。
copied_user = copy.copy(user.__dict__)
ソースコード
再現できなかったのでなし。
終わりに
起こった事象自体はかなりニッチな内容で、一般的に役に立たない記事かもしれませんが、NoInspectionAvailable
で調べた際に私の記事が参考になって解決できると幸いです。