Skip to content

Using numpy types conditionally gives confusing [assignment] error #16875

Closed

Description

@cebtenzzre

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

Activity

  1. BdSCunha commented on Feb 6, 2024

    @BdSCunha

    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.

  2. cebtenzzre commented on Feb 6, 2024

    @cebtenzzre
    Author

    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.

  3. brianschubert commented on Nov 15, 2024

    @brianschubert
    Collaborator

    Reproducer without numpy:

    from typing_extensions import TypeAlias
    
    class A: ...
    class B: ...
    
    class Foo[T]: ...
    
    FooA: TypeAlias = Foo[A]
    FooB: TypeAlias = Foo[B]
    
    def func() -> None:
        if int():
            new_dtype = FooA
        else:
            new_dtype = FooB  # E: Incompatible types in assignment (expression has type "type[Foo[Any]]", variable has type "type[Foo[Any]]")  [assignment]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions