-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Closed
Labels
covariant protocol use casesormtypingpep -484 typing issues. independent of "mypy"pep -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 anticipatednot really a feature or a bug; can be support for new DB features or user use cases not anticipated
Milestone
Description
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
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
covariant protocol use casesormtypingpep -484 typing issues. independent of "mypy"pep -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 anticipatednot really a feature or a bug; can be support for new DB features or user use cases not anticipated