Problem
MyPy incorrectly infers the return type of SQLAlchemy AsyncSession.get() as type[T] | None instead of T | None.
This breaks type narrowing after a None check.
Environment
- Python: 3.11
- MyPy: 1.16
- SQLAlchemy: 2.0.41
- OS: Linux
Code
from sqlalchemy.ext.asyncio import AsyncSession
class WorkerProfile:
pass
async def test(db: AsyncSession) -> None:
worker_profile = await db.get(WorkerProfile, 1)
reveal_type(worker_profile)
if worker_profile is None:
return
reveal_type(worker_profile)
Observed MyPy output
First reveal_type:
type[WorkerProfile] | None
Second reveal_type (after narrowing):
Expected MyPy output
First reveal_type:
Second reveal_type:
Impact
This makes MyPy treat ORM instances as class objects (type[T]) instead of instances (T), breaking type narrowing and downstream attribute access.
Notes
- Runtime behavior is correct
- worker_profile is an instance of WorkerProfile at runtime
- This only affects static type inference
Problem
MyPy incorrectly infers the return type of SQLAlchemy AsyncSession.get() as
type[T] | Noneinstead ofT | None.This breaks type narrowing after a None check.
Environment
Code
from sqlalchemy.ext.asyncio import AsyncSession
class WorkerProfile:
pass
async def test(db: AsyncSession) -> None:
worker_profile = await db.get(WorkerProfile, 1)
Observed MyPy output
First reveal_type:
Second reveal_type (after narrowing):
Expected MyPy output
First reveal_type:
Second reveal_type:
Impact
This makes MyPy treat ORM instances as class objects (
type[T]) instead of instances (T), breaking type narrowing and downstream attribute access.Notes