]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
mypy 1.2 has fixed dataclass descriptor support
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 4 Apr 2023 14:02:30 +0000 (10:02 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 4 Apr 2023 14:02:30 +0000 (10:02 -0400)
Currently using the PR for test.

Change-Id: Idc4c475587f5151ef79046d24ca3ac274c2cb2ca
References: https://github.com/python/mypy/issues/14868

doc/build/orm/dataclasses.rst
test/ext/mypy/plain_files/pep681.py [new file with mode: 0644]
tox.ini

index 6285ddef72d8b948f6412bb273c88059ff99e007..bbd05fcd5e508d9404d3ceeb9fa2592b726c5763 100644 (file)
@@ -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 (file)
index 0000000..caa219d
--- /dev/null
@@ -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 ca1e46d6a7a7e5d06edaf44f69529a8fa7a44d10..5a31ac7d1d08304df6d868d7dc5d790bf7d1f752 100644 (file)
--- 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 =