mypy icon indicating copy to clipboard operation
mypy copied to clipboard

Using numpy types conditionally gives confusing `[assignment]` error

Open cebtenzzre opened this issue 1 year ago • 2 comments

Bug Report

When running strict mode on a simple example with numpy types, mypy will generate a confusing error message for [assignment] in which the expression type and the variable type are apparently the same, yet it fails anyway.

To Reproduce

import random

import numpy as np

def foo() -> None:
    if random.randrange(2):
        new_dtype = np.float16
    else:
        new_dtype = np.float32

Expected Behavior

If there is something wrong with the above code, I would expect mypy to tell me what the specific mismatch is.

Actual Behavior

$ mypy --strict repr.py
repr.py:9: error: Incompatible types in assignment (expression has type
"type[floating[Any]]", variable has type "type[floating[Any]]")  [assignment]
            new_dtype = np.float32
                        ^~~~~~~~~~
Found 1 error in 1 file (checked 1 source file)

Why would type[floating[Any]] not match type[floating[Any]]?

Your Environment

  • Mypy version used: mypy 1.9.0+dev.b956e6a57c4dd36d670097a3eccf7dc092348fec (compiled: no)
  • Python version used: Python 3.11.3

cebtenzzre avatar Feb 05 '24 19:02 cebtenzzre

In NumPy, numpy.floating serves as the base class for all floating-point numbers. When a variable is annotated with np.floating, its type becomes floating[Any].

float16 and float32 are aliases for floating[_16Bit] and floating[_32Bit] respectively in NumPy. This makes them incompatible with each other due to the different bit sizes.

To address this issue, I've revised the code as follows:

import random

import numpy as np
from numpy.typing import DTypeLike


def foo() -> None:
    new_dtype: DTypeLike
    if random.randrange(2):
        new_dtype = np.float16
    else:
        new_dtype = np.float32

In this version, new_dtype is annotated with numpy.typing.DTypeLike, which is a type hint that encompasses all data types in NumPy, including np.float16 and np.float32. This change should resolve the type incompatibility issue.

BdSCunha avatar Feb 06 '24 12:02 BdSCunha

float16 and float32 are aliases for floating[_16Bit] and floating[_32Bit] respectively in NumPy. This makes them incompatible with each other due to the different bit sizes.

That's a reasonable explanation, and I already had a solution for this in my code - but my concern is with the error from numpy that appears tautologically false. If mypy sees the type of np.float16 as type[floating[_16Bit]], it should communicate that to the user.

cebtenzzre avatar Feb 06 '24 15:02 cebtenzzre