Skip to content

False narrowing with repeated assignment inside if resulting in bad false negative #18492

Description

@MaxG87

Bug Report

In a function, mypy fails to detect an incompatible assignment in a function, if that is after a __get_item__ access inside a branch. Weirdly, mypy correctly deduces the types, as shown with reveal_type but does not complain about the incorrect assignment anyways.

To Reproduce

I would have liked to give a playground link, but the MWE involves a pandas.DataFrame which seems not to work on the playground.

importpandasaspd# fails as expectedsome_condition: bool="123".isnumeric()
list_of_dicts= [{"some": 1, "columns": 2, "will": 3, "go": 4, "here": 5}]
ifsome_condition>0:
output_df=pd.DataFrame(list_of_dicts)
output_df=output_df[["some", "columns", "here"]]
else:
output_df=None# fails heredeffails_as_expected_1(some_condition: bool) ->pd.DataFrame:
list_of_dicts= [{"some": 1, "columns": 2, "will": 3, "go": 4, "here": 5}]
output_df=pd.DataFrame(list_of_dicts)
output_df=output_df[["some", "columns", "here"]]
output_df=None# fails hereother_df: pd.DataFrame=output_dfreturnother_dfdeffails_as_expected_2(some_condition: bool) ->pd.DataFrame:
list_of_dicts= [{"some": 1, "columns": 2, "will": 3, "go": 4, "here": 5}]
ifsome_condition>0:
output_df=pd.DataFrame(list_of_dicts)
else:
output_df=Noneother_df: pd.DataFrame=output_df# fails herereturnother_dfdefdoes_not_fail_but_should(some_condition: bool) ->pd.DataFrame:
list_of_dicts= [{"some": 1, "columns": 2, "will": 3, "go": 4, "here": 5}]
ifsome_condition>0:
output_df=pd.DataFrame(list_of_dicts)
reveal_type(output_df)
output_df=output_df[["some", "columns", "here"]]
reveal_type(output_df)
else:
output_df=Noneother_df: pd.DataFrame=output_dfreturnother_df

Expected Behavior
Each block and function should contain a mypy error regarding an incompatible assignment.

Actual Behavior

For the last function, no such error is produced:

mwe2.py:10: error: Incompatible types in assignment (expression has type "None", variable has type "DataFrame") [assignment]
mwe2.py:17: error: Incompatible types in assignment (expression has type "None", variable has type "DataFrame") [assignment]
mwe2.py:28: error: Incompatible types in assignment (expression has type "DataFrame | None", variable has type "DataFrame") [assignment]
mwe2.py:36: note: Revealed type is "pandas.core.frame.DataFrame"
mwe2.py:38: note: Revealed type is "pandas.core.frame.DataFrame"
Found 3 errors in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: mypy 1.14.1 (compiled: yes)
  • Mypy command-line flags: only the filename
  • Mypy configuration options from pyproject.toml:
[tool.mypy]
warn_unreachable = trueenable_error_code = [
"possibly-undefined"
]
strict = true
  • Python version used: Python 3.12.8 from Debian Testing

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions