【问题标题】:mypy doesn't recognize SQLAlchemy columns with hybrid_propertymypy 无法识别具有 hybrid_property 的 SQLAlchemy 列
【发布时间】:2022-12-22 15:08:38
【问题描述】:

我正在尝试将 mypy 与 SQLAlchemy 一起使用。 为了验证/修改特定的列值(在本例中为email),SQLAlchemy official document提供了hybrid_property装饰器。

问题是,mypy 无法正确识别 EmailAddress 类构造函数,它给出:

email_address.py:31: error: Unexpected keyword argument "email" for "EmailAddress"; did you mean "_email"?

我如何告诉 mypy 识别这些列?

from typing import TYPE_CHECKING

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

# I don't even like the following statements just for setter
if TYPE_CHECKING:
    hybrid_property = property
else:
    from sqlalchemy.ext.hybrid import hybrid_property

Base = declarative_base()


class EmailAddress(Base):
    __tablename__ = "email_address"

    id = Column(Integer, primary_key=True)

    _email = Column("email", String)

    @hybrid_property
    def email(self):
        return self._email

    @email.setter
    def email(self, email):
        self._email = email


EmailAddress(email="foobar@example.com")
# email_address.py:31: error: Unexpected keyword argument "email" for "EmailAddress"; did you mean "_email"?

我正在使用以下软件包:

SQLAlchemy==1.4.35
mypy==0.942
mypy-extensions==0.4.3
sqlalchemy2-stubs==0.0.2a22

【问题讨论】:

  • 到目前为止,您是否找到了让它发挥作用的方法?
  • @Welyweloo,不。在对象初始化后分配属性“技术上”可以避免 mypy 错误,但这与我想要的相差甚远,例如 email = EmailAddress() 然后 email.email = "foobar@example.com"
  • @Welyweloo,我在下面写下了我的答案。

标签: python sqlalchemy mypy


【解决方案1】:

好的,看来我终于找到了解决问题的方法。

这让我想起了here 中讨论的数据类/属性装饰器之间的不合作行为。

我最终将 EmailAddress 类分成 2 个:

  1. 在基类上使用 @dataclass 装饰器以指示构造函数选项。
  2. 覆盖email 属性,这样 mypy 就不会抱怨重新定义。
    from dataclasses import dataclass
    from typing import TYPE_CHECKING, Optional
    
    from sqlalchemy import Column, Integer, String, Table
    from sqlalchemy.orm import registry
    
    mapper_registry: registry = registry()
    
    # I don't even like the following statements just for setter
    if TYPE_CHECKING:
        hybrid_property = property
    else:
        from sqlalchemy.ext.hybrid import hybrid_property
    
    
    @dataclass
    @mapper_registry.mapped
    class EmailAddressBase:
        __tablename__ = "email address"
    
        id: int = Column(Integer, primary_key=True)
        email: Optional[str] = None
    
    
    class EmailAddress(EmailAddressBase):
        _email = Column("email", String)
    
        @hybrid_property
        def email(self):
            return self._email
    
        @email.setter
        def email(self, email):
            self._email = email
    
    
    email = EmailAddress(email="foobar@example.com")
    print(email.email)
    

【讨论】:

    猜你喜欢
    • 2021-02-03
    • 2021-10-22
    • 2022-01-23
    • 2020-05-16
    • 2020-09-08
    • 2022-01-13
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多