Skip to content

Commit ad0e180

Browse files
Fix false positive for Final local scope variable in Protocol (#17308)
This PR fixes and closes #17281 ,which reported a false positive when using Final within the local function scope of a protocol method. With these changes: - Local variables within protocol methods can be marked as Final. - Protocol members still cannot be marked as Final Modified ``semanal.py`` file and added a unit test in ``test-data/unit/check.final.test`` --------- Co-authored-by: Jelle Zijlstra <[email protected]> Co-authored-by: Stanislav Terliakov
1 parent 16d5aaf commit ad0e180

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

mypy/semanal.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3505,7 +3505,8 @@ def unwrap_final(self, s: AssignmentStmt) -> bool:
35053505
if self.loop_depth[-1] > 0:
35063506
self.fail("Cannot use Final inside a loop", s)
35073507
if self.type and self.type.is_protocol:
3508-
self.msg.protocol_members_cant_be_final(s)
3508+
if self.is_class_scope():
3509+
self.msg.protocol_members_cant_be_final(s)
35093510
if (
35103511
isinstance(s.rvalue, TempNode)
35113512
and s.rvalue.no_rhs

test-data/unit/check-final.test

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,50 @@ class P(Protocol):
301301
pass
302302
[out]
303303

304+
[case testFinalInProtocol]
305+
from typing import Final, Protocol, final
306+
307+
class P(Protocol):
308+
var1 : Final[int] = 0 # E: Protocol member cannot be final
309+
310+
@final # E: Protocol member cannot be final
311+
def meth1(self) -> None:
312+
var2: Final = 0
313+
314+
def meth2(self) -> None:
315+
var3: Final = 0
316+
317+
def meth3(self) -> None:
318+
class Inner:
319+
var3: Final = 0 # OK
320+
321+
@final
322+
def inner(self) -> None: ...
323+
324+
class Inner:
325+
var3: Final = 0 # OK
326+
327+
@final
328+
def inner(self) -> None: ...
329+
330+
[out]
331+
332+
[case testFinalWithClassVarInProtocol]
333+
from typing import Protocol, Final, final, ClassVar
334+
335+
class P(Protocol):
336+
var1 : Final[ClassVar[int]] = 0 # E: Variable should not be annotated with both ClassVar and Final
337+
var2: ClassVar[int] = 1
338+
339+
@final # E: Protocol member cannot be final
340+
def meth1(self) -> None:
341+
...
342+
343+
def meth2(self) -> None:
344+
var3: Final[ClassVar[int]] = 0 # E: Variable should not be annotated with both ClassVar and Final # E: ClassVar can only be used for assignments in class body
345+
346+
[out]
347+
304348
[case testFinalNotInLoops]
305349
from typing import Final
306350

0 commit comments

Comments
 (0)