flask-sqlalchemy
flask-sqlalchemy copied to clipboard
Type (typehint) error for `db.relationship`
Problem Description
The typehint of
db.relationship("...", secondary=..., back_populates="...")
should be sq_orm.Relationship[...], not sq_orm.RelationshipProperty[...].
The mismatch of the typehint causes the manual annotation supported by sqlalchemy fails:
How to fix it
Go here: https://github.com/pallets-eco/flask-sqlalchemy/blob/42a36a3cb604fd39d81d00b54ab3988bbd0ad184/src/flask_sqlalchemy/extension.py#L953-L963
Make this modification:
def relationship(
self, *args: t.Any, **kwargs: t.Any
- ) -> sa_orm.RelationshipProperty[t.Any]:
+ ) -> sa_orm.Relationship[t.Any]:
"""A :func:`sqlalchemy.orm.relationship` that applies this extension's
Things will get corrected.
It is also recommended to modify this place:
https://github.com/pallets-eco/flask-sqlalchemy/blob/42a36a3cb604fd39d81d00b54ab3988bbd0ad184/src/flask_sqlalchemy/extension.py#L977-L979
But the following place should NOT be changed, because it is consistent with sq_orm:
https://github.com/pallets-eco/flask-sqlalchemy/blob/42a36a3cb604fd39d81d00b54ab3988bbd0ad184/src/flask_sqlalchemy/extension.py#L965-L967
Codes with typehint errors when using flask-sqlalchemy
# -*- coding: UTF-8 -*-
try:
from typing import List
except ImportError:
from builtins import list as List
from flask_sqlalchemy import SQLAlchemy
import sqlalchemy as sa
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass
class Base(DeclarativeBase, MappedAsDataclass):
"""The base class for creating SQLAlchemy models.
All mixins are defined in the mro list.
All metadata of are defined as attributes.
"""
db = SQLAlchemy(model_class=Base)
roles = db.Table(
"role_users",
sa.Column("user_id", sa.ForeignKey("user.id"), primary_key=True),
sa.Column("role_id", sa.ForeignKey("role.id"), primary_key=True),
)
class User(db.Model):
id: Mapped[int] = mapped_column(primary_key=True, init=False)
# Expression of type "RelationshipProperty[Any]" cannot be assigned to declared type "Mapped[List[Role]]"
# "RelationshipProperty[Any]" is incompatible with "Mapped[List[Role]]"Pylance[reportAssignmentType]
# (https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportAssignmentType)
roles: Mapped[List["Role"]] = db.relationship(
"Role", secondary=roles, back_populates="users", default_factory=list
)
class Role(db.Model):
id: Mapped[int] = mapped_column(primary_key=True, init=False)
# Expression of type "RelationshipProperty[Any]" cannot be assigned to declared type "Mapped[List[User]]"
# "RelationshipProperty[Any]" is incompatible with "Mapped[List[User]]"Pylance[reportAssignmentType]
# (https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportAssignmentType)
users: Mapped[List["User"]] = db.relationship(
"User", secondary=roles, back_populates="roles", default_factory=list
)
Codes working perfectly if only using sqlalchemy
# -*- coding: UTF-8 -*-
try:
from typing import List
except ImportError:
from builtins import list as List
import sqlalchemy as sa
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass
class Base(DeclarativeBase, MappedAsDataclass):
"""The base class for creating SQLAlchemy models.
All mixins are defined in the mro list.
All metadata of are defined as attributes.
"""
roles = sa.Table(
"role_users",
Base.metadata,
sa.Column("user_id", sa.ForeignKey("user.id"), primary_key=True),
sa.Column("role_id", sa.ForeignKey("role.id"), primary_key=True),
)
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True, init=False)
roles: Mapped[List["Role"]] = relationship(
"Role", secondary=roles, back_populates="users", default_factory=list
)
class Role(Base):
__tablename__ = "roles"
id: Mapped[int] = mapped_column(primary_key=True, init=False)
users: Mapped[List["User"]] = relationship(
"User", secondary=roles, back_populates="roles", default_factory=list
)
Environment:
- Python version:
3.10.13 - Flask-SQLAlchemy version:
3.1.1 - SQLAlchemy version:
2.0.28
Happy to review a PR.