Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python generic type on function getting lost somewhere

Getting this typing error:

error: Incompatible types in assignment (expression has type "object", variable has type "A | B")  [assignment]

With this code:

from dataclasses import dataclass
from typing import TypeVar, Mapping, reveal_type


@dataclass
class A:
    foo: str = "a"

@dataclass
class B:
    bar: str = "b"

lookup_table: Mapping[str, type[A] | type[B]] = {
    "a": A,
    "b": B
}

reveal_type(lookup_table)  # note: Revealed type is "typing.Mapping[builtins.str, Union[type[simple.A], type[simple.B]]]"
T = TypeVar("T")

def load(lookup_table: Mapping[str, type[T]], lookup_key:str) -> T:
    con: type[T] = lookup_table[lookup_key]
    instance: T = con()
    return instance

example_a: A | B = load(lookup_table, "a")  # error: Incompatible types in assignment (expression has type "object", variable has type "A | B")
print(example_a)

Edit: Logged a mypy bug here: https://github.com/python/mypy/issues/18265

like image 517
sixtyfootersdude Avatar asked Nov 24 '25 00:11

sixtyfootersdude


1 Answers

This is a mypy bug present in 1.13.0 and below (previously reported here and by OP here). pyright and basedmypy both accept the given snippet.

mypy stores type[A | B] types as a union of types internally (type[A] | type[B]). This is usually convenient, but causes troubles when solving type[T] <: type[A] | type[B] for T, because most types aren't "distributive" (P[A, B] is not equivalent to P[A] | P[B]), and type special case isn't taken into account yet.

General solver produces meet(A, B) in such case by solving

type[T] <: type[A]  =>  T <: A  |
                                |  =>  T <: meet(A, B)
type[T] <: type[B]  =>  T <: B  |

When A and B have no explicit parent in common, the closest supertype is object. To understand the logic behind that, consider similar equations: x < 2 && x < 3 => x < min(2, 3), and intersection/meet is for types what min operation is for numbers (and union/join is similar to max).

I submitted a PR to special-case this behaviour, so things may change in a future mypy release.

like image 147
STerliakov Avatar answered Nov 25 '25 14:11

STerliakov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!