From 02d1ccb0d18e284955bd4588a825bfb51f25b787 Mon Sep 17 00:00:00 2001 From: Christoph Tyralla Date: Fri, 7 Feb 2025 20:52:57 +0100 Subject: [PATCH 1/5] Report that `NamedTuple` and `dataclass` are incompatile instead of crashing. The fix is pretty simple. I could not find a situation where combining `NamedTuple` and `dataclass` makes sense, so emitting an error seems sensible. --- mypy/plugins/dataclasses.py | 3 +++ test-data/unit/check-dataclasses.test | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index acb785aad70a..86f78d9c3d89 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -965,6 +965,9 @@ def dataclass_tag_callback(ctx: ClassDefContext) -> None: def dataclass_class_maker_callback(ctx: ClassDefContext) -> bool: """Hooks into the class typechecking process to add support for dataclasses.""" + if any(i.is_named_tuple for i in ctx.cls.info.mro): + ctx.api.fail(f"A NamedTuple cannot be a dataclass.", ctx=ctx.cls.info) + return True transformer = DataclassTransformer( ctx.cls, ctx.reason, _get_transform_spec(ctx.reason), ctx.api ) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 26c81812ab62..2c386a86c99a 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2576,3 +2576,20 @@ reveal_type(m.b) # N: Revealed type is "builtins.int" m.a = 1 # E: Cannot assign to final attribute "a" m.b = 2 # E: Cannot assign to final attribute "b" [builtins fixtures/tuple.pyi] + +[case testNoCrashForDataclassNamedTupleCombination] +# flags: --python-version 3.13 +from dataclasses import dataclass +from typing import NamedTuple + +@dataclass +class A(NamedTuple): # E: A NamedTuple cannot be a dataclass. + i: int + +class B1(NamedTuple): + i: int +@dataclass +class B2(B1): # E: A NamedTuple cannot be a dataclass. + pass + +[builtins fixtures/tuple.pyi] From 0011a71e4fc0fd0686611af755d58e8fe03a6450 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 7 Feb 2025 19:56:44 +0000 Subject: [PATCH 2/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- 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 86f78d9c3d89..766e4b0ff0f4 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -966,7 +966,7 @@ def dataclass_tag_callback(ctx: ClassDefContext) -> None: def dataclass_class_maker_callback(ctx: ClassDefContext) -> bool: """Hooks into the class typechecking process to add support for dataclasses.""" if any(i.is_named_tuple for i in ctx.cls.info.mro): - ctx.api.fail(f"A NamedTuple cannot be a dataclass.", ctx=ctx.cls.info) + ctx.api.fail("A NamedTuple cannot be a dataclass.", ctx=ctx.cls.info) return True transformer = DataclassTransformer( ctx.cls, ctx.reason, _get_transform_spec(ctx.reason), ctx.api From 640c4b2486689df148e3eefa22efe26d26d40068 Mon Sep 17 00:00:00 2001 From: Christoph Tyralla Date: Sat, 8 Feb 2025 15:48:34 +0100 Subject: [PATCH 3/5] Update mypy/plugins/dataclasses.py Co-authored-by: sobolevn --- 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 766e4b0ff0f4..90c983b0bacd 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -966,7 +966,7 @@ def dataclass_tag_callback(ctx: ClassDefContext) -> None: def dataclass_class_maker_callback(ctx: ClassDefContext) -> bool: """Hooks into the class typechecking process to add support for dataclasses.""" if any(i.is_named_tuple for i in ctx.cls.info.mro): - ctx.api.fail("A NamedTuple cannot be a dataclass.", ctx=ctx.cls.info) + ctx.api.fail("A NamedTuple cannot be a dataclass", ctx=ctx.cls.info) return True transformer = DataclassTransformer( ctx.cls, ctx.reason, _get_transform_spec(ctx.reason), ctx.api From c4bb341abcb982535924ceff5c2a7ec5b8508839 Mon Sep 17 00:00:00 2001 From: Christoph Tyralla Date: Sat, 8 Feb 2025 15:48:46 +0100 Subject: [PATCH 4/5] Update test-data/unit/check-dataclasses.test Co-authored-by: sobolevn --- 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 2c386a86c99a..95a989ed8db7 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2583,7 +2583,7 @@ from dataclasses import dataclass from typing import NamedTuple @dataclass -class A(NamedTuple): # E: A NamedTuple cannot be a dataclass. +class A(NamedTuple): # E: A NamedTuple cannot be a dataclass i: int class B1(NamedTuple): From 8c711679ff8eb409e9cbf4c3d4dd647e1e956e9f Mon Sep 17 00:00:00 2001 From: Christoph Tyralla Date: Sat, 8 Feb 2025 15:49:01 +0100 Subject: [PATCH 5/5] Update test-data/unit/check-dataclasses.test Co-authored-by: sobolevn --- 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 95a989ed8db7..9109b2b7c36d 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2589,7 +2589,7 @@ class A(NamedTuple): # E: A NamedTuple cannot be a dataclass class B1(NamedTuple): i: int @dataclass -class B2(B1): # E: A NamedTuple cannot be a dataclass. +class B2(B1): # E: A NamedTuple cannot be a dataclass pass [builtins fixtures/tuple.pyi]