From: Mike Bayer Date: Tue, 4 Apr 2023 14:02:30 +0000 (-0400) Subject: mypy 1.2 has fixed dataclass descriptor support X-Git-Tag: rel_2_0_10~24^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=dab175471f9ce57bcb6097dd05b341b18cd3435d;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git mypy 1.2 has fixed dataclass descriptor support Currently using the PR for test. Change-Id: Idc4c475587f5151ef79046d24ca3ac274c2cb2ca References: https://github.com/python/mypy/issues/14868 --- diff --git a/doc/build/orm/dataclasses.rst b/doc/build/orm/dataclasses.rst index 6285ddef72..bbd05fcd5e 100644 --- a/doc/build/orm/dataclasses.rst +++ b/doc/build/orm/dataclasses.rst @@ -37,53 +37,14 @@ as having Dataclass-specific behaviors, most notably by taking advantage of :pe as though it were explicitly decorated using the ``@dataclasses.dataclass`` decorator. -.. note:: Support for :pep:`681` in typing tools as of **March 11, 2023** is - limited and is currently known to be supported by Pyright_, but - **not correctly supported** by Mypy_ version 1.1.1. Mypy 1.1.1 introduced - :pep:`681` support but failed to accommodate for Python descriptors - correctly (see Github issue below). - - In order to resolve errors when using :class:`_orm.MappedAsDataclass` with - Mypy version 1.1.1 or other typing tools that have similar errors, the - following workaround may be used, which uses a plain non-pep681 mixin within - ``TYPE_CHECKING`` to avoid errors:: - - import typing - - if typing.TYPE_CHECKING: - - class MappedAsDataclass: - """Mixin class which works in the same way as - :class:`_orm.MappedAsDataclass`, - but does not include :pep:`681` directives. - - """ - - def __init__(self, *arg: typing.Any, **kw: typing.Any): - pass - - else: - from sqlalchemy.orm import MappedAsDataclass - - Above, the SQLAlchemy :class:`_orm.MappedAsDataclass` mixin is hidden - from typing tools and replaced with a plain mixin that sets up an - ``__init__`` constructor that accommodates any arguments. - - When using the :meth:`_orm.registry.mapped_as_dataclass` method, - similar approaches can be taken using a plain decorator, however classes - would need to also include an explicit ``__init__()`` method on a mixin - like the one indicated above for the workaround to work completely:: - - - def mapped_as_dataclass(registry, cls, **kw): - """Will conceal the pep-681 enabled methods from typing tools""" - - return registry.mapped_as_dataclass(cls, **kw) +.. note:: Support for :pep:`681` in typing tools as of **April 4, 2023** is + limited and is currently known to be supported by Pyright_ as well + as Mypy_ as of **version 1.2**. Note that Mypy 1.1.1 introduced + :pep:`681` support but did not correctly accommodate Python descriptors + which will lead to errors when using SQLAlhcemy's ORM mapping scheme. .. seealso:: - https://github.com/python/mypy/issues/13856 - Mypy issue on github - https://peps.python.org/pep-0681/#the-dataclass-transform-decorator - background on how libraries like SQLAlchemy enable :pep:`681` support diff --git a/test/ext/mypy/plain_files/pep681.py b/test/ext/mypy/plain_files/pep681.py new file mode 100644 index 0000000000..caa219d78b --- /dev/null +++ b/test/ext/mypy/plain_files/pep681.py @@ -0,0 +1,32 @@ +from __future__ import annotations + +from typing import Optional + +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column +from sqlalchemy.orm import MappedAsDataclass + + +class Base(MappedAsDataclass, DeclarativeBase): + pass + + +class A(Base): + __tablename__ = "a" + + id: Mapped[int] = mapped_column(primary_key=True, init=False) + data: Mapped[str] + x: Mapped[Optional[int]] = mapped_column(default=None) + y: Mapped[Optional[int]] = mapped_column(kw_only=True) + + +a1 = A(data="some data", y=5) + +# EXPECTED_TYPE: str +reveal_type(a1.data) + +# EXPECTED_RE_TYPE: .*Union\[builtins.int, None\] +reveal_type(a1.y) + +a1.data = "some other data" diff --git a/tox.ini b/tox.ini index ca1e46d6a7..5a31ac7d1d 100644 --- a/tox.ini +++ b/tox.ini @@ -168,6 +168,7 @@ deps= greenlet != 0.4.17 importlib_metadata; python_version < '3.8' mypy >= 1.1.1 + git+https://github.com/python/mypy@dataclass-transform-descriptors#egg=mypy patch==1.* commands =