From 88ffbd283006714bb2d468241e69f7eb094a65d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandru=20M=C4=83r=C4=83=C8=99teanu?= Date: Mon, 25 Mar 2024 21:58:35 +0000 Subject: [PATCH 1/4] fix: use `Any` for field type in `make_dataclass` Fixes #11653 --- stdlib/dataclasses.pyi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stdlib/dataclasses.pyi b/stdlib/dataclasses.pyi index 00e0d31d092a..c361122704a5 100644 --- a/stdlib/dataclasses.pyi +++ b/stdlib/dataclasses.pyi @@ -243,7 +243,7 @@ class InitVar(Generic[_T], metaclass=_InitVarMeta): if sys.version_info >= (3, 12): def make_dataclass( cls_name: str, - fields: Iterable[str | tuple[str, type] | tuple[str, type, Any]], + fields: Iterable[str | tuple[str, Any] | tuple[str, Any, Any]], *, bases: tuple[type, ...] = (), namespace: dict[str, Any] | None = None, @@ -263,7 +263,7 @@ if sys.version_info >= (3, 12): elif sys.version_info >= (3, 11): def make_dataclass( cls_name: str, - fields: Iterable[str | tuple[str, type] | tuple[str, type, Any]], + fields: Iterable[str | tuple[str, Any] | tuple[str, Any, Any]], *, bases: tuple[type, ...] = (), namespace: dict[str, Any] | None = None, @@ -282,7 +282,7 @@ elif sys.version_info >= (3, 11): elif sys.version_info >= (3, 10): def make_dataclass( cls_name: str, - fields: Iterable[str | tuple[str, type] | tuple[str, type, Any]], + fields: Iterable[str | tuple[str, Any] | tuple[str, Any, Any]], *, bases: tuple[type, ...] = (), namespace: dict[str, Any] | None = None, @@ -300,7 +300,7 @@ elif sys.version_info >= (3, 10): else: def make_dataclass( cls_name: str, - fields: Iterable[str | tuple[str, type] | tuple[str, type, Any]], + fields: Iterable[str | tuple[str, Any] | tuple[str, Any, Any]], *, bases: tuple[type, ...] = (), namespace: dict[str, Any] | None = None, From ef798727e3f2c005c890610cc384bfcd55d04f0e Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 25 Mar 2024 22:43:30 +0000 Subject: [PATCH 2/4] Add some test cases --- test_cases/stdlib/check_dataclasses.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test_cases/stdlib/check_dataclasses.py b/test_cases/stdlib/check_dataclasses.py index b06c4a9fff7c..d82408218ed8 100644 --- a/test_cases/stdlib/check_dataclasses.py +++ b/test_cases/stdlib/check_dataclasses.py @@ -1,7 +1,7 @@ from __future__ import annotations import dataclasses as dc -from typing import TYPE_CHECKING, Any, Dict, Tuple, Type, Union +from typing import TYPE_CHECKING, Annotated, Any, Dict, Tuple, Type, Union from typing_extensions import assert_type if TYPE_CHECKING: @@ -88,3 +88,14 @@ def check_other_isdataclass_overloads(x: type, y: object) -> None: assert_type(dc.asdict(y), Dict[str, Any]) assert_type(dc.astuple(y), Tuple[Any, ...]) dc.replace(y) + + +# Regression test for #11653 +D = dc.make_dataclass( + "D", [("a", int | None), "y", ("z", Annotated[frozenset[bytes], "metadata"], dc.field(default=frozenset()))] +) +# Check that it's inferred by the type checker as a class object of some kind +# (but don't assert the exact type that `D` is inferred as, +# in case a type checker decides to add some special-casing for +# `make_dataclass` in the future) +assert_type(D.__mro__, tuple[type, ...]) From fe618e92c52a20cda182fe811a2a27d41db920bf Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 25 Mar 2024 22:51:43 +0000 Subject: [PATCH 3/4] fixes --- test_cases/stdlib/check_dataclasses.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test_cases/stdlib/check_dataclasses.py b/test_cases/stdlib/check_dataclasses.py index d82408218ed8..ce4fa77deeed 100644 --- a/test_cases/stdlib/check_dataclasses.py +++ b/test_cases/stdlib/check_dataclasses.py @@ -1,8 +1,8 @@ from __future__ import annotations import dataclasses as dc -from typing import TYPE_CHECKING, Annotated, Any, Dict, Tuple, Type, Union -from typing_extensions import assert_type +from typing import TYPE_CHECKING, Any, Dict, FrozenSet, Tuple, Type, Union +from typing_extensions import Annotated, assert_type if TYPE_CHECKING: from _typeshed import DataclassInstance @@ -92,10 +92,10 @@ def check_other_isdataclass_overloads(x: type, y: object) -> None: # Regression test for #11653 D = dc.make_dataclass( - "D", [("a", int | None), "y", ("z", Annotated[frozenset[bytes], "metadata"], dc.field(default=frozenset()))] + "D", [("a", Union[int, None]), "y", ("z", Annotated[FrozenSet[bytes], "metadata"], dc.field(default=frozenset()))] ) # Check that it's inferred by the type checker as a class object of some kind # (but don't assert the exact type that `D` is inferred as, # in case a type checker decides to add some special-casing for # `make_dataclass` in the future) -assert_type(D.__mro__, tuple[type, ...]) +_: type = D From f065c088cd2d45b36d5f967a3999aec4309131d5 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 25 Mar 2024 22:57:03 +0000 Subject: [PATCH 4/4] try to satisfy pyright --- test_cases/stdlib/check_dataclasses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_cases/stdlib/check_dataclasses.py b/test_cases/stdlib/check_dataclasses.py index ce4fa77deeed..76ce8e1bd260 100644 --- a/test_cases/stdlib/check_dataclasses.py +++ b/test_cases/stdlib/check_dataclasses.py @@ -92,10 +92,10 @@ def check_other_isdataclass_overloads(x: type, y: object) -> None: # Regression test for #11653 D = dc.make_dataclass( - "D", [("a", Union[int, None]), "y", ("z", Annotated[FrozenSet[bytes], "metadata"], dc.field(default=frozenset()))] + "D", [("a", Union[int, None]), "y", ("z", Annotated[FrozenSet[bytes], "metadata"], dc.field(default=frozenset({b"foo"})))] ) # Check that it's inferred by the type checker as a class object of some kind # (but don't assert the exact type that `D` is inferred as, # in case a type checker decides to add some special-casing for # `make_dataclass` in the future) -_: type = D +assert_type(D.__mro__, Tuple[type, ...])