最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - SQLAlchemy Mapped field not correctly type-checked - Stack Overflow

programmeradmin7浏览0评论

With this code:

from typing import Protocol
from sqlalchemy import Integer
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column


class SpamProt(Protocol):
    id: int


class Base(DeclarativeBase):
    pass


class SpamModel(Base):
   id: Mapped[int] = mapped_column(Integer())


def do_with_spam(d: SpamProt) -> None:
    raise NotImplementedError()


if __name__ == "__main__":
    spam = SpamModel(id=10)
    do_with_spam(spam)

mypy is returning an error:

spam.py:24: error: Argument 1 to "do_with_spam" has incompatible type "SpamModel"; expected "SpamProt"  [arg-type]
spam.py:24: note: Following member(s) of "SpamModel" have conflicts:
spam.py:24: note:     id: expected "int", got "Mapped[int]"
Found 1 error in 1 file (checked 1 source file)

As SQLAlchemy claims to have no fully compatible typing without any plugins, I don't understand why this simplest example doesn't work. It is not a result of invariance. It is not an effect of interference from old plugin (here's the whole environment):

╭───────────────────┬─────────┬──────────╮
│ name              │ version │ location │
├───────────────────┼─────────┼──────────┤
│ greenlet          │ 3.1.1   │          │
│ mypy              │ 1.15.0  │          │
│ mypy-extensions   │ 1.0.0   │          │
│ SQLAlchemy        │ 2.0.39  │          │
│ typing_extensions │ 4.12.2  │          │
╰───────────────────┴─────────┴──────────╯

do I fundamentally misunderstand how the Mapped arguments should work?

With this code:

from typing import Protocol
from sqlalchemy import Integer
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column


class SpamProt(Protocol):
    id: int


class Base(DeclarativeBase):
    pass


class SpamModel(Base):
   id: Mapped[int] = mapped_column(Integer())


def do_with_spam(d: SpamProt) -> None:
    raise NotImplementedError()


if __name__ == "__main__":
    spam = SpamModel(id=10)
    do_with_spam(spam)

mypy is returning an error:

spam.py:24: error: Argument 1 to "do_with_spam" has incompatible type "SpamModel"; expected "SpamProt"  [arg-type]
spam.py:24: note: Following member(s) of "SpamModel" have conflicts:
spam.py:24: note:     id: expected "int", got "Mapped[int]"
Found 1 error in 1 file (checked 1 source file)

As SQLAlchemy claims to have no fully compatible typing without any plugins, I don't understand why this simplest example doesn't work. It is not a result of invariance. It is not an effect of interference from old plugin (here's the whole environment):

╭───────────────────┬─────────┬──────────╮
│ name              │ version │ location │
├───────────────────┼─────────┼──────────┤
│ greenlet          │ 3.1.1   │          │
│ mypy              │ 1.15.0  │          │
│ mypy-extensions   │ 1.0.0   │          │
│ SQLAlchemy        │ 2.0.39  │          │
│ typing_extensions │ 4.12.2  │          │
╰───────────────────┴─────────┴──────────╯

do I fundamentally misunderstand how the Mapped arguments should work?

Share Improve this question edited Mar 21 at 9:19 InSync 11.1k4 gold badges18 silver badges56 bronze badges asked Mar 21 at 6:06 zefciuzefciu 2,0572 gold badges17 silver badges40 bronze badges 3
  • 1 Have you tried adding __ tablename __ and a primary key to the class then run it? – Sam Commented Mar 21 at 8:23
  • My problem is not with running the code, but with mypy static checks. Yes, the tablename is missing in this minimal example. My problem is that code like this does run as expected. The spam.id expression does return integer. Yet mypy doesn't accept this. – zefciu Commented Mar 21 at 8:42
  • 1 mypy doesn't execute any code. The only way it knows what list[int] means, for example, is because it's hard-coded in mypy itself what list means. Without a plugin, Mapped[int] is just an opaque string with no defined semantics. – chepner Commented Mar 24 at 11:27
Add a comment  | 

1 Answer 1

Reset to default -1

Adding the tablename and a primary key to the class solves your issue

class SpamModel(Base):
   __tablename__ = 'spam'
   id: Mapped[int] = mapped_column(Integer(), primary_key=True)
NotImplementedError
发布评论

评论列表(0)

  1. 暂无评论