Strange behavior when one of the constraints of a generic class's type variable is typing.Any
?
#9744
-
I'm not entirely sure if this is a bug, but I've noticed a strange behavior as the title says. Consider the following example: from typing import Any, reveal_type
class MyClass[T: (int, float, Any)]:
def __init__(self, name: str, attr: T, attrs: list[T]) -> None:
self.name: str = name
self.attr: T = attr
self.attrs: list[T] = attrs
def test_int(obj: MyClass[int]) -> None:
reveal_type(obj)
reveal_type(obj.name)
reveal_type(obj.attr)
reveal_type(obj.attrs)
def test_float(obj: MyClass[float]) -> None:
reveal_type(obj)
reveal_type(obj.name)
reveal_type(obj.attr)
reveal_type(obj.attrs)
def test_any(obj: MyClass[Any]) -> None:
reveal_type(obj)
reveal_type(obj.name)
reveal_type(obj.attr)
reveal_type(obj.attrs) This defines a generic class with one type variable that has 3 constraints:
The output is also the same when using the Pyright playground instead of running locally (playground link). As the output shows, it now treats the TypeVar as having the type
If I type-check the original code using MyPy instead, it outputs what I expect (playground link):
Is this a bug in Pyright or is it intentional? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
In this code sample, you're using a value-constrained type variable. The behaviors of value-constrained type variables are woefully underspecified in the Python typing spec. I generally recommend against using them if at all possible. They are not found in any other language or type system — and for good reason. It's unfortunate that they were added to the Python type system, and it's not clear whether we'll ever be able to fully specify them in a way that composes well with other type features. One aspect of value-constrained type variables that is unspecified is what a type checker should do when two or more of the constraint types are overlapping. In your example, all three constraint types are overlapping. The I can't tell from your code sample what problem you're trying to solve here, but if you're able to use a standard type variable — or a type variable with an upper bound of In summary, this isn't a bug in pyright, nor is it a bug in mypy. The behavior you're seeing is because you're using a poorly-specified feature of the type system in a way that it wasn't designed to be used. |
Beta Was this translation helpful? Give feedback.
In this code sample, you're using a value-constrained type variable. The behaviors of value-constrained type variables are woefully underspecified in the Python typing spec. I generally recommend against using them if at all possible. They are not found in any other language or type system — and for good reason. It's unfortunate that they were added to the Python type system, and it's not clear whether we'll ever be able to fully specify them in a way that composes well with other type features.
One aspect of value-constrained type variables that is unspecified is what a type checker should do when two or more of the constraint types are overlapping. In your example, all three constraint …