Skip to content

Commit 0352178

Browse files
Warn when @disjoint_base is used on protocols or TypedDicts (#21029)
Per https://peps.python.org/pep-0800/#disjoint-base-on-special-classes cc @JelleZijlstra
1 parent 17326d0 commit 0352178

File tree

3 files changed

+27
-1
lines changed

3 files changed

+27
-1
lines changed

mypy/semanal.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2259,7 +2259,12 @@ def analyze_class_decorator_common(
22592259
if refers_to_fullname(decorator, FINAL_DECORATOR_NAMES):
22602260
info.is_final = True
22612261
elif refers_to_fullname(decorator, DISJOINT_BASE_DECORATOR_NAMES):
2262-
info.is_disjoint_base = True
2262+
if info.is_protocol:
2263+
self.fail("@disjoint_base cannot be used with protocol class", decorator)
2264+
elif info.typeddict_type is not None:
2265+
self.fail("@disjoint_base cannot be used with TypedDict", decorator)
2266+
else:
2267+
info.is_disjoint_base = True
22632268
elif refers_to_fullname(decorator, TYPE_CHECK_ONLY_NAMES):
22642269
info.is_type_check_only = True
22652270
elif (deprecated := self.get_deprecated(decorator)) is not None:

test-data/unit/check-protocols.test

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4746,3 +4746,13 @@ tmp/a.py:8: note: Expected:
47464746
tmp/a.py:8: note: def f(self) -> PNested
47474747
tmp/a.py:8: note: Got:
47484748
tmp/a.py:8: note: def f(self) -> CNested
4749+
4750+
[case testProtocolCannotBeDisjointBase]
4751+
from typing import Protocol
4752+
from typing_extensions import disjoint_base
4753+
4754+
@disjoint_base # E: @disjoint_base cannot be used with protocol class
4755+
class A(Protocol):
4756+
pass
4757+
4758+
[builtins fixtures/tuple.pyi]

test-data/unit/check-typeddict.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2515,6 +2515,17 @@ class ForwardDeclared: pass
25152515
[builtins fixtures/dict.pyi]
25162516
[typing fixtures/typing-full.pyi]
25172517

2518+
[case testTypedDictCannotBeDisjointBase]
2519+
from typing import TypedDict
2520+
from typing_extensions import disjoint_base
2521+
2522+
@disjoint_base # E: @disjoint_base cannot be used with TypedDict
2523+
class A(TypedDict):
2524+
pass
2525+
2526+
[builtins fixtures/dict.pyi]
2527+
[typing fixtures/typing-typeddict.pyi]
2528+
25182529
[case testTypedDictTypeNarrowingWithFinalKey]
25192530
from typing import Final, Optional, TypedDict
25202531

0 commit comments

Comments
 (0)