Strange behavior when UnionType meets overload methods #10904
|
I intend to create a generic class such that the static type checker can get its generic argument correctly when I pass a type (which can be a UnionType) into its a = Foo(tp=str) # `a` is expected to be `Foo[str]`
b = Foo(tp=str | int) # `b` is expected to be `Foo[str | int]`I first tried this: class Foo[T]:
def __init__(self, *, tp: type[T]) -> None: ...
foo = Foo(tp=str | int)Then Pylance reports an error here: By some accident, however, I find the following code works: from typing_extensions import deprecated
from typing import overload
class Foo[T]:
@overload
def __init__(self, *, tp: type[T]) -> None: ...
@overload
@deprecated("xxx")
def __init__(self, *, tp: type[T]) -> None: ...
def __init__(self, *, tp: type[T]) -> None: ...
foo = Foo(tp=str | int)Pylance never reports any error, and I wonder why the latter works, and what's the best way to achieve my goal. |
Replies: 2 comments 2 replies
|
The value expression Pyright should reject both of the above cases. The fact that it doesn't in the second case (involving an overload) is a bug. It looks like you are using |
|
Hello! I tried from typing_extensions import TypeForm
class Foo[T]:
def __init__(self, *, tp: TypeForm[T]) -> None: ...
foo = Foo(tp=str | int) # Error here |
The value expression
str | intat runtime produces an object that is an instance ofUnionType. It is not an instance of thetypeclass, so it's not assignable totype. The typing spec is clear on that point, so pyright is correct in flagging that as a type violation.Pyright should reject both of the above cases. The fact that it doesn't in the second case (involving an overload) is a bug.
It looks like you are using
str | intas a type form — that is, you want it to be interpreted as a type expression rather than a value expression. There is a draft PEP 747 that introduces a mechanism in the type system to handle type forms.