From b0a0190e04f7cabbdd42024777589918808a56e4 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Tue, 2 Jul 2024 23:47:08 -0500 Subject: [PATCH 01/23] Add dunder replace --- mypy/plugins/dataclasses.py | 8 ++++++++ test-data/unit/check-dataclasses.test | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index dd2eceab217f..1be5be0e1102 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -385,6 +385,7 @@ def transform(self) -> bool: self._add_dataclass_fields_magic_attribute() self._add_internal_replace_method(attributes) + self._add_dunder_replace(attributes) if "__post_init__" in info.names: self._add_internal_post_init_method(attributes) @@ -394,6 +395,13 @@ def transform(self) -> bool: } return True + + def _add_dunder_replace(self, attributes: list[DataclassAttribute]) -> None: + """Add a `__replace__` method to the class, which is used to replace attributes in the `copy` module.""" + args = [attr.to_argument(self._cls.info, of="replace") for attr in attributes] + add_method_to_class( + self._api, self._cls, "__replace__", args=args, return_type=self._cls.info.self_type + ) def _add_internal_replace_method(self, attributes: list[DataclassAttribute]) -> None: """ diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index f26ccd9a4854..b414abe55621 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2489,3 +2489,16 @@ class Base: class Child(Base): y: int [builtins fixtures/dataclasses.pyi] + +[case testDunderReplacePresent] +from dataclasses import dataclass + +@dataclass +class Coords: + x: int + y: int + + +replaced = Coords(2, 4).__replace__(x=2, y=5) +reveal_type(replaced) # N: Revealed type is "__main__.Coords" + From df19ef39c44fe0498970deb91d4231831042f838 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 3 Jul 2024 04:47:50 +0000 Subject: [PATCH 02/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/plugins/dataclasses.py | 2 +- test-data/unit/check-dataclasses.test | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index 1be5be0e1102..a007c6936a6a 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -395,7 +395,7 @@ def transform(self) -> bool: } return True - + def _add_dunder_replace(self, attributes: list[DataclassAttribute]) -> None: """Add a `__replace__` method to the class, which is used to replace attributes in the `copy` module.""" args = [attr.to_argument(self._cls.info, of="replace") for attr in attributes] diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index b414abe55621..61959f46ff20 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2501,4 +2501,3 @@ class Coords: replaced = Coords(2, 4).__replace__(x=2, y=5) reveal_type(replaced) # N: Revealed type is "__main__.Coords" - From 6ab41c9f100cf0c6545a9348e9cb2b7b2a178bff Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Tue, 2 Jul 2024 23:49:44 -0500 Subject: [PATCH 03/23] Limit to 3.13 --- mypy/plugins/dataclasses.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index 1be5be0e1102..1eda350a25f4 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -385,7 +385,9 @@ def transform(self) -> bool: self._add_dataclass_fields_magic_attribute() self._add_internal_replace_method(attributes) - self._add_dunder_replace(attributes) + if self._api.options.python_version >= (3, 13): + self._add_dunder_replace(attributes) + if "__post_init__" in info.names: self._add_internal_post_init_method(attributes) From 9a143a2a08ab60ff87344f79efa096098fd16570 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Tue, 2 Jul 2024 23:50:59 -0500 Subject: [PATCH 04/23] Add flag for test --- test-data/unit/check-dataclasses.test | 1 + 1 file changed, 1 insertion(+) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 61959f46ff20..e9017e97b5f1 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2491,6 +2491,7 @@ class Child(Base): [builtins fixtures/dataclasses.pyi] [case testDunderReplacePresent] +# flags: --python-version 3.13 from dataclasses import dataclass @dataclass From 1be91501bd8fb49c1fa0b9aab3dc13fc4497af9e Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Tue, 2 Jul 2024 23:57:44 -0500 Subject: [PATCH 05/23] Fix typing issue --- mypy/plugins/dataclasses.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index 25765fa671f0..68ff98218f1c 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -401,9 +401,10 @@ def transform(self) -> bool: def _add_dunder_replace(self, attributes: list[DataclassAttribute]) -> None: """Add a `__replace__` method to the class, which is used to replace attributes in the `copy` module.""" args = [attr.to_argument(self._cls.info, of="replace") for attr in attributes] - add_method_to_class( - self._api, self._cls, "__replace__", args=args, return_type=self._cls.info.self_type - ) + if self._cls.info.self_type: + add_method_to_class( + self._api, self._cls, "__replace__", args=args, return_type=self._cls.info.self_type + ) def _add_internal_replace_method(self, attributes: list[DataclassAttribute]) -> None: """ From 2d457282016520e106610e1a3b6902f70a822f81 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Tue, 2 Jul 2024 23:58:14 -0500 Subject: [PATCH 06/23] Formatting --- mypy/plugins/dataclasses.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index 68ff98218f1c..657f4edb2db4 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -403,7 +403,11 @@ def _add_dunder_replace(self, attributes: list[DataclassAttribute]) -> None: args = [attr.to_argument(self._cls.info, of="replace") for attr in attributes] if self._cls.info.self_type: add_method_to_class( - self._api, self._cls, "__replace__", args=args, return_type=self._cls.info.self_type + self._api, + self._cls, + "__replace__", + args=args, + return_type=self._cls.info.self_type, ) def _add_internal_replace_method(self, attributes: list[DataclassAttribute]) -> None: From 90cd81a738ae5f09043eb9cdc29aae6a2177eb7e Mon Sep 17 00:00:00 2001 From: Maxwell Muoto Date: Wed, 3 Jul 2024 01:28:58 -0500 Subject: [PATCH 07/23] Add fixture --- test-data/unit/check-dataclasses.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index e9017e97b5f1..1c3cb5d349f6 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2500,5 +2500,5 @@ class Coords: y: int -replaced = Coords(2, 4).__replace__(x=2, y=5) -reveal_type(replaced) # N: Revealed type is "__main__.Coords" +Coords(2, 4).__replace__(x=2, y=5) +[builtins fixtures/dataclasses.pyi] From 6b9f491b18d793f8bfe3d4d9b098ed3d11b86012 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto Date: Wed, 3 Jul 2024 01:32:29 -0500 Subject: [PATCH 08/23] Correct fixture --- test-data/unit/check-dataclasses.test | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 1c3cb5d349f6..dd5b1b4a5562 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2500,5 +2500,7 @@ class Coords: y: int -Coords(2, 4).__replace__(x=2, y=5) -[builtins fixtures/dataclasses.pyi] +replaced = Coords(2, 4).__replace__(x=2, y=5) +reveal_type(replaced) # N: Revealed type is "__main__.Coords" +[builtins fixtures/tuple.pyi] + From aaf1fd77c9f2d0a27f8ec3f1ebd80a36394078c4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 3 Jul 2024 06:32:52 +0000 Subject: [PATCH 09/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- test-data/unit/check-dataclasses.test | 1 - 1 file changed, 1 deletion(-) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index dd5b1b4a5562..285491c21e13 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2503,4 +2503,3 @@ class Coords: replaced = Coords(2, 4).__replace__(x=2, y=5) reveal_type(replaced) # N: Revealed type is "__main__.Coords" [builtins fixtures/tuple.pyi] - From 4e9a553b98f456142ff256b037d7bd3e0e179f9a Mon Sep 17 00:00:00 2001 From: Maxwell Muoto Date: Wed, 3 Jul 2024 02:02:14 -0500 Subject: [PATCH 10/23] Tweak --- mypy/plugins/dataclasses.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index 657f4edb2db4..92b45cb487bb 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -401,14 +401,13 @@ def transform(self) -> bool: def _add_dunder_replace(self, attributes: list[DataclassAttribute]) -> None: """Add a `__replace__` method to the class, which is used to replace attributes in the `copy` module.""" args = [attr.to_argument(self._cls.info, of="replace") for attr in attributes] - if self._cls.info.self_type: - add_method_to_class( - self._api, - self._cls, - "__replace__", - args=args, - return_type=self._cls.info.self_type, - ) + add_method_to_class( + self._api, + self._cls, + "__replace__", + args=args, + return_type=NoneType(), + ) def _add_internal_replace_method(self, attributes: list[DataclassAttribute]) -> None: """ From dbb6dc38316b29ea887f38d96987b7dcdad8938f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 3 Jul 2024 07:03:09 +0000 Subject: [PATCH 11/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/plugins/dataclasses.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index 92b45cb487bb..4ec81e92c9fc 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -401,13 +401,7 @@ def transform(self) -> bool: def _add_dunder_replace(self, attributes: list[DataclassAttribute]) -> None: """Add a `__replace__` method to the class, which is used to replace attributes in the `copy` module.""" args = [attr.to_argument(self._cls.info, of="replace") for attr in attributes] - add_method_to_class( - self._api, - self._cls, - "__replace__", - args=args, - return_type=NoneType(), - ) + add_method_to_class(self._api, self._cls, "__replace__", args=args, return_type=NoneType()) def _add_internal_replace_method(self, attributes: list[DataclassAttribute]) -> None: """ From 5269ef91f19ce1ebbd8f2c55a755599283482a25 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto Date: Wed, 3 Jul 2024 02:25:42 -0500 Subject: [PATCH 12/23] Fix --- mypy/plugins/dataclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index 92b45cb487bb..4b54c4d50faa 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -406,7 +406,7 @@ def _add_dunder_replace(self, attributes: list[DataclassAttribute]) -> None: self._cls, "__replace__", args=args, - return_type=NoneType(), + return_type=Instance(self._cls.info, []), ) def _add_internal_replace_method(self, attributes: list[DataclassAttribute]) -> None: From e3f2b73e48d106b683a35770eef8d193bd2c815d Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:05:24 -0500 Subject: [PATCH 13/23] Expand tests --- test-data/unit/check-dataclasses.test | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 285491c21e13..1d51dc0093c3 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2502,4 +2502,12 @@ class Coords: replaced = Coords(2, 4).__replace__(x=2, y=5) reveal_type(replaced) # N: Revealed type is "__main__.Coords" + +replaced = Coords(2, 4).__replace(x=2) +reveal_type(replaced) # N: Revealed type is "__main__.Coords" + +Coords(2, 4).__replace__(x="asdf") # E: Argument "x" to "__replace__" of "Coords" has incompatible type "str"; expected "int" +Coords(2, 4).__replace(23) # E: Too many positional arguments for "Coords" +Coords(2, 4).__replace(23, 25) # E: Too many positional arguments for "Coords" + [builtins fixtures/tuple.pyi] From 0338aeeb67e409dde840e6fc1ba817523eade486 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:08:47 -0500 Subject: [PATCH 14/23] FIx misnamed --- test-data/unit/check-dataclasses.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 1d51dc0093c3..4890a75d52ae 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2507,7 +2507,7 @@ replaced = Coords(2, 4).__replace(x=2) reveal_type(replaced) # N: Revealed type is "__main__.Coords" Coords(2, 4).__replace__(x="asdf") # E: Argument "x" to "__replace__" of "Coords" has incompatible type "str"; expected "int" -Coords(2, 4).__replace(23) # E: Too many positional arguments for "Coords" -Coords(2, 4).__replace(23, 25) # E: Too many positional arguments for "Coords" +Coords(2, 4).__replace__(23) # E: Too many positional arguments for "Coords" +Coords(2, 4).__replace__(23, 25) # E: Too many positional arguments for "Coords" [builtins fixtures/tuple.pyi] From bdfa9fbe659c3be943a2c65109c8557889868ae8 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:09:55 -0500 Subject: [PATCH 15/23] Add unexpected kwarg --- test-data/unit/check-dataclasses.test | 1 + 1 file changed, 1 insertion(+) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 4890a75d52ae..defd6369b021 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2509,5 +2509,6 @@ reveal_type(replaced) # N: Revealed type is "__main__.Coords" Coords(2, 4).__replace__(x="asdf") # E: Argument "x" to "__replace__" of "Coords" has incompatible type "str"; expected "int" Coords(2, 4).__replace__(23) # E: Too many positional arguments for "Coords" Coords(2, 4).__replace__(23, 25) # E: Too many positional arguments for "Coords" +Coords(2, 4).__replace__(x=23, y=25, z=42) # E: Unexpected keyword argument "z" for "__replace__" of "Coords" [builtins fixtures/tuple.pyi] From 2b4ea7843943171d7632ab0542437cc872970efa Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:10:44 -0500 Subject: [PATCH 16/23] Fix --- test-data/unit/check-dataclasses.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index defd6369b021..95542f667414 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2503,7 +2503,7 @@ class Coords: replaced = Coords(2, 4).__replace__(x=2, y=5) reveal_type(replaced) # N: Revealed type is "__main__.Coords" -replaced = Coords(2, 4).__replace(x=2) +replaced = Coords(2, 4).__replace__(x=2) reveal_type(replaced) # N: Revealed type is "__main__.Coords" Coords(2, 4).__replace__(x="asdf") # E: Argument "x" to "__replace__" of "Coords" has incompatible type "str"; expected "int" From 3291c4837f194de12a3e5c5884f2fcd5b222e4e7 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:25:14 -0500 Subject: [PATCH 17/23] Add generics test --- test-data/unit/check-dataclasses.test | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 95542f667414..652074a313d1 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2511,4 +2511,13 @@ Coords(2, 4).__replace__(23) # E: Too many positional arguments for "Co Coords(2, 4).__replace__(23, 25) # E: Too many positional arguments for "Coords" Coords(2, 4).__replace__(x=23, y=25, z=42) # E: Unexpected keyword argument "z" for "__replace__" of "Coords" +from typing import Generic + +@dataclass +class Gen(Generic[T]): + x: T + +replaced = Gen(2).__replace__(x=2) +reveal_type(replaced) # N: Revealed type is "__main__.Gen[builtins.int]" + [builtins fixtures/tuple.pyi] From b733e35724281a31e64e4d07351dda0e5151280a Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:25:26 -0500 Subject: [PATCH 18/23] Missing TV --- test-data/unit/check-dataclasses.test | 1 + 1 file changed, 1 insertion(+) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 652074a313d1..dae328f5fe2f 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2512,6 +2512,7 @@ Coords(2, 4).__replace__(23, 25) # E: Too many positional arguments for "Co Coords(2, 4).__replace__(x=23, y=25, z=42) # E: Unexpected keyword argument "z" for "__replace__" of "Coords" from typing import Generic +T = TypeVar('T') @dataclass class Gen(Generic[T]): From 14b7ef610226b0ae99e80c112457aa7a7f36c386 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:29:13 -0500 Subject: [PATCH 19/23] Missing import --- test-data/unit/check-dataclasses.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index dae328f5fe2f..5ffe10ed7d1b 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2511,7 +2511,7 @@ Coords(2, 4).__replace__(23) # E: Too many positional arguments for "Co Coords(2, 4).__replace__(23, 25) # E: Too many positional arguments for "Coords" Coords(2, 4).__replace__(x=23, y=25, z=42) # E: Unexpected keyword argument "z" for "__replace__" of "Coords" -from typing import Generic +from typing import Generic, TypeVar T = TypeVar('T') @dataclass From 56555c7877a8d4539f12bc375a591e44593b8a12 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:52:42 -0500 Subject: [PATCH 20/23] Fixes --- test-data/unit/check-dataclasses.test | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 5ffe10ed7d1b..c7aefa1d9ccd 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2507,8 +2507,8 @@ replaced = Coords(2, 4).__replace__(x=2) reveal_type(replaced) # N: Revealed type is "__main__.Coords" Coords(2, 4).__replace__(x="asdf") # E: Argument "x" to "__replace__" of "Coords" has incompatible type "str"; expected "int" -Coords(2, 4).__replace__(23) # E: Too many positional arguments for "Coords" -Coords(2, 4).__replace__(23, 25) # E: Too many positional arguments for "Coords" +Coords(2, 4).__replace__(23) # E: Too many positional arguments for "__replace__" of "Coords" +Coords(2, 4).__replace__(23, 25) # E: Too many positional arguments "__replace__" of "Coords" Coords(2, 4).__replace__(x=23, y=25, z=42) # E: Unexpected keyword argument "z" for "__replace__" of "Coords" from typing import Generic, TypeVar @@ -2518,7 +2518,7 @@ T = TypeVar('T') class Gen(Generic[T]): x: T -replaced = Gen(2).__replace__(x=2) -reveal_type(replaced) # N: Revealed type is "__main__.Gen[builtins.int]" +replaced_2 = Gen(2).__replace__(x=2) +reveal_type(replaced_2) # N: Revealed type is "__main__.Gen[builtins.int]" [builtins fixtures/tuple.pyi] From 74222709fb7b7b318ef76e687dac79253754f158 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:52:57 -0500 Subject: [PATCH 21/23] Fix --- test-data/unit/check-dataclasses.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index c7aefa1d9ccd..b76dbc458259 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2508,7 +2508,7 @@ reveal_type(replaced) # N: Revealed type is "__main__.Coords" Coords(2, 4).__replace__(x="asdf") # E: Argument "x" to "__replace__" of "Coords" has incompatible type "str"; expected "int" Coords(2, 4).__replace__(23) # E: Too many positional arguments for "__replace__" of "Coords" -Coords(2, 4).__replace__(23, 25) # E: Too many positional arguments "__replace__" of "Coords" +Coords(2, 4).__replace__(23, 25) # E: Too many positional arguments for "__replace__" of "Coords" Coords(2, 4).__replace__(x=23, y=25, z=42) # E: Unexpected keyword argument "z" for "__replace__" of "Coords" from typing import Generic, TypeVar From a1e11f1fecf6bae73e7b5736bddbd5e0b009de8f Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Wed, 3 Jul 2024 11:14:56 -0500 Subject: [PATCH 22/23] Preserve generic info --- mypy/plugins/dataclasses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index 4b54c4d50faa..edfc6840fc37 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -401,12 +401,13 @@ def transform(self) -> bool: def _add_dunder_replace(self, attributes: list[DataclassAttribute]) -> None: """Add a `__replace__` method to the class, which is used to replace attributes in the `copy` module.""" args = [attr.to_argument(self._cls.info, of="replace") for attr in attributes] + type_vars = [tv for tv in self._cls.type_vars] add_method_to_class( self._api, self._cls, "__replace__", args=args, - return_type=Instance(self._cls.info, []), + return_type=Instance(self._cls.info, type_vars), ) def _add_internal_replace_method(self, attributes: list[DataclassAttribute]) -> None: From 30df8b714e00f267ebdf23578cbc861d832a69dc Mon Sep 17 00:00:00 2001 From: Max Muoto Date: Wed, 3 Jul 2024 11:34:17 -0500 Subject: [PATCH 23/23] Update test-data/unit/check-dataclasses.test Co-authored-by: Jelle Zijlstra --- test-data/unit/check-dataclasses.test | 1 + 1 file changed, 1 insertion(+) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index b76dbc458259..0f726242b25b 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2520,5 +2520,6 @@ class Gen(Generic[T]): replaced_2 = Gen(2).__replace__(x=2) reveal_type(replaced_2) # N: Revealed type is "__main__.Gen[builtins.int]" +Gen(2).__replace__(x="not an int") # E: Argument "x" to "__replace__" of "Gen" has incompatible type "str"; expected "int" [builtins fixtures/tuple.pyi]