Skip to content

Make Mapped covariant #10288

@RomeoDespres

Description

@RomeoDespres

Describe the use case

Mapped is currently invariant. It would make sense to have it covariant. For instance, it would help better support describing SQLAlchemy tables with protocols.

(Already discussed in #10287 - this is mainly a copy-paste of it)

Databases / Backends / Drivers targeted

All

Example Use

Currenty, the following code does not type-check. Its aim is to be able to write a general helper function get_parent_name that operate on table protocols instead of actual tables.

from typing import Protocol

from sqlalchemy import ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship


# Protocols


class ParentProtocol(Protocol):
    name: Mapped[str]


class ChildProtocol(Protocol):
    # Read-only for simplicity, mutable protocol members are complicated,
    # see https://mypy.readthedocs.io/en/latest/common_issues.html#covariant-subtyping-of-mutable-protocol-members-is-rejected
    @property
    def parent(self) -> Mapped[ParentProtocol]:
        ...


def get_parent_name(child: ChildProtocol) -> str:
    return child.parent.name


# Implementations


class Base(DeclarativeBase):
    pass


class Parent(Base):
    __tablename__ = "parent"

    name: Mapped[str] = mapped_column(primary_key=True)


class Child(Base):
    __tablename__ = "child"

    name: Mapped[str] = mapped_column(primary_key=True)
    parent_name: Mapped[str] = mapped_column(ForeignKey(Parent.name))

    parent: Mapped[Parent] = relationship()


assert get_parent_name(Child(parent=Parent(name="foo"))) == "foo"

Current mypy output:

test.py:48: error: Argument 1 to "get_parent_name" has incompatible type "Child"; expected "ChildProtocol"  [arg-type]
test.py:48: note: Following member(s) of "Child" have conflicts:
test.py:48: note:     parent: expected "Mapped[ParentProtocol]", got "Mapped[Parent]"
Found 1 error in 1 file (checked 1 source file)

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    covariant protocol use casesormtypingpep -484 typing issues. independent of "mypy"use casenot really a feature or a bug; can be support for new DB features or user use cases not anticipated

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions