dropbox / sqlalchemy-stubs

Mypy plugin and stubs for SQLAlchemy
Apache License 2.0
573 stars 101 forks source link

Deferred columns not recognized as a column #192

Open mabeyj opened 3 years ago

mabeyj commented 3 years ago

Columns wrapped in deferred() are not recognized as a column and are typed as Any.

SQLAlchemy docs: https://docs.sqlalchemy.org/en/13/orm/loading_columns.html#deferred-column-loading

from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import deferred

Base = declarative_base()

class Model(Base):
    __tablename__ = "models"
    id = Column(Integer, primary_key=True)
    value = deferred(Column(String, nullable=False))

model = Model(value="test")

reveal_type(Model.value)
reveal_type(model.value)
> mypy deferred.py
deferred.py:12: error: Unexpected column "value" for model "Model"
deferred.py:14: note: Revealed type is 'Any'
deferred.py:15: note: Revealed type is 'Any'
Found 1 error in 1 file (checked 1 source file)

> pip freeze
mypy==0.790
mypy-extensions==0.4.3
SQLAlchemy==1.3.20
sqlalchemy-stubs @ git+https://github.com/dropbox/sqlalchemy-stubs.git@55470ceab8149db983411d5c094c9fe16343c58b
typed-ast==1.4.1
typing-extensions==3.7.4.3

However, this does work if you type the column manually:

from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import deferred

Base = declarative_base()

class Model(Base):
    __tablename__ = "models"
    id = Column(Integer, primary_key=True)
    value = deferred(Column(String, nullable=False)) # type: Column[str]

model = Model(value="test")

reveal_type(Model.value)
reveal_type(model.value)
> mypy deferred.py
deferred.py:14: note: Revealed type is 'sqlalchemy.sql.schema.Column[builtins.str*]'
deferred.py:15: note: Revealed type is 'builtins.str*'