You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
mypy doesn't narrow Final objects in nested contexts #19080
I have a global constant I've marked with Final. In a class definition, I use this constant to swap out implementations of a method. While inside a type guarding block, but outside the method definition, the type of the Final object is narrowed, but inside of the method it is not narrowed.
fromtypingimport*def_init() ->None|str:
returnNoneRESOLVE_X: Final=_init()
classExample:
ifRESOLVE_XisnotNone:
reveal_type(RESOLVE_X) # note: Revealed type is "builtins.str"def__str__(self) ->str:
returnRESOLVE_X# error: Incompatible return value type (got "str | None", expected "str") [return-value]else:
def__str__(self) ->str:
return"example"
Expected Behavior
Inside the __str__ definition in the if RESOLVE_X is not None: block, RESOLVE_X should stay narrowed as it cannot be reassigned and have its type re-widened in the future.
Actual Behavior
main.py:12: note: Revealed type is "builtins.str"
main.py:15: error: Incompatible return value type (got "str | None", expected "str") [return-value]
Found 1 error in 1 file (checked 1 source file)
Activity
Admit that Final variables are never redefined (#19083)
ilevkivskyi commentedon Apr 15, 2026
Support for this is being removed in #21241. Re-opening in case we will decide to support this again later.
ilevkivskyi commentedon Apr 15, 2026
A recommended workaround is to use
assert RESOLVE_X is not Nonein the function body.ilevkivskyi commentedon Apr 16, 2026
Another possible (and in some cases better) workaround proposed in #21241 is