python / python/mypy

Wrong errors of type unsupported operand when type checking is done in list

Open
#16,778 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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)

Playground link

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.