pythonpython-typingmypy

Not sure why this generates a mypy "Incompatible types in assignment"


Simple example of what's confusing me:

from typing import Callable, List, Union

Value = Union[bool, int, str]
Helper = Callable[[Value], List[Value]]


def func_with_alias(aa: Value) -> List[Value]:
    return []


def func_with_type(aa: bool) -> List[Value]:
    return []


your_func1: Helper = func_with_alias
your_func2: Helper = func_with_type

mypy complains that "your_func2" has an incompatible type: error: Incompatible types in assignment (expression has type "Callable[[bool], List[Union[bool, int, str]]]", variable has type "Callable[[Union[bool, int, str]], List[Union[bool, int, str]]]")

Why doesn't it let me do this, as bool is in Union[bool, int, str]?

❯ mypy --version
mypy 0.782

Solution

  • Let's look at what you're saying with your type definitions:

    Value = Union[bool, int, str]
    

    A Value can be either a boolean, an integer or a string.

    Helper = Callable[[Value], List[Value]]
    

    A Helper takes a Value and returns a List of Values.

    Now the assignment that errors:

    def func_with_type(aa: bool) -> List[Value]:
        return []
    
    your_func2: Helper = func_with_type
    

    func_with_type only accepts a boolean, but you're assigning it to a type that should be able to accept an integer or string as well.


    To see why that doesn't make sense, think about the following consumer of a Helper function:

    def consumer(func: Helper) -> List[Value]:
         return func("Hello, world!")
    

    A Helper can take a Value, which can either be bool, int or str, so this usage should be fine. But func_with_type only accepts a bool, so cannot be called in this way, therefore we can't consider it a Helper.


    What I am actually doing is building a dispatch dict that has a key of the actual class (say bool, int, or str) and a value of a function that handles it. The return is a list of Value (eg, bool, int, or str).

    Possibly what you want is a generic function, where the generic type is constrained by the union:

    T = TypeVar('T', bool, int, str)
    Helper = Callable[[T], List[T]]