Type hint一个SQLAlchemy 2声明式模型

huangapple go评论73阅读模式
英文:

Type hint a SQLAlchemy 2 declarative model

问题

I create my SQLAlchemy models in the 2.0 way:

from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "user_account"

    id: Mapped[int] = mapped_column(primary_key=True)

I'm writing a function which does something to one of these models:

def drop_table(model):
    model.__table__.drop()

如何在这里对model进行类型提示,以便我的类型提示器:

  1. 知道model.__table__有哪些方法?
  2. 接受drop_table(User)

我天真地以为我可以这样做:

def drop_table(model: Base):
    ...

但这给了我以下错误:

"Type[DeclarativeAttributeIntercept]" is incompatible with "Type[Base]"

英文:

I create my SQLAlchemy models in the 2.0 way:

from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "user_account"

    id: Mapped[int] = mapped_column(primary_key=True)

I'm writing a function which does something to one of these models:

def drop_table(model):
    model.__table__.drop()

How can I type hint model here, such that my type hinter will:

  1. Know which methods model.__table__ has got?
  2. Accept drop_table(User)?

I naively assumed I could do:

def drop_table(model: Base):
    ...

but that gives me:

> "Type[DeclarativeAttributeIntercept]" is incompatible with "Type[Base]"

答案1

得分: 1

我目前还没有完美的答案但这是我能做到的最好的

```python
from sqlalchemy.orm import MappedClassProtocol
from sqlalchemy import Table

def drop_table(model: MappedClassProtocol):
    table: Table = model.__table__  # type: ignore
    model.__table__.drop()

drop_table(User) # 这个类型检查没问题

所以,MappedClassProtocol 允许函数接受一个ORM模型,但不幸的是 model.__table__ 不是一个 Table,所以我们必须加上 # type: ignore。有人能改进这个吗?


<details>
<summary>英文:</summary>

I don&#39;t have the perfect answer so far, but here&#39;s the best I can do:

```python
from sqlalchemy.orm import MappedClassProtocol
from sqlalchemy import Table

def drop_table(model: MappedClassProtocol):
    table: Table = model.__table__  # type: ignore
    model.__table__.drop()

drop_table(User) # this type checks ok

So MappedClassProtocol allows the function to accept an ORM model, but unfortunately model.__table__ doesn't appear as a Table so we've got to do one # type: ignore.

Can anyone improve on this?

答案2

得分: 0

与您正在做的非常相似没有 `# type: ignore`,而是一个 `assert` 检查。

从搜索SQLAlchemy源代码来看这似乎是它们在内部处理的方式 - 这是我想要分享的主要信息所以我现在可能会暂时使用这个

```python
def drop_table(model: MappedClassProtocol):
    assert isinstance(model.__table__, Table)
    model.__table__.drop()

这种类型检查是没问题的。但我想对于某些结构,您可能会得到一个 AssertionError,这是mypy没有检测到的。


<details>
<summary>英文:</summary>

Pretty similar to what you&#39;re doing, without `# type: ignore` but rather an `assert` check.

From searching the SQLAlchemy source code, it looks like that&#39;s the way they do it internally - that&#39;s the main info I wanted to share. So I&#39;m probably going to use this for now.

```python
def drop_table(model: MappedClassProtocol):
    assert isinstance(model.__table__, Table)
    model.__table__.drop()

Which type-checks fine. But I guess for some constructs you could get an AssertionError that mypy hasn't detected.

huangapple
  • 本文由 发表于 2023年4月19日 23:19:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76056223.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定