mirror of https://github.com/astral-sh/ruff
[red-knot] MDTest: Use custom class names instead of builtins (#16269)
## Summary Follow up on the discussion [here](https://github.com/astral-sh/ruff/pull/16121#discussion_r1962973298). Replace builtin classes with custom placeholder names, which should hopefully make the tests a bit easier to understand. I carefully renamed things one after the other, to make sure that there is no functional change in the tests.
This commit is contained in:
parent
fc6b03c8da
commit
8198668fc3
|
|
@ -16,31 +16,38 @@ most common case involves implementing these methods for the same type:
|
|||
```py
|
||||
from __future__ import annotations
|
||||
|
||||
class EqReturnType: ...
|
||||
class NeReturnType: ...
|
||||
class LtReturnType: ...
|
||||
class LeReturnType: ...
|
||||
class GtReturnType: ...
|
||||
class GeReturnType: ...
|
||||
|
||||
class A:
|
||||
def __eq__(self, other: A) -> int:
|
||||
return 42
|
||||
def __eq__(self, other: A) -> EqReturnType:
|
||||
return EqReturnType()
|
||||
|
||||
def __ne__(self, other: A) -> bytearray:
|
||||
return bytearray()
|
||||
def __ne__(self, other: A) -> NeReturnType:
|
||||
return NeReturnType()
|
||||
|
||||
def __lt__(self, other: A) -> str:
|
||||
return "42"
|
||||
def __lt__(self, other: A) -> LtReturnType:
|
||||
return LtReturnType()
|
||||
|
||||
def __le__(self, other: A) -> bytes:
|
||||
return b"42"
|
||||
def __le__(self, other: A) -> LeReturnType:
|
||||
return LeReturnType()
|
||||
|
||||
def __gt__(self, other: A) -> list:
|
||||
return [42]
|
||||
def __gt__(self, other: A) -> GtReturnType:
|
||||
return GtReturnType()
|
||||
|
||||
def __ge__(self, other: A) -> set:
|
||||
return {42}
|
||||
def __ge__(self, other: A) -> GeReturnType:
|
||||
return GeReturnType()
|
||||
|
||||
reveal_type(A() == A()) # revealed: int
|
||||
reveal_type(A() != A()) # revealed: bytearray
|
||||
reveal_type(A() < A()) # revealed: str
|
||||
reveal_type(A() <= A()) # revealed: bytes
|
||||
reveal_type(A() > A()) # revealed: list
|
||||
reveal_type(A() >= A()) # revealed: set
|
||||
reveal_type(A() == A()) # revealed: EqReturnType
|
||||
reveal_type(A() != A()) # revealed: NeReturnType
|
||||
reveal_type(A() < A()) # revealed: LtReturnType
|
||||
reveal_type(A() <= A()) # revealed: LeReturnType
|
||||
reveal_type(A() > A()) # revealed: GtReturnType
|
||||
reveal_type(A() >= A()) # revealed: GeReturnType
|
||||
```
|
||||
|
||||
## Rich Comparison Dunder Implementations for Other Class
|
||||
|
|
@ -51,33 +58,40 @@ type:
|
|||
```py
|
||||
from __future__ import annotations
|
||||
|
||||
class EqReturnType: ...
|
||||
class NeReturnType: ...
|
||||
class LtReturnType: ...
|
||||
class LeReturnType: ...
|
||||
class GtReturnType: ...
|
||||
class GeReturnType: ...
|
||||
|
||||
class A:
|
||||
def __eq__(self, other: B) -> int:
|
||||
return 42
|
||||
def __eq__(self, other: B) -> EqReturnType:
|
||||
return EqReturnType()
|
||||
|
||||
def __ne__(self, other: B) -> bytearray:
|
||||
return bytearray()
|
||||
def __ne__(self, other: B) -> NeReturnType:
|
||||
return NeReturnType()
|
||||
|
||||
def __lt__(self, other: B) -> str:
|
||||
return "42"
|
||||
def __lt__(self, other: B) -> LtReturnType:
|
||||
return LtReturnType()
|
||||
|
||||
def __le__(self, other: B) -> bytes:
|
||||
return b"42"
|
||||
def __le__(self, other: B) -> LeReturnType:
|
||||
return LeReturnType()
|
||||
|
||||
def __gt__(self, other: B) -> list:
|
||||
return [42]
|
||||
def __gt__(self, other: B) -> GtReturnType:
|
||||
return GtReturnType()
|
||||
|
||||
def __ge__(self, other: B) -> set:
|
||||
return {42}
|
||||
def __ge__(self, other: B) -> GeReturnType:
|
||||
return GeReturnType()
|
||||
|
||||
class B: ...
|
||||
|
||||
reveal_type(A() == B()) # revealed: int
|
||||
reveal_type(A() != B()) # revealed: bytearray
|
||||
reveal_type(A() < B()) # revealed: str
|
||||
reveal_type(A() <= B()) # revealed: bytes
|
||||
reveal_type(A() > B()) # revealed: list
|
||||
reveal_type(A() >= B()) # revealed: set
|
||||
reveal_type(A() == B()) # revealed: EqReturnType
|
||||
reveal_type(A() != B()) # revealed: NeReturnType
|
||||
reveal_type(A() < B()) # revealed: LtReturnType
|
||||
reveal_type(A() <= B()) # revealed: LeReturnType
|
||||
reveal_type(A() > B()) # revealed: GtReturnType
|
||||
reveal_type(A() >= B()) # revealed: GeReturnType
|
||||
```
|
||||
|
||||
## Reflected Comparisons
|
||||
|
|
@ -89,55 +103,64 @@ these methods will be ignored here because they require a mismatched operand typ
|
|||
```py
|
||||
from __future__ import annotations
|
||||
|
||||
class EqReturnType: ...
|
||||
class NeReturnType: ...
|
||||
class LtReturnType: ...
|
||||
class LeReturnType: ...
|
||||
class GtReturnType: ...
|
||||
class GeReturnType: ...
|
||||
|
||||
class A:
|
||||
def __eq__(self, other: B) -> int:
|
||||
return 42
|
||||
def __eq__(self, other: B) -> EqReturnType:
|
||||
return EqReturnType()
|
||||
|
||||
def __ne__(self, other: B) -> bytearray:
|
||||
return bytearray()
|
||||
def __ne__(self, other: B) -> NeReturnType:
|
||||
return NeReturnType()
|
||||
|
||||
def __lt__(self, other: B) -> str:
|
||||
return "42"
|
||||
def __lt__(self, other: B) -> LtReturnType:
|
||||
return LtReturnType()
|
||||
|
||||
def __le__(self, other: B) -> bytes:
|
||||
return b"42"
|
||||
def __le__(self, other: B) -> LeReturnType:
|
||||
return LeReturnType()
|
||||
|
||||
def __gt__(self, other: B) -> list:
|
||||
return [42]
|
||||
def __gt__(self, other: B) -> GtReturnType:
|
||||
return GtReturnType()
|
||||
|
||||
def __ge__(self, other: B) -> set:
|
||||
return {42}
|
||||
def __ge__(self, other: B) -> GeReturnType:
|
||||
return GeReturnType()
|
||||
|
||||
class Unrelated: ...
|
||||
|
||||
class B:
|
||||
# To override builtins.object.__eq__ and builtins.object.__ne__
|
||||
# TODO these should emit an invalid override diagnostic
|
||||
def __eq__(self, other: str) -> B:
|
||||
def __eq__(self, other: Unrelated) -> B:
|
||||
return B()
|
||||
|
||||
def __ne__(self, other: str) -> B:
|
||||
def __ne__(self, other: Unrelated) -> B:
|
||||
return B()
|
||||
|
||||
# Because `object.__eq__` and `object.__ne__` accept `object` in typeshed,
|
||||
# this can only happen with an invalid override of these methods,
|
||||
# but we still support it.
|
||||
reveal_type(B() == A()) # revealed: int
|
||||
reveal_type(B() != A()) # revealed: bytearray
|
||||
reveal_type(B() == A()) # revealed: EqReturnType
|
||||
reveal_type(B() != A()) # revealed: NeReturnType
|
||||
|
||||
reveal_type(B() < A()) # revealed: list
|
||||
reveal_type(B() <= A()) # revealed: set
|
||||
reveal_type(B() < A()) # revealed: GtReturnType
|
||||
reveal_type(B() <= A()) # revealed: GeReturnType
|
||||
|
||||
reveal_type(B() > A()) # revealed: str
|
||||
reveal_type(B() >= A()) # revealed: bytes
|
||||
reveal_type(B() > A()) # revealed: LtReturnType
|
||||
reveal_type(B() >= A()) # revealed: LeReturnType
|
||||
|
||||
class C:
|
||||
def __gt__(self, other: C) -> int:
|
||||
def __gt__(self, other: C) -> EqReturnType:
|
||||
return 42
|
||||
|
||||
def __ge__(self, other: C) -> bytearray:
|
||||
return bytearray()
|
||||
def __ge__(self, other: C) -> NeReturnType:
|
||||
return NeReturnType()
|
||||
|
||||
reveal_type(C() < C()) # revealed: int
|
||||
reveal_type(C() <= C()) # revealed: bytearray
|
||||
reveal_type(C() < C()) # revealed: EqReturnType
|
||||
reveal_type(C() <= C()) # revealed: NeReturnType
|
||||
```
|
||||
|
||||
## Reflected Comparisons with Subclasses
|
||||
|
|
@ -149,6 +172,13 @@ than `A`.
|
|||
```py
|
||||
from __future__ import annotations
|
||||
|
||||
class EqReturnType: ...
|
||||
class NeReturnType: ...
|
||||
class LtReturnType: ...
|
||||
class LeReturnType: ...
|
||||
class GtReturnType: ...
|
||||
class GeReturnType: ...
|
||||
|
||||
class A:
|
||||
def __eq__(self, other: A) -> A:
|
||||
return A()
|
||||
|
|
@ -169,32 +199,32 @@ class A:
|
|||
return A()
|
||||
|
||||
class B(A):
|
||||
def __eq__(self, other: A) -> int:
|
||||
return 42
|
||||
def __eq__(self, other: A) -> EqReturnType:
|
||||
return EqReturnType()
|
||||
|
||||
def __ne__(self, other: A) -> bytearray:
|
||||
return bytearray()
|
||||
def __ne__(self, other: A) -> NeReturnType:
|
||||
return NeReturnType()
|
||||
|
||||
def __lt__(self, other: A) -> str:
|
||||
return "42"
|
||||
def __lt__(self, other: A) -> LtReturnType:
|
||||
return LtReturnType()
|
||||
|
||||
def __le__(self, other: A) -> bytes:
|
||||
return b"42"
|
||||
def __le__(self, other: A) -> LeReturnType:
|
||||
return LeReturnType()
|
||||
|
||||
def __gt__(self, other: A) -> list:
|
||||
return [42]
|
||||
def __gt__(self, other: A) -> GtReturnType:
|
||||
return GtReturnType()
|
||||
|
||||
def __ge__(self, other: A) -> set:
|
||||
return {42}
|
||||
def __ge__(self, other: A) -> GeReturnType:
|
||||
return GeReturnType()
|
||||
|
||||
reveal_type(A() == B()) # revealed: int
|
||||
reveal_type(A() != B()) # revealed: bytearray
|
||||
reveal_type(A() == B()) # revealed: EqReturnType
|
||||
reveal_type(A() != B()) # revealed: NeReturnType
|
||||
|
||||
reveal_type(A() < B()) # revealed: list
|
||||
reveal_type(A() <= B()) # revealed: set
|
||||
reveal_type(A() < B()) # revealed: GtReturnType
|
||||
reveal_type(A() <= B()) # revealed: GeReturnType
|
||||
|
||||
reveal_type(A() > B()) # revealed: str
|
||||
reveal_type(A() >= B()) # revealed: bytes
|
||||
reveal_type(A() > B()) # revealed: LtReturnType
|
||||
reveal_type(A() >= B()) # revealed: LeReturnType
|
||||
```
|
||||
|
||||
## Reflected Comparisons with Subclass But Falls Back to LHS
|
||||
|
|
|
|||
|
|
@ -147,33 +147,40 @@ of the dunder methods.)
|
|||
```py
|
||||
from __future__ import annotations
|
||||
|
||||
class EqReturnType: ...
|
||||
class NeReturnType: ...
|
||||
class LtReturnType: ...
|
||||
class LeReturnType: ...
|
||||
class GtReturnType: ...
|
||||
class GeReturnType: ...
|
||||
|
||||
class A:
|
||||
def __eq__(self, o: object) -> str:
|
||||
return "hello"
|
||||
def __eq__(self, o: object) -> EqReturnType:
|
||||
return EqReturnType()
|
||||
|
||||
def __ne__(self, o: object) -> bytes:
|
||||
return b"world"
|
||||
def __ne__(self, o: object) -> NeReturnType:
|
||||
return NeReturnType()
|
||||
|
||||
def __lt__(self, o: A) -> bytearray:
|
||||
return bytearray()
|
||||
def __lt__(self, o: A) -> LtReturnType:
|
||||
return LtReturnType()
|
||||
|
||||
def __le__(self, o: A) -> memoryview:
|
||||
return memoryview(b"")
|
||||
def __le__(self, o: A) -> LeReturnType:
|
||||
return LeReturnType()
|
||||
|
||||
def __gt__(self, o: A) -> tuple:
|
||||
return (1, 2, 3)
|
||||
def __gt__(self, o: A) -> GtReturnType:
|
||||
return GtReturnType()
|
||||
|
||||
def __ge__(self, o: A) -> list:
|
||||
return [1, 2, 3]
|
||||
def __ge__(self, o: A) -> GeReturnType:
|
||||
return GeReturnType()
|
||||
|
||||
a = (A(), A())
|
||||
|
||||
reveal_type(a == a) # revealed: bool
|
||||
reveal_type(a != a) # revealed: bool
|
||||
reveal_type(a < a) # revealed: bytearray | Literal[False]
|
||||
reveal_type(a <= a) # revealed: memoryview | Literal[True]
|
||||
reveal_type(a > a) # revealed: tuple | Literal[False]
|
||||
reveal_type(a >= a) # revealed: list | Literal[True]
|
||||
reveal_type(a < a) # revealed: LtReturnType | Literal[False]
|
||||
reveal_type(a <= a) # revealed: LeReturnType | Literal[True]
|
||||
reveal_type(a > a) # revealed: GtReturnType | Literal[False]
|
||||
reveal_type(a >= a) # revealed: GeReturnType | Literal[True]
|
||||
|
||||
# If lexicographic comparison is finished before comparing A()
|
||||
b = ("1_foo", A())
|
||||
|
|
@ -186,11 +193,13 @@ reveal_type(b <= c) # revealed: Literal[True]
|
|||
reveal_type(b > c) # revealed: Literal[False]
|
||||
reveal_type(b >= c) # revealed: Literal[False]
|
||||
|
||||
class LtReturnTypeOnB: ...
|
||||
|
||||
class B:
|
||||
def __lt__(self, o: B) -> set:
|
||||
def __lt__(self, o: B) -> LtReturnTypeOnB:
|
||||
return set()
|
||||
|
||||
reveal_type((A(), B()) < (A(), B())) # revealed: bytearray | set | Literal[False]
|
||||
reveal_type((A(), B()) < (A(), B())) # revealed: LtReturnType | LtReturnTypeOnB | Literal[False]
|
||||
```
|
||||
|
||||
#### Special Handling of Eq and NotEq in Lexicographic Comparisons
|
||||
|
|
|
|||
|
|
@ -241,30 +241,34 @@ suites:
|
|||
`except` suite ran to completion
|
||||
|
||||
```py
|
||||
def could_raise_returns_str() -> str:
|
||||
return "foo"
|
||||
class A: ...
|
||||
class B: ...
|
||||
class C: ...
|
||||
|
||||
def could_raise_returns_bytes() -> bytes:
|
||||
return b"foo"
|
||||
def could_raise_returns_A() -> A:
|
||||
return A()
|
||||
|
||||
def could_raise_returns_bool() -> bool:
|
||||
return True
|
||||
def could_raise_returns_B() -> B:
|
||||
return B()
|
||||
|
||||
def could_raise_returns_C() -> C:
|
||||
return C()
|
||||
|
||||
x = 1
|
||||
|
||||
try:
|
||||
reveal_type(x) # revealed: Literal[1]
|
||||
x = could_raise_returns_str()
|
||||
reveal_type(x) # revealed: str
|
||||
x = could_raise_returns_A()
|
||||
reveal_type(x) # revealed: A
|
||||
except TypeError:
|
||||
reveal_type(x) # revealed: Literal[1] | str
|
||||
x = could_raise_returns_bytes()
|
||||
reveal_type(x) # revealed: bytes
|
||||
x = could_raise_returns_bool()
|
||||
reveal_type(x) # revealed: bool
|
||||
reveal_type(x) # revealed: Literal[1] | A
|
||||
x = could_raise_returns_B()
|
||||
reveal_type(x) # revealed: B
|
||||
x = could_raise_returns_C()
|
||||
reveal_type(x) # revealed: C
|
||||
finally:
|
||||
# TODO: should be `Literal[1] | str | bytes | bool`
|
||||
reveal_type(x) # revealed: str | bool
|
||||
# TODO: should be `Literal[1] | A | B | C`
|
||||
reveal_type(x) # revealed: A | C
|
||||
x = 2
|
||||
reveal_type(x) # revealed: Literal[2]
|
||||
|
||||
|
|
@ -282,53 +286,56 @@ x = 1
|
|||
|
||||
try:
|
||||
reveal_type(x) # revealed: Literal[1]
|
||||
x = could_raise_returns_str()
|
||||
reveal_type(x) # revealed: str
|
||||
x = could_raise_returns_A()
|
||||
reveal_type(x) # revealed: A
|
||||
except TypeError:
|
||||
reveal_type(x) # revealed: Literal[1] | str
|
||||
x = could_raise_returns_bytes()
|
||||
reveal_type(x) # revealed: bytes
|
||||
x = could_raise_returns_bool()
|
||||
reveal_type(x) # revealed: bool
|
||||
reveal_type(x) # revealed: Literal[1] | A
|
||||
x = could_raise_returns_B()
|
||||
reveal_type(x) # revealed: B
|
||||
x = could_raise_returns_C()
|
||||
reveal_type(x) # revealed: C
|
||||
finally:
|
||||
# TODO: should be `Literal[1] | str | bytes | bool`
|
||||
reveal_type(x) # revealed: str | bool
|
||||
# TODO: should be `Literal[1] | A | B | C`
|
||||
reveal_type(x) # revealed: A | C
|
||||
|
||||
reveal_type(x) # revealed: str | bool
|
||||
reveal_type(x) # revealed: A | C
|
||||
```
|
||||
|
||||
An example with multiple `except` branches and a `finally` branch:
|
||||
|
||||
```py
|
||||
def could_raise_returns_memoryview() -> memoryview:
|
||||
return memoryview(b"")
|
||||
class D: ...
|
||||
class E: ...
|
||||
|
||||
def could_raise_returns_bytearray() -> bytearray:
|
||||
return bytearray()
|
||||
def could_raise_returns_D() -> D:
|
||||
return D()
|
||||
|
||||
def could_raise_returns_E() -> E:
|
||||
return E()
|
||||
|
||||
x = 1
|
||||
|
||||
try:
|
||||
reveal_type(x) # revealed: Literal[1]
|
||||
x = could_raise_returns_str()
|
||||
reveal_type(x) # revealed: str
|
||||
x = could_raise_returns_A()
|
||||
reveal_type(x) # revealed: A
|
||||
except TypeError:
|
||||
reveal_type(x) # revealed: Literal[1] | str
|
||||
x = could_raise_returns_bytes()
|
||||
reveal_type(x) # revealed: bytes
|
||||
x = could_raise_returns_bool()
|
||||
reveal_type(x) # revealed: bool
|
||||
reveal_type(x) # revealed: Literal[1] | A
|
||||
x = could_raise_returns_B()
|
||||
reveal_type(x) # revealed: B
|
||||
x = could_raise_returns_C()
|
||||
reveal_type(x) # revealed: C
|
||||
except ValueError:
|
||||
reveal_type(x) # revealed: Literal[1] | str
|
||||
x = could_raise_returns_memoryview()
|
||||
reveal_type(x) # revealed: memoryview
|
||||
x = could_raise_returns_bytearray()
|
||||
reveal_type(x) # revealed: bytearray
|
||||
reveal_type(x) # revealed: Literal[1] | A
|
||||
x = could_raise_returns_D()
|
||||
reveal_type(x) # revealed: D
|
||||
x = could_raise_returns_E()
|
||||
reveal_type(x) # revealed: E
|
||||
finally:
|
||||
# TODO: should be `Literal[1] | str | bytes | bool | memoryview | bytearray`
|
||||
reveal_type(x) # revealed: str | bool | bytearray
|
||||
# TODO: should be `Literal[1] | A | B | C | D | E`
|
||||
reveal_type(x) # revealed: A | C | E
|
||||
|
||||
reveal_type(x) # revealed: str | bool | bytearray
|
||||
reveal_type(x) # revealed: A | C | E
|
||||
```
|
||||
|
||||
## Combining `except`, `else` and `finally` branches
|
||||
|
|
@ -338,84 +345,93 @@ control flow could have jumped to the `finally` suite from partway through the `
|
|||
an exception raised *there*.
|
||||
|
||||
```py
|
||||
def could_raise_returns_str() -> str:
|
||||
return "foo"
|
||||
class A: ...
|
||||
class B: ...
|
||||
class C: ...
|
||||
class D: ...
|
||||
class E: ...
|
||||
|
||||
def could_raise_returns_bytes() -> bytes:
|
||||
return b"foo"
|
||||
def could_raise_returns_A() -> A:
|
||||
return A()
|
||||
|
||||
def could_raise_returns_bool() -> bool:
|
||||
return True
|
||||
def could_raise_returns_B() -> B:
|
||||
return B()
|
||||
|
||||
def could_raise_returns_memoryview() -> memoryview:
|
||||
return memoryview(b"")
|
||||
def could_raise_returns_C() -> C:
|
||||
return C()
|
||||
|
||||
def could_raise_returns_bytearray() -> bytearray:
|
||||
return bytearray()
|
||||
def could_raise_returns_D() -> D:
|
||||
return D()
|
||||
|
||||
def could_raise_returns_E() -> E:
|
||||
return E()
|
||||
|
||||
x = 1
|
||||
|
||||
try:
|
||||
reveal_type(x) # revealed: Literal[1]
|
||||
x = could_raise_returns_str()
|
||||
reveal_type(x) # revealed: str
|
||||
x = could_raise_returns_A()
|
||||
reveal_type(x) # revealed: A
|
||||
except TypeError:
|
||||
reveal_type(x) # revealed: Literal[1] | str
|
||||
x = could_raise_returns_bytes()
|
||||
reveal_type(x) # revealed: bytes
|
||||
x = could_raise_returns_bool()
|
||||
reveal_type(x) # revealed: bool
|
||||
reveal_type(x) # revealed: Literal[1] | A
|
||||
x = could_raise_returns_B()
|
||||
reveal_type(x) # revealed: B
|
||||
x = could_raise_returns_C()
|
||||
reveal_type(x) # revealed: C
|
||||
else:
|
||||
reveal_type(x) # revealed: str
|
||||
x = could_raise_returns_memoryview()
|
||||
reveal_type(x) # revealed: memoryview
|
||||
x = could_raise_returns_bytearray()
|
||||
reveal_type(x) # revealed: bytearray
|
||||
reveal_type(x) # revealed: A
|
||||
x = could_raise_returns_D()
|
||||
reveal_type(x) # revealed: D
|
||||
x = could_raise_returns_E()
|
||||
reveal_type(x) # revealed: E
|
||||
finally:
|
||||
# TODO: should be `Literal[1] | str | bytes | bool | memoryview | bytearray`
|
||||
reveal_type(x) # revealed: bool | bytearray
|
||||
# TODO: should be `Literal[1] | A | B | C | D | E`
|
||||
reveal_type(x) # revealed: C | E
|
||||
|
||||
reveal_type(x) # revealed: bool | bytearray
|
||||
reveal_type(x) # revealed: C | E
|
||||
```
|
||||
|
||||
The same again, this time with multiple `except` branches:
|
||||
|
||||
```py
|
||||
def could_raise_returns_range() -> range:
|
||||
return range(42)
|
||||
class F: ...
|
||||
class G: ...
|
||||
|
||||
def could_raise_returns_slice() -> slice:
|
||||
return slice(None)
|
||||
def could_raise_returns_F() -> F:
|
||||
return F()
|
||||
|
||||
def could_raise_returns_G() -> G:
|
||||
return G()
|
||||
|
||||
x = 1
|
||||
|
||||
try:
|
||||
reveal_type(x) # revealed: Literal[1]
|
||||
x = could_raise_returns_str()
|
||||
reveal_type(x) # revealed: str
|
||||
x = could_raise_returns_A()
|
||||
reveal_type(x) # revealed: A
|
||||
except TypeError:
|
||||
reveal_type(x) # revealed: Literal[1] | str
|
||||
x = could_raise_returns_bytes()
|
||||
reveal_type(x) # revealed: bytes
|
||||
x = could_raise_returns_bool()
|
||||
reveal_type(x) # revealed: bool
|
||||
reveal_type(x) # revealed: Literal[1] | A
|
||||
x = could_raise_returns_B()
|
||||
reveal_type(x) # revealed: B
|
||||
x = could_raise_returns_C()
|
||||
reveal_type(x) # revealed: C
|
||||
except ValueError:
|
||||
reveal_type(x) # revealed: Literal[1] | str
|
||||
x = could_raise_returns_memoryview()
|
||||
reveal_type(x) # revealed: memoryview
|
||||
x = could_raise_returns_bytearray()
|
||||
reveal_type(x) # revealed: bytearray
|
||||
reveal_type(x) # revealed: Literal[1] | A
|
||||
x = could_raise_returns_D()
|
||||
reveal_type(x) # revealed: D
|
||||
x = could_raise_returns_E()
|
||||
reveal_type(x) # revealed: E
|
||||
else:
|
||||
reveal_type(x) # revealed: str
|
||||
x = could_raise_returns_range()
|
||||
reveal_type(x) # revealed: range
|
||||
x = could_raise_returns_slice()
|
||||
reveal_type(x) # revealed: slice
|
||||
reveal_type(x) # revealed: A
|
||||
x = could_raise_returns_F()
|
||||
reveal_type(x) # revealed: F
|
||||
x = could_raise_returns_G()
|
||||
reveal_type(x) # revealed: G
|
||||
finally:
|
||||
# TODO: should be `Literal[1] | str | bytes | bool | memoryview | bytearray | range | slice`
|
||||
reveal_type(x) # revealed: bool | bytearray | slice
|
||||
# TODO: should be `Literal[1] | A | B | C | D | E | F | G`
|
||||
reveal_type(x) # revealed: C | E | G
|
||||
|
||||
reveal_type(x) # revealed: bool | bytearray | slice
|
||||
reveal_type(x) # revealed: C | E | G
|
||||
```
|
||||
|
||||
## Nested `try`/`except` blocks
|
||||
|
|
@ -429,92 +445,101 @@ a suite containing statements that could possibly raise exceptions, which would
|
|||
jumping out of that suite prior to the suite running to completion.
|
||||
|
||||
```py
|
||||
def could_raise_returns_str() -> str:
|
||||
return "foo"
|
||||
class A: ...
|
||||
class B: ...
|
||||
class C: ...
|
||||
class D: ...
|
||||
class E: ...
|
||||
class F: ...
|
||||
class G: ...
|
||||
class H: ...
|
||||
class I: ...
|
||||
class J: ...
|
||||
class K: ...
|
||||
|
||||
def could_raise_returns_bytes() -> bytes:
|
||||
return b"foo"
|
||||
def could_raise_returns_A() -> A:
|
||||
return A()
|
||||
|
||||
def could_raise_returns_bool() -> bool:
|
||||
return True
|
||||
def could_raise_returns_B() -> B:
|
||||
return B()
|
||||
|
||||
def could_raise_returns_memoryview() -> memoryview:
|
||||
return memoryview(b"")
|
||||
def could_raise_returns_C() -> C:
|
||||
return C()
|
||||
|
||||
def could_raise_returns_property() -> property:
|
||||
return property()
|
||||
def could_raise_returns_D() -> D:
|
||||
return D()
|
||||
|
||||
def could_raise_returns_range() -> range:
|
||||
return range(42)
|
||||
def could_raise_returns_E() -> E:
|
||||
return E()
|
||||
|
||||
def could_raise_returns_slice() -> slice:
|
||||
return slice(None)
|
||||
def could_raise_returns_F() -> F:
|
||||
return F()
|
||||
|
||||
def could_raise_returns_super() -> super:
|
||||
return super()
|
||||
def could_raise_returns_G() -> G:
|
||||
return G()
|
||||
|
||||
def could_raise_returns_bytearray() -> bytearray:
|
||||
return bytearray()
|
||||
def could_raise_returns_H() -> H:
|
||||
return H()
|
||||
|
||||
class Foo: ...
|
||||
class Bar: ...
|
||||
def could_raise_returns_I() -> I:
|
||||
return I()
|
||||
|
||||
def could_raise_returns_Foo() -> Foo:
|
||||
return Foo()
|
||||
def could_raise_returns_J() -> J:
|
||||
return J()
|
||||
|
||||
def could_raise_returns_Bar() -> Bar:
|
||||
return Bar()
|
||||
def could_raise_returns_K() -> K:
|
||||
return K()
|
||||
|
||||
x = 1
|
||||
|
||||
try:
|
||||
try:
|
||||
reveal_type(x) # revealed: Literal[1]
|
||||
x = could_raise_returns_str()
|
||||
reveal_type(x) # revealed: str
|
||||
x = could_raise_returns_A()
|
||||
reveal_type(x) # revealed: A
|
||||
except TypeError:
|
||||
reveal_type(x) # revealed: Literal[1] | str
|
||||
x = could_raise_returns_bytes()
|
||||
reveal_type(x) # revealed: bytes
|
||||
x = could_raise_returns_bool()
|
||||
reveal_type(x) # revealed: bool
|
||||
reveal_type(x) # revealed: Literal[1] | A
|
||||
x = could_raise_returns_B()
|
||||
reveal_type(x) # revealed: B
|
||||
x = could_raise_returns_C()
|
||||
reveal_type(x) # revealed: C
|
||||
except ValueError:
|
||||
reveal_type(x) # revealed: Literal[1] | str
|
||||
x = could_raise_returns_memoryview()
|
||||
reveal_type(x) # revealed: memoryview
|
||||
x = could_raise_returns_property()
|
||||
reveal_type(x) # revealed: property
|
||||
reveal_type(x) # revealed: Literal[1] | A
|
||||
x = could_raise_returns_D()
|
||||
reveal_type(x) # revealed: D
|
||||
x = could_raise_returns_E()
|
||||
reveal_type(x) # revealed: E
|
||||
else:
|
||||
reveal_type(x) # revealed: str
|
||||
x = could_raise_returns_range()
|
||||
reveal_type(x) # revealed: range
|
||||
x = could_raise_returns_slice()
|
||||
reveal_type(x) # revealed: slice
|
||||
reveal_type(x) # revealed: A
|
||||
x = could_raise_returns_F()
|
||||
reveal_type(x) # revealed: F
|
||||
x = could_raise_returns_G()
|
||||
reveal_type(x) # revealed: G
|
||||
finally:
|
||||
# TODO: should be `Literal[1] | str | bytes | bool | memoryview | property | range | slice`
|
||||
reveal_type(x) # revealed: bool | property | slice
|
||||
# TODO: should be `Literal[1] | A | B | C | D | E | F | G`
|
||||
reveal_type(x) # revealed: C | E | G
|
||||
x = 2
|
||||
reveal_type(x) # revealed: Literal[2]
|
||||
reveal_type(x) # revealed: Literal[2]
|
||||
except:
|
||||
reveal_type(x) # revealed: Literal[1, 2] | str | bytes | bool | memoryview | property | range | slice
|
||||
x = could_raise_returns_super()
|
||||
reveal_type(x) # revealed: super
|
||||
x = could_raise_returns_bytearray()
|
||||
reveal_type(x) # revealed: bytearray
|
||||
reveal_type(x) # revealed: Literal[1, 2] | A | B | C | D | E | F | G
|
||||
x = could_raise_returns_H()
|
||||
reveal_type(x) # revealed: H
|
||||
x = could_raise_returns_I()
|
||||
reveal_type(x) # revealed: I
|
||||
else:
|
||||
reveal_type(x) # revealed: Literal[2]
|
||||
x = could_raise_returns_Foo()
|
||||
reveal_type(x) # revealed: Foo
|
||||
x = could_raise_returns_Bar()
|
||||
reveal_type(x) # revealed: Bar
|
||||
x = could_raise_returns_J()
|
||||
reveal_type(x) # revealed: J
|
||||
x = could_raise_returns_K()
|
||||
reveal_type(x) # revealed: K
|
||||
finally:
|
||||
# TODO: should be `Literal[1, 2] | str | bytes | bool | memoryview | property | range | slice | super | bytearray | Foo | Bar`
|
||||
reveal_type(x) # revealed: bytearray | Bar
|
||||
# TODO: should be `Literal[1, 2] | A | B | C | D | E | F | G | H | I | J | K`
|
||||
reveal_type(x) # revealed: I | K
|
||||
|
||||
# Either one `except` branch or the `else`
|
||||
# must have been taken and completed to get here:
|
||||
reveal_type(x) # revealed: bytearray | Bar
|
||||
reveal_type(x) # revealed: I | K
|
||||
```
|
||||
|
||||
## Nested scopes inside `try` blocks
|
||||
|
|
@ -523,50 +548,56 @@ Shadowing a variable in an inner scope has no effect on type inference of the va
|
|||
in the outer scope:
|
||||
|
||||
```py
|
||||
def could_raise_returns_str() -> str:
|
||||
return "foo"
|
||||
class A: ...
|
||||
class B: ...
|
||||
class C: ...
|
||||
class D: ...
|
||||
class E: ...
|
||||
|
||||
def could_raise_returns_bytes() -> bytes:
|
||||
return b"foo"
|
||||
def could_raise_returns_A() -> A:
|
||||
return A()
|
||||
|
||||
def could_raise_returns_range() -> range:
|
||||
return range(42)
|
||||
def could_raise_returns_B() -> B:
|
||||
return B()
|
||||
|
||||
def could_raise_returns_bytearray() -> bytearray:
|
||||
return bytearray()
|
||||
def could_raise_returns_C() -> C:
|
||||
return C()
|
||||
|
||||
def could_raise_returns_memoryview() -> memoryview:
|
||||
return memoryview(b"")
|
||||
def could_raise_returns_D() -> D:
|
||||
return D()
|
||||
|
||||
def could_raise_returns_E() -> E:
|
||||
return E()
|
||||
|
||||
x = 1
|
||||
|
||||
try:
|
||||
|
||||
def foo(param=could_raise_returns_str()):
|
||||
x = could_raise_returns_str()
|
||||
def foo(param=could_raise_returns_A()):
|
||||
x = could_raise_returns_A()
|
||||
|
||||
try:
|
||||
reveal_type(x) # revealed: str
|
||||
x = could_raise_returns_bytes()
|
||||
reveal_type(x) # revealed: bytes
|
||||
reveal_type(x) # revealed: A
|
||||
x = could_raise_returns_B()
|
||||
reveal_type(x) # revealed: B
|
||||
except:
|
||||
reveal_type(x) # revealed: str | bytes
|
||||
x = could_raise_returns_bytearray()
|
||||
reveal_type(x) # revealed: bytearray
|
||||
x = could_raise_returns_memoryview()
|
||||
reveal_type(x) # revealed: memoryview
|
||||
reveal_type(x) # revealed: A | B
|
||||
x = could_raise_returns_C()
|
||||
reveal_type(x) # revealed: C
|
||||
x = could_raise_returns_D()
|
||||
reveal_type(x) # revealed: D
|
||||
finally:
|
||||
# TODO: should be `str | bytes | bytearray | memoryview`
|
||||
reveal_type(x) # revealed: bytes | memoryview
|
||||
reveal_type(x) # revealed: bytes | memoryview
|
||||
# TODO: should be `A | B | C | D`
|
||||
reveal_type(x) # revealed: B | D
|
||||
reveal_type(x) # revealed: B | D
|
||||
x = foo
|
||||
reveal_type(x) # revealed: Literal[foo]
|
||||
except:
|
||||
reveal_type(x) # revealed: Literal[1] | Literal[foo]
|
||||
|
||||
class Bar:
|
||||
x = could_raise_returns_range()
|
||||
reveal_type(x) # revealed: range
|
||||
x = could_raise_returns_E()
|
||||
reveal_type(x) # revealed: E
|
||||
|
||||
x = Bar
|
||||
reveal_type(x) # revealed: Literal[Bar]
|
||||
|
|
|
|||
|
|
@ -183,25 +183,32 @@ for x in Test():
|
|||
## Union type as iterable and union type as iterator
|
||||
|
||||
```py
|
||||
class TestIter:
|
||||
def __next__(self) -> int | Exception:
|
||||
return 42
|
||||
class Result1A: ...
|
||||
class Result1B: ...
|
||||
class Result2A: ...
|
||||
class Result2B: ...
|
||||
class Result3: ...
|
||||
class Result4: ...
|
||||
|
||||
class TestIter1:
|
||||
def __next__(self) -> Result1A | Result1B:
|
||||
return Result1B()
|
||||
|
||||
class TestIter2:
|
||||
def __next__(self) -> str | tuple[int, int]:
|
||||
return "42"
|
||||
def __next__(self) -> Result2A | Result2B:
|
||||
return Result2B()
|
||||
|
||||
class TestIter3:
|
||||
def __next__(self) -> bytes:
|
||||
return b"42"
|
||||
def __next__(self) -> Result3:
|
||||
return Result3()
|
||||
|
||||
class TestIter4:
|
||||
def __next__(self) -> memoryview:
|
||||
return memoryview(b"42")
|
||||
def __next__(self) -> Result4:
|
||||
return Result4()
|
||||
|
||||
class Test:
|
||||
def __iter__(self) -> TestIter | TestIter2:
|
||||
return TestIter()
|
||||
def __iter__(self) -> TestIter1 | TestIter2:
|
||||
return TestIter1()
|
||||
|
||||
class Test2:
|
||||
def __iter__(self) -> TestIter3 | TestIter4:
|
||||
|
|
@ -209,7 +216,7 @@ class Test2:
|
|||
|
||||
def _(flag: bool):
|
||||
for x in Test() if flag else Test2():
|
||||
reveal_type(x) # revealed: int | Exception | str | tuple[int, int] | bytes | memoryview
|
||||
reveal_type(x) # revealed: Result1A | Result1B | Result2A | Result2B | Result3 | Result4
|
||||
```
|
||||
|
||||
## Union type as iterable where one union element has no `__iter__` method
|
||||
|
|
|
|||
Loading…
Reference in New Issue