joinedload() fails static type checking (Pyright/Pylance) when using SQLModel relationships
#1853
Replies: 2 comments 2 replies
-
|
This is more of an SQLAlchemy issue. A lot of syntaxes are not type supported yet. If you don't want to turn type checking off for the whole project, one option is to isolate sqlalchemy code and turn off type checking for the those modules or packages only (i.e repository pattern) |
Beta Was this translation helpful? Give feedback.
-
|
Update/Clarification on the Typing Issue: After digging deeper and comparing this to pure SQLAlchemy 2.0, I realized this is definitely a SQLModel typing limitation, not a SQLAlchemy issue. The error happens because of how Pyright handles class-level vs. instance-level types for relationships. In pure SQLAlchemy 2.0, we use # Pure SQLAlchemy 2.0 (Passes Static Analysis)
class Employee(Base):
call_center: Mapped["CallCenter"] = relationship()
# Pyright reads Employee.call_center as QueryableAttribute["CallCenter"]
stmt = select(Employee).options(joinedload(Employee.call_center)) However, SQLModel requires us to type the relationship using standard Pydantic-compatible hints: # SQLModel
class Employee(SQLModel, table=True):
call_center: CallCenter | None = Relationship()Because static type checkers (like Pyright/mypy) do not execute SQLModel's metaclass at analysis time, they interpret So when we pass Potential Solutions for SQLModel:
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
First Check
Commit to Help
Example Code
Description
When using SQLAlchemy's eager loading options like
joinedload(), passing a SQLModel relationship directly (e.g.,joinedload(Model.relationship)) results in static type checking errors in Pyright/Pylance.The static analyzer reads the relationship as the associated Model type (or
Model | None), butjoinedload()expects aQueryableAttribute. While this works perfectly at runtime due to SQLModel's metaclass swapping the attributes, the developer experience suffers due to the static analyzer throwing errors.Current Workaround:
Currently, the only way to satisfy the static type checker without using
# pyright: ignoreis to cast the relationship usingtyping.cast:Expected Behavior:
Ideally,
SQLModelcould provide a built-in typing utility (similar to thecol()function used for.where()clauses, but compatible with loader options) or type theRelationshipin a way that static analyzers recognize it as a valid argument for SQLAlchemy loader options.Operating System
Linux, Windows, macOS
Operating System Details
No response
SQLModel Version
0.0.38
Python Version
3.14
Additional Context
Pyright Version: 1.1.408
FastAPI Version: 0.135.1
Pydantic Version: 2.12.5
SQLAlchemy Version: 2.0.48
Beta Was this translation helpful? Give feedback.
All reactions