Wrong errors of type unsupported operand when type checking is done in list
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 20.6k
- Forks
- 3.3k
- PR merge metrics
- PR metrics pending
Description
Bug Report
(A clear and concise description of what the bug is.)
To Reproduce
a: None | float = 0.0
b: None | float = 0.0
c = None if None in (a, b) else a - b
print(c)
(Also the alternative approach of using a regular if...else... block fails)
Expected Behavior
No error found by mypy. I cannot think of a way that this code fails. But maybe I'm just very code-blind right now.
Actual Behavior
coordinate_magic/test.py:4: error: Unsupported left operand type for - ("None") [operator]
coordinate_magic/test.py:4: error: Unsupported operand types for - ("None" and "float") [operator]
coordinate_magic/test.py:4: error: Unsupported operand types for - ("float" and "None") [operator]
coordinate_magic/test.py:4: note: Both left and right operands are unions
Found 3 errors in 1 file (checked 1 source file)
Your Environment
- Mypy version used:
mypy 1.8.0 (compiled: yes) - Mypy command-line flags: None
- Mypy configuration options from
mypy.ini(and other config files):pyproject.toml[tool.mypy] # Config for 'mypy' # See https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml-file for more details python_version = "3.11" plugins = "numpy.typing.mypy_plugin" warn_return_any = true warn_unused_configs = true allow_redefinition = true # Allows variables to be redefined with an arbitrary type, as long as the redefinition is in the same block and nesting level as the original definition. disallow_untyped_defs = true disallow_incomplete_defs = true # Disallows defining functions with incomplete type annotations. check_untyped_defs = true # Type-checks the interior of functions without type annotations. no_implicit_optional = true # Changes the treatment of arguments with a default value of None by not implicitly making their type Optional. show_error_codes = true exclude = "gui/|doc/|coordinate.py" [[tool.mypy.overrides]] # mypy per-module options module = [ "scipy", "scipy.*", "mpl_toolkits.mplot3d", "altair", # Remove when issue https://github.com/altair-viz/altair/issues/2493 is solved "folium", # Remove when issue https://github.com/python-visualization/folium/issues/1559 is solved "folium.plugins", "matplotlib", # Remove when issue https://github.com/matplotlib/matplotlib/issues/20504 is solved "matplotlib.*", "traffic", "coloredlogs", # Remove when issue https://github.com/xolox/python-coloredlogs/issues/93 is solved "pymap3d", # Remove when discussion https://github.com/geospace-code/pymap3d/pull/76 is solved ] ignore_missing_imports = true - Python version used:
3.11
The problem lies in the if None in (a, b) part.
As soon as code is changed to
a: None | float = 0.0
b: None | float = 0.0
c = None if a is None or b is None else a - b
print(c)
mypy does not report an error.
EDIT: Added a playground link with all examples
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the snippet from coordinate_magic/test.py with mypy 1.8.0, then compare the None in (a, b) form with the is None form. Inspect the type-checking path for membership-based narrowing; done means the valid subtraction no longer produces unsupported-operand errors and the regression is covered by a test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100