mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-25 22:29:02 +00:00
[ty] Add functions for revealing assignability/subtyping constraints (#20217)
This PR adds two new `ty_extensions` functions, `reveal_when_assignable_to` and `reveal_when_subtype_of`. These are closely related to the existing `is_assignable_to` and `is_subtype_of`, but instead of returning when the property (always) holds, it produces a diagnostic that describes _when_ the property holds. (This will let us construct mdtests that print out constraints that are not always true or always false — though we don't currently have any instances of those.) I did not replace _every_ occurrence of the `is_property` variants in the mdtest suite, instead focusing on the generics-related tests where it will be important to see the full detail of the constraint sets. As part of this, I also updated the mdtest harness to accept the shorter `# revealed:` assertion format for more than just `reveal_type`, and updated the existing uses of `reveal_protocol_interface` to take advantage of this.
This commit is contained in:
parent
200349c6e8
commit
77b2cee223
7 changed files with 309 additions and 199 deletions
|
|
@ -129,7 +129,7 @@ specialization. Thus, the typevar is a subtype of itself and of `object`, but no
|
|||
(including other typevars).
|
||||
|
||||
```py
|
||||
from ty_extensions import is_assignable_to, is_subtype_of, static_assert
|
||||
from ty_extensions import reveal_when_assignable_to, reveal_when_subtype_of
|
||||
|
||||
class Super: ...
|
||||
class Base(Super): ...
|
||||
|
|
@ -137,23 +137,23 @@ class Sub(Base): ...
|
|||
class Unrelated: ...
|
||||
|
||||
def unbounded_unconstrained[T, U](t: T, u: U) -> None:
|
||||
static_assert(is_assignable_to(T, T))
|
||||
static_assert(is_assignable_to(T, object))
|
||||
static_assert(not is_assignable_to(T, Super))
|
||||
static_assert(is_assignable_to(U, U))
|
||||
static_assert(is_assignable_to(U, object))
|
||||
static_assert(not is_assignable_to(U, Super))
|
||||
static_assert(not is_assignable_to(T, U))
|
||||
static_assert(not is_assignable_to(U, T))
|
||||
reveal_when_assignable_to(T, T) # revealed: always
|
||||
reveal_when_assignable_to(T, object) # revealed: always
|
||||
reveal_when_assignable_to(T, Super) # revealed: never
|
||||
reveal_when_assignable_to(U, U) # revealed: always
|
||||
reveal_when_assignable_to(U, object) # revealed: always
|
||||
reveal_when_assignable_to(U, Super) # revealed: never
|
||||
reveal_when_assignable_to(T, U) # revealed: never
|
||||
reveal_when_assignable_to(U, T) # revealed: never
|
||||
|
||||
static_assert(is_subtype_of(T, T))
|
||||
static_assert(is_subtype_of(T, object))
|
||||
static_assert(not is_subtype_of(T, Super))
|
||||
static_assert(is_subtype_of(U, U))
|
||||
static_assert(is_subtype_of(U, object))
|
||||
static_assert(not is_subtype_of(U, Super))
|
||||
static_assert(not is_subtype_of(T, U))
|
||||
static_assert(not is_subtype_of(U, T))
|
||||
reveal_when_subtype_of(T, T) # revealed: always
|
||||
reveal_when_subtype_of(T, object) # revealed: always
|
||||
reveal_when_subtype_of(T, Super) # revealed: never
|
||||
reveal_when_subtype_of(U, U) # revealed: always
|
||||
reveal_when_subtype_of(U, object) # revealed: always
|
||||
reveal_when_subtype_of(U, Super) # revealed: never
|
||||
reveal_when_subtype_of(T, U) # revealed: never
|
||||
reveal_when_subtype_of(U, T) # revealed: never
|
||||
```
|
||||
|
||||
A bounded typevar is assignable to its bound, and a bounded, fully static typevar is a subtype of
|
||||
|
|
@ -167,40 +167,40 @@ from typing import Any
|
|||
from typing_extensions import final
|
||||
|
||||
def bounded[T: Super](t: T) -> None:
|
||||
static_assert(is_assignable_to(T, Super))
|
||||
static_assert(not is_assignable_to(T, Sub))
|
||||
static_assert(not is_assignable_to(Super, T))
|
||||
static_assert(not is_assignable_to(Sub, T))
|
||||
reveal_when_assignable_to(T, Super) # revealed: always
|
||||
reveal_when_assignable_to(T, Sub) # revealed: never
|
||||
reveal_when_assignable_to(Super, T) # revealed: never
|
||||
reveal_when_assignable_to(Sub, T) # revealed: never
|
||||
|
||||
static_assert(is_subtype_of(T, Super))
|
||||
static_assert(not is_subtype_of(T, Sub))
|
||||
static_assert(not is_subtype_of(Super, T))
|
||||
static_assert(not is_subtype_of(Sub, T))
|
||||
reveal_when_subtype_of(T, Super) # revealed: always
|
||||
reveal_when_subtype_of(T, Sub) # revealed: never
|
||||
reveal_when_subtype_of(Super, T) # revealed: never
|
||||
reveal_when_subtype_of(Sub, T) # revealed: never
|
||||
|
||||
def bounded_by_gradual[T: Any](t: T) -> None:
|
||||
static_assert(is_assignable_to(T, Any))
|
||||
static_assert(is_assignable_to(Any, T))
|
||||
static_assert(is_assignable_to(T, Super))
|
||||
static_assert(not is_assignable_to(Super, T))
|
||||
static_assert(is_assignable_to(T, Sub))
|
||||
static_assert(not is_assignable_to(Sub, T))
|
||||
reveal_when_assignable_to(T, Any) # revealed: always
|
||||
reveal_when_assignable_to(Any, T) # revealed: always
|
||||
reveal_when_assignable_to(T, Super) # revealed: always
|
||||
reveal_when_assignable_to(Super, T) # revealed: never
|
||||
reveal_when_assignable_to(T, Sub) # revealed: always
|
||||
reveal_when_assignable_to(Sub, T) # revealed: never
|
||||
|
||||
static_assert(not is_subtype_of(T, Any))
|
||||
static_assert(not is_subtype_of(Any, T))
|
||||
static_assert(not is_subtype_of(T, Super))
|
||||
static_assert(not is_subtype_of(Super, T))
|
||||
static_assert(not is_subtype_of(T, Sub))
|
||||
static_assert(not is_subtype_of(Sub, T))
|
||||
reveal_when_subtype_of(T, Any) # revealed: never
|
||||
reveal_when_subtype_of(Any, T) # revealed: never
|
||||
reveal_when_subtype_of(T, Super) # revealed: never
|
||||
reveal_when_subtype_of(Super, T) # revealed: never
|
||||
reveal_when_subtype_of(T, Sub) # revealed: never
|
||||
reveal_when_subtype_of(Sub, T) # revealed: never
|
||||
|
||||
@final
|
||||
class FinalClass: ...
|
||||
|
||||
def bounded_final[T: FinalClass](t: T) -> None:
|
||||
static_assert(is_assignable_to(T, FinalClass))
|
||||
static_assert(not is_assignable_to(FinalClass, T))
|
||||
reveal_when_assignable_to(T, FinalClass) # revealed: always
|
||||
reveal_when_assignable_to(FinalClass, T) # revealed: never
|
||||
|
||||
static_assert(is_subtype_of(T, FinalClass))
|
||||
static_assert(not is_subtype_of(FinalClass, T))
|
||||
reveal_when_subtype_of(T, FinalClass) # revealed: always
|
||||
reveal_when_subtype_of(FinalClass, T) # revealed: never
|
||||
```
|
||||
|
||||
Two distinct fully static typevars are not subtypes of each other, even if they have the same
|
||||
|
|
@ -210,18 +210,18 @@ typevars to `Never` in addition to that final class.
|
|||
|
||||
```py
|
||||
def two_bounded[T: Super, U: Super](t: T, u: U) -> None:
|
||||
static_assert(not is_assignable_to(T, U))
|
||||
static_assert(not is_assignable_to(U, T))
|
||||
reveal_when_assignable_to(T, U) # revealed: never
|
||||
reveal_when_assignable_to(U, T) # revealed: never
|
||||
|
||||
static_assert(not is_subtype_of(T, U))
|
||||
static_assert(not is_subtype_of(U, T))
|
||||
reveal_when_subtype_of(T, U) # revealed: never
|
||||
reveal_when_subtype_of(U, T) # revealed: never
|
||||
|
||||
def two_final_bounded[T: FinalClass, U: FinalClass](t: T, u: U) -> None:
|
||||
static_assert(not is_assignable_to(T, U))
|
||||
static_assert(not is_assignable_to(U, T))
|
||||
reveal_when_assignable_to(T, U) # revealed: never
|
||||
reveal_when_assignable_to(U, T) # revealed: never
|
||||
|
||||
static_assert(not is_subtype_of(T, U))
|
||||
static_assert(not is_subtype_of(U, T))
|
||||
reveal_when_subtype_of(T, U) # revealed: never
|
||||
reveal_when_subtype_of(U, T) # revealed: never
|
||||
```
|
||||
|
||||
A constrained fully static typevar is assignable to the union of its constraints, but not to any of
|
||||
|
|
@ -232,64 +232,64 @@ intersection of all of its constraints is a subtype of the typevar.
|
|||
from ty_extensions import Intersection
|
||||
|
||||
def constrained[T: (Base, Unrelated)](t: T) -> None:
|
||||
static_assert(not is_assignable_to(T, Super))
|
||||
static_assert(not is_assignable_to(T, Base))
|
||||
static_assert(not is_assignable_to(T, Sub))
|
||||
static_assert(not is_assignable_to(T, Unrelated))
|
||||
static_assert(is_assignable_to(T, Super | Unrelated))
|
||||
static_assert(is_assignable_to(T, Base | Unrelated))
|
||||
static_assert(not is_assignable_to(T, Sub | Unrelated))
|
||||
static_assert(not is_assignable_to(Super, T))
|
||||
static_assert(not is_assignable_to(Unrelated, T))
|
||||
static_assert(not is_assignable_to(Super | Unrelated, T))
|
||||
static_assert(is_assignable_to(Intersection[Base, Unrelated], T))
|
||||
reveal_when_assignable_to(T, Super) # revealed: never
|
||||
reveal_when_assignable_to(T, Base) # revealed: never
|
||||
reveal_when_assignable_to(T, Sub) # revealed: never
|
||||
reveal_when_assignable_to(T, Unrelated) # revealed: never
|
||||
reveal_when_assignable_to(T, Super | Unrelated) # revealed: always
|
||||
reveal_when_assignable_to(T, Base | Unrelated) # revealed: always
|
||||
reveal_when_assignable_to(T, Sub | Unrelated) # revealed: never
|
||||
reveal_when_assignable_to(Super, T) # revealed: never
|
||||
reveal_when_assignable_to(Unrelated, T) # revealed: never
|
||||
reveal_when_assignable_to(Super | Unrelated, T) # revealed: never
|
||||
reveal_when_assignable_to(Intersection[Base, Unrelated], T) # revealed: always
|
||||
|
||||
static_assert(not is_subtype_of(T, Super))
|
||||
static_assert(not is_subtype_of(T, Base))
|
||||
static_assert(not is_subtype_of(T, Sub))
|
||||
static_assert(not is_subtype_of(T, Unrelated))
|
||||
static_assert(is_subtype_of(T, Super | Unrelated))
|
||||
static_assert(is_subtype_of(T, Base | Unrelated))
|
||||
static_assert(not is_subtype_of(T, Sub | Unrelated))
|
||||
static_assert(not is_subtype_of(Super, T))
|
||||
static_assert(not is_subtype_of(Unrelated, T))
|
||||
static_assert(not is_subtype_of(Super | Unrelated, T))
|
||||
static_assert(is_subtype_of(Intersection[Base, Unrelated], T))
|
||||
reveal_when_subtype_of(T, Super) # revealed: never
|
||||
reveal_when_subtype_of(T, Base) # revealed: never
|
||||
reveal_when_subtype_of(T, Sub) # revealed: never
|
||||
reveal_when_subtype_of(T, Unrelated) # revealed: never
|
||||
reveal_when_subtype_of(T, Super | Unrelated) # revealed: always
|
||||
reveal_when_subtype_of(T, Base | Unrelated) # revealed: always
|
||||
reveal_when_subtype_of(T, Sub | Unrelated) # revealed: never
|
||||
reveal_when_subtype_of(Super, T) # revealed: never
|
||||
reveal_when_subtype_of(Unrelated, T) # revealed: never
|
||||
reveal_when_subtype_of(Super | Unrelated, T) # revealed: never
|
||||
reveal_when_subtype_of(Intersection[Base, Unrelated], T) # revealed: always
|
||||
|
||||
def constrained_by_gradual[T: (Base, Any)](t: T) -> None:
|
||||
static_assert(is_assignable_to(T, Super))
|
||||
static_assert(is_assignable_to(T, Base))
|
||||
static_assert(not is_assignable_to(T, Sub))
|
||||
static_assert(not is_assignable_to(T, Unrelated))
|
||||
static_assert(is_assignable_to(T, Any))
|
||||
static_assert(is_assignable_to(T, Super | Any))
|
||||
static_assert(is_assignable_to(T, Super | Unrelated))
|
||||
static_assert(not is_assignable_to(Super, T))
|
||||
static_assert(is_assignable_to(Base, T))
|
||||
static_assert(not is_assignable_to(Unrelated, T))
|
||||
static_assert(is_assignable_to(Any, T))
|
||||
static_assert(not is_assignable_to(Super | Any, T))
|
||||
static_assert(is_assignable_to(Base | Any, T))
|
||||
static_assert(not is_assignable_to(Super | Unrelated, T))
|
||||
static_assert(is_assignable_to(Intersection[Base, Unrelated], T))
|
||||
static_assert(is_assignable_to(Intersection[Base, Any], T))
|
||||
reveal_when_assignable_to(T, Super) # revealed: always
|
||||
reveal_when_assignable_to(T, Base) # revealed: always
|
||||
reveal_when_assignable_to(T, Sub) # revealed: never
|
||||
reveal_when_assignable_to(T, Unrelated) # revealed: never
|
||||
reveal_when_assignable_to(T, Any) # revealed: always
|
||||
reveal_when_assignable_to(T, Super | Any) # revealed: always
|
||||
reveal_when_assignable_to(T, Super | Unrelated) # revealed: always
|
||||
reveal_when_assignable_to(Super, T) # revealed: never
|
||||
reveal_when_assignable_to(Base, T) # revealed: always
|
||||
reveal_when_assignable_to(Unrelated, T) # revealed: never
|
||||
reveal_when_assignable_to(Any, T) # revealed: always
|
||||
reveal_when_assignable_to(Super | Any, T) # revealed: never
|
||||
reveal_when_assignable_to(Base | Any, T) # revealed: always
|
||||
reveal_when_assignable_to(Super | Unrelated, T) # revealed: never
|
||||
reveal_when_assignable_to(Intersection[Base, Unrelated], T) # revealed: always
|
||||
reveal_when_assignable_to(Intersection[Base, Any], T) # revealed: always
|
||||
|
||||
static_assert(not is_subtype_of(T, Super))
|
||||
static_assert(not is_subtype_of(T, Base))
|
||||
static_assert(not is_subtype_of(T, Sub))
|
||||
static_assert(not is_subtype_of(T, Unrelated))
|
||||
static_assert(not is_subtype_of(T, Any))
|
||||
static_assert(not is_subtype_of(T, Super | Any))
|
||||
static_assert(not is_subtype_of(T, Super | Unrelated))
|
||||
static_assert(not is_subtype_of(Super, T))
|
||||
static_assert(not is_subtype_of(Base, T))
|
||||
static_assert(not is_subtype_of(Unrelated, T))
|
||||
static_assert(not is_subtype_of(Any, T))
|
||||
static_assert(not is_subtype_of(Super | Any, T))
|
||||
static_assert(not is_subtype_of(Base | Any, T))
|
||||
static_assert(not is_subtype_of(Super | Unrelated, T))
|
||||
static_assert(not is_subtype_of(Intersection[Base, Unrelated], T))
|
||||
static_assert(not is_subtype_of(Intersection[Base, Any], T))
|
||||
reveal_when_subtype_of(T, Super) # revealed: never
|
||||
reveal_when_subtype_of(T, Base) # revealed: never
|
||||
reveal_when_subtype_of(T, Sub) # revealed: never
|
||||
reveal_when_subtype_of(T, Unrelated) # revealed: never
|
||||
reveal_when_subtype_of(T, Any) # revealed: never
|
||||
reveal_when_subtype_of(T, Super | Any) # revealed: never
|
||||
reveal_when_subtype_of(T, Super | Unrelated) # revealed: never
|
||||
reveal_when_subtype_of(Super, T) # revealed: never
|
||||
reveal_when_subtype_of(Base, T) # revealed: never
|
||||
reveal_when_subtype_of(Unrelated, T) # revealed: never
|
||||
reveal_when_subtype_of(Any, T) # revealed: never
|
||||
reveal_when_subtype_of(Super | Any, T) # revealed: never
|
||||
reveal_when_subtype_of(Base | Any, T) # revealed: never
|
||||
reveal_when_subtype_of(Super | Unrelated, T) # revealed: never
|
||||
reveal_when_subtype_of(Intersection[Base, Unrelated], T) # revealed: never
|
||||
reveal_when_subtype_of(Intersection[Base, Any], T) # revealed: never
|
||||
```
|
||||
|
||||
Two distinct fully static typevars are not subtypes of each other, even if they have the same
|
||||
|
|
@ -299,58 +299,58 @@ the same type.
|
|||
|
||||
```py
|
||||
def two_constrained[T: (int, str), U: (int, str)](t: T, u: U) -> None:
|
||||
static_assert(not is_assignable_to(T, U))
|
||||
static_assert(not is_assignable_to(U, T))
|
||||
reveal_when_assignable_to(T, U) # revealed: never
|
||||
reveal_when_assignable_to(U, T) # revealed: never
|
||||
|
||||
static_assert(not is_subtype_of(T, U))
|
||||
static_assert(not is_subtype_of(U, T))
|
||||
reveal_when_subtype_of(T, U) # revealed: never
|
||||
reveal_when_subtype_of(U, T) # revealed: never
|
||||
|
||||
@final
|
||||
class AnotherFinalClass: ...
|
||||
|
||||
def two_final_constrained[T: (FinalClass, AnotherFinalClass), U: (FinalClass, AnotherFinalClass)](t: T, u: U) -> None:
|
||||
static_assert(not is_assignable_to(T, U))
|
||||
static_assert(not is_assignable_to(U, T))
|
||||
reveal_when_assignable_to(T, U) # revealed: never
|
||||
reveal_when_assignable_to(U, T) # revealed: never
|
||||
|
||||
static_assert(not is_subtype_of(T, U))
|
||||
static_assert(not is_subtype_of(U, T))
|
||||
reveal_when_subtype_of(T, U) # revealed: never
|
||||
reveal_when_subtype_of(U, T) # revealed: never
|
||||
```
|
||||
|
||||
A bound or constrained typevar is a subtype of itself in a union:
|
||||
|
||||
```py
|
||||
def union[T: Base, U: (Base, Unrelated)](t: T, u: U) -> None:
|
||||
static_assert(is_assignable_to(T, T | None))
|
||||
static_assert(is_assignable_to(U, U | None))
|
||||
reveal_when_assignable_to(T, T | None) # revealed: always
|
||||
reveal_when_assignable_to(U, U | None) # revealed: always
|
||||
|
||||
static_assert(is_subtype_of(T, T | None))
|
||||
static_assert(is_subtype_of(U, U | None))
|
||||
reveal_when_subtype_of(T, T | None) # revealed: always
|
||||
reveal_when_subtype_of(U, U | None) # revealed: always
|
||||
```
|
||||
|
||||
A bound or constrained typevar in a union with a dynamic type is assignable to the typevar:
|
||||
|
||||
```py
|
||||
def union_with_dynamic[T: Base, U: (Base, Unrelated)](t: T, u: U) -> None:
|
||||
static_assert(is_assignable_to(T | Any, T))
|
||||
static_assert(is_assignable_to(U | Any, U))
|
||||
reveal_when_assignable_to(T | Any, T) # revealed: always
|
||||
reveal_when_assignable_to(U | Any, U) # revealed: always
|
||||
|
||||
static_assert(not is_subtype_of(T | Any, T))
|
||||
static_assert(not is_subtype_of(U | Any, U))
|
||||
reveal_when_subtype_of(T | Any, T) # revealed: never
|
||||
reveal_when_subtype_of(U | Any, U) # revealed: never
|
||||
```
|
||||
|
||||
And an intersection of a typevar with another type is always a subtype of the TypeVar:
|
||||
|
||||
```py
|
||||
from ty_extensions import Intersection, Not, is_disjoint_from
|
||||
from ty_extensions import Intersection, Not, is_disjoint_from, static_assert
|
||||
|
||||
class A: ...
|
||||
|
||||
def inter[T: Base, U: (Base, Unrelated)](t: T, u: U) -> None:
|
||||
static_assert(is_assignable_to(Intersection[T, Unrelated], T))
|
||||
static_assert(is_subtype_of(Intersection[T, Unrelated], T))
|
||||
reveal_when_assignable_to(Intersection[T, Unrelated], T) # revealed: always
|
||||
reveal_when_subtype_of(Intersection[T, Unrelated], T) # revealed: always
|
||||
|
||||
static_assert(is_assignable_to(Intersection[U, A], U))
|
||||
static_assert(is_subtype_of(Intersection[U, A], U))
|
||||
reveal_when_assignable_to(Intersection[U, A], U) # revealed: always
|
||||
reveal_when_subtype_of(Intersection[U, A], U) # revealed: always
|
||||
|
||||
static_assert(is_disjoint_from(Not[T], T))
|
||||
static_assert(is_disjoint_from(T, Not[T]))
|
||||
|
|
@ -647,14 +647,14 @@ The intersection of a typevar with any other type is assignable to (and if fully
|
|||
of) itself.
|
||||
|
||||
```py
|
||||
from ty_extensions import is_assignable_to, is_subtype_of, static_assert, Not
|
||||
from ty_extensions import reveal_when_assignable_to, reveal_when_subtype_of, Not
|
||||
|
||||
def intersection_is_assignable[T](t: T) -> None:
|
||||
static_assert(is_assignable_to(Intersection[T, None], T))
|
||||
static_assert(is_assignable_to(Intersection[T, Not[None]], T))
|
||||
reveal_when_assignable_to(Intersection[T, None], T) # revealed: always
|
||||
reveal_when_assignable_to(Intersection[T, Not[None]], T) # revealed: always
|
||||
|
||||
static_assert(is_subtype_of(Intersection[T, None], T))
|
||||
static_assert(is_subtype_of(Intersection[T, Not[None]], T))
|
||||
reveal_when_subtype_of(Intersection[T, None], T) # revealed: always
|
||||
reveal_when_subtype_of(Intersection[T, Not[None]], T) # revealed: always
|
||||
```
|
||||
|
||||
## Narrowing
|
||||
|
|
|
|||
|
|
@ -413,13 +413,13 @@ To see the kinds and types of the protocol members, you can use the debugging ai
|
|||
from ty_extensions import reveal_protocol_interface
|
||||
from typing import SupportsIndex, SupportsAbs, ClassVar, Iterator
|
||||
|
||||
# error: [revealed-type] "Revealed protocol interface: `{"method_member": MethodMember(`(self) -> bytes`), "x": AttributeMember(`int`), "y": PropertyMember { getter: `def y(self) -> str` }, "z": PropertyMember { getter: `def z(self) -> int`, setter: `def z(self, z: int) -> None` }}`"
|
||||
# revealed: {"method_member": MethodMember(`(self) -> bytes`), "x": AttributeMember(`int`), "y": PropertyMember { getter: `def y(self) -> str` }, "z": PropertyMember { getter: `def z(self) -> int`, setter: `def z(self, z: int) -> None` }}
|
||||
reveal_protocol_interface(Foo)
|
||||
# error: [revealed-type] "Revealed protocol interface: `{"__index__": MethodMember(`(self) -> int`)}`"
|
||||
# revealed: {"__index__": MethodMember(`(self) -> int`)}
|
||||
reveal_protocol_interface(SupportsIndex)
|
||||
# error: [revealed-type] "Revealed protocol interface: `{"__abs__": MethodMember(`(self) -> Unknown`)}`"
|
||||
# revealed: {"__abs__": MethodMember(`(self) -> Unknown`)}
|
||||
reveal_protocol_interface(SupportsAbs)
|
||||
# error: [revealed-type] "Revealed protocol interface: `{"__iter__": MethodMember(`(self) -> Iterator[Unknown]`), "__next__": MethodMember(`(self) -> Unknown`)}`"
|
||||
# revealed: {"__iter__": MethodMember(`(self) -> Iterator[Unknown]`), "__next__": MethodMember(`(self) -> Unknown`)}
|
||||
reveal_protocol_interface(Iterator)
|
||||
|
||||
# error: [invalid-argument-type] "Invalid argument to `reveal_protocol_interface`: Only protocol classes can be passed to `reveal_protocol_interface`"
|
||||
|
|
@ -439,9 +439,9 @@ do not implement any special handling for generic aliases passed to the function
|
|||
reveal_type(get_protocol_members(SupportsAbs[int])) # revealed: frozenset[str]
|
||||
reveal_type(get_protocol_members(Iterator[int])) # revealed: frozenset[str]
|
||||
|
||||
# error: [revealed-type] "Revealed protocol interface: `{"__abs__": MethodMember(`(self) -> int`)}`"
|
||||
# revealed: {"__abs__": MethodMember(`(self) -> int`)}
|
||||
reveal_protocol_interface(SupportsAbs[int])
|
||||
# error: [revealed-type] "Revealed protocol interface: `{"__iter__": MethodMember(`(self) -> Iterator[int]`), "__next__": MethodMember(`(self) -> int`)}`"
|
||||
# revealed: {"__iter__": MethodMember(`(self) -> Iterator[int]`), "__next__": MethodMember(`(self) -> int`)}
|
||||
reveal_protocol_interface(Iterator[int])
|
||||
|
||||
class BaseProto(Protocol):
|
||||
|
|
@ -450,16 +450,16 @@ class BaseProto(Protocol):
|
|||
class SubProto(BaseProto, Protocol):
|
||||
def member(self) -> bool: ...
|
||||
|
||||
# error: [revealed-type] "Revealed protocol interface: `{"member": MethodMember(`(self) -> int`)}`"
|
||||
# revealed: {"member": MethodMember(`(self) -> int`)}
|
||||
reveal_protocol_interface(BaseProto)
|
||||
|
||||
# error: [revealed-type] "Revealed protocol interface: `{"member": MethodMember(`(self) -> bool`)}`"
|
||||
# revealed: {"member": MethodMember(`(self) -> bool`)}
|
||||
reveal_protocol_interface(SubProto)
|
||||
|
||||
class ProtoWithClassVar(Protocol):
|
||||
x: ClassVar[int]
|
||||
|
||||
# error: [revealed-type] "Revealed protocol interface: `{"x": AttributeMember(`int`; ClassVar)}`"
|
||||
# revealed: {"x": AttributeMember(`int`; ClassVar)}
|
||||
reveal_protocol_interface(ProtoWithClassVar)
|
||||
|
||||
class ProtocolWithDefault(Protocol):
|
||||
|
|
@ -468,7 +468,7 @@ class ProtocolWithDefault(Protocol):
|
|||
# We used to incorrectly report this as having an `x: Literal[0]` member;
|
||||
# declared types should take priority over inferred types for protocol interfaces!
|
||||
#
|
||||
# error: [revealed-type] "Revealed protocol interface: `{"x": AttributeMember(`int`)}`"
|
||||
# revealed: {"x": AttributeMember(`int`)}
|
||||
reveal_protocol_interface(ProtocolWithDefault)
|
||||
```
|
||||
|
||||
|
|
@ -2474,7 +2474,7 @@ class Foo(Protocol):
|
|||
from stub import Foo
|
||||
from ty_extensions import reveal_protocol_interface
|
||||
|
||||
# error: [revealed-type] "Revealed protocol interface: `{"x": AttributeMember(`int`; ClassVar)}`"
|
||||
# revealed: {"x": AttributeMember(`int`; ClassVar)}
|
||||
reveal_protocol_interface(Foo)
|
||||
```
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue