Skip to content

Commit 55cffc1

Browse files
Allow protocols with untyped "__slots__" (#9314)
Closes #7290. Co-authored-by: Shantanu <[email protected]>
1 parent 96db3a0 commit 55cffc1

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

mypy/semanal.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2320,8 +2320,8 @@ def process_type_annotation(self, s: AssignmentStmt) -> None:
23202320
if isinstance(lvalue.node, Var):
23212321
lvalue.node.is_abstract_var = True
23222322
else:
2323-
if (any(isinstance(lv, NameExpr) and lv.is_inferred_def for lv in s.lvalues) and
2324-
self.type and self.type.is_protocol and not self.is_func_scope()):
2323+
if (self.type and self.type.is_protocol and
2324+
self.is_annotated_protocol_member(s) and not self.is_func_scope()):
23252325
self.fail('All protocol members must have explicitly declared types', s)
23262326
# Set the type if the rvalue is a simple literal (even if the above error occurred).
23272327
if len(s.lvalues) == 1 and isinstance(s.lvalues[0], RefExpr):
@@ -2332,6 +2332,19 @@ def process_type_annotation(self, s: AssignmentStmt) -> None:
23322332
for lvalue in s.lvalues:
23332333
self.store_declared_types(lvalue, s.type)
23342334

2335+
def is_annotated_protocol_member(self, s: AssignmentStmt) -> bool:
2336+
"""Check whether a protocol member is annotated.
2337+
2338+
There are some exceptions that can be left unannotated, like ``__slots__``."""
2339+
return any(
2340+
(
2341+
isinstance(lv, NameExpr)
2342+
and lv.name != '__slots__'
2343+
and lv.is_inferred_def
2344+
)
2345+
for lv in s.lvalues
2346+
)
2347+
23352348
def analyze_simple_literal_type(self, rvalue: Expression, is_final: bool) -> Optional[Type]:
23362349
"""Return builtins.int if rvalue is an int literal, etc.
23372350

test-data/unit/check-protocols.test

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,3 +2499,11 @@ reveal_type(abs(3)) # N: Revealed type is 'builtins.int*'
24992499
reveal_type(abs(ALL)) # N: Revealed type is 'builtins.int*'
25002500
[builtins fixtures/float.pyi]
25012501
[typing fixtures/typing-full.pyi]
2502+
2503+
[case testProtocolWithSlots]
2504+
from typing import Protocol
2505+
2506+
class A(Protocol):
2507+
__slots__ = ()
2508+
2509+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)