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?
1 Answer
Reset to default -1Adding 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
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744371019a4570951.html
spam.id
expression does return integer. Yet mypy doesn't accept this. – zefciu Commented Mar 21 at 8:42mypy
doesn't execute any code. The only way it knows whatlist[int]
means, for example, is because it's hard-coded inmypy
itself whatlist
means. Without a plugin,Mapped[int]
is just an opaque string with no defined semantics. – chepner Commented Mar 24 at 11:27