From: Mike Bayer Date: Tue, 20 Jun 2023 14:11:14 +0000 (-0400) Subject: add correct descriptor methods to dynamic/writeonly X-Git-Tag: rel_2_0_17~5^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b880dca14a13c7cf861aa5531738ee303c3eded7;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git add correct descriptor methods to dynamic/writeonly Fixed typing issue which prevented :class:`_orm.WriteOnlyMapped` and :class:`_orm.DynamicMapped` attributes from being used fully within ORM queries. Fixes: #9985 Change-Id: I33eef4d06fc84e85f2ea1a997a017ffce47df7d6 --- diff --git a/doc/build/changelog/unreleased_20/9985.rst b/doc/build/changelog/unreleased_20/9985.rst new file mode 100644 index 0000000000..243fb6fb41 --- /dev/null +++ b/doc/build/changelog/unreleased_20/9985.rst @@ -0,0 +1,7 @@ +.. change:: + :tags: bug, typing + :tickets: 9985 + + Fixed typing issue which prevented :class:`_orm.WriteOnlyMapped` and + :class:`_orm.DynamicMapped` attributes from being used fully within ORM + queries. diff --git a/lib/sqlalchemy/orm/base.py b/lib/sqlalchemy/orm/base.py index 5d19cf20ad..5079dfc7c5 100644 --- a/lib/sqlalchemy/orm/base.py +++ b/lib/sqlalchemy/orm/base.py @@ -912,9 +912,19 @@ class DynamicMapped(_MappedAnnotationBase[_T]): if TYPE_CHECKING: + @overload + def __get__( + self, instance: None, owner: Any + ) -> InstrumentedAttribute[_T]: + ... + + @overload + def __get__(self, instance: object, owner: Any) -> AppenderQuery[_T]: + ... + def __get__( self, instance: Optional[object], owner: Any - ) -> AppenderQuery[_T]: + ) -> Union[InstrumentedAttribute[_T], AppenderQuery[_T]]: ... def __set__(self, instance: Any, value: typing.Collection[_T]) -> None: @@ -954,10 +964,22 @@ class WriteOnlyMapped(_MappedAnnotationBase[_T]): if TYPE_CHECKING: + @overload def __get__( - self, instance: Optional[object], owner: Any + self, instance: None, owner: Any + ) -> InstrumentedAttribute[_T]: + ... + + @overload + def __get__( + self, instance: object, owner: Any ) -> WriteOnlyCollection[_T]: ... + def __get__( + self, instance: Optional[object], owner: Any + ) -> Union[InstrumentedAttribute[_T], WriteOnlyCollection[_T]]: + ... + def __set__(self, instance: Any, value: typing.Collection[_T]) -> None: ... diff --git a/test/ext/mypy/plain_files/dynamic_rel.py b/test/ext/mypy/plain_files/dynamic_rel.py index 3aee8f3204..8b406bb171 100644 --- a/test/ext/mypy/plain_files/dynamic_rel.py +++ b/test/ext/mypy/plain_files/dynamic_rel.py @@ -3,6 +3,7 @@ from __future__ import annotations import typing from sqlalchemy import ForeignKey +from sqlalchemy import select from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import DynamicMapped from sqlalchemy.orm import Mapped @@ -80,3 +81,6 @@ with Session() as session: u.addresses.append(Address()) session.commit() + + # test #9985 + stmt = select(User).join(User.addresses) diff --git a/test/ext/mypy/plain_files/write_only.py b/test/ext/mypy/plain_files/write_only.py index 5d322a606b..619cde74e8 100644 --- a/test/ext/mypy/plain_files/write_only.py +++ b/test/ext/mypy/plain_files/write_only.py @@ -3,6 +3,7 @@ from __future__ import annotations import typing from sqlalchemy import ForeignKey +from sqlalchemy import select from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import Mapped from sqlalchemy.orm import mapped_column @@ -55,3 +56,6 @@ with Session() as session: u.addresses.add(Address()) session.commit() + + # test #9985 + stmt = select(User).join(User.addresses)