-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[red-knot] Add explicit TODO branches for many typing special forms a…
…nd qualifiers (#14936)
- Loading branch information
1 parent
5893090
commit 71239f2
Showing
6 changed files
with
466 additions
and
17 deletions.
There are no files selected for viewing
83 changes: 83 additions & 0 deletions
83
.../red_knot_python_semantic/resources/mdtest/annotations/stdlib_typing_aliases.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# Typing-module aliases to other stdlib classes | ||
|
||
The `typing` module has various aliases to other stdlib classes. These are a legacy feature, but | ||
still need to be supported by a type checker. | ||
|
||
## Currently unsupported | ||
|
||
Support for most of these symbols is currently a TODO: | ||
|
||
```py | ||
import typing | ||
|
||
def f( | ||
a: typing.List, | ||
b: typing.List[int], | ||
c: typing.Dict, | ||
d: typing.Dict[int, str], | ||
e: typing.DefaultDict, | ||
f: typing.DefaultDict[str, int], | ||
g: typing.Set, | ||
h: typing.Set[int], | ||
i: typing.FrozenSet, | ||
j: typing.FrozenSet[str], | ||
k: typing.OrderedDict, | ||
l: typing.OrderedDict[int, str], | ||
m: typing.Counter, | ||
n: typing.Counter[int], | ||
): | ||
reveal_type(a) # revealed: @Todo(Unsupported or invalid type in a type expression) | ||
reveal_type(b) # revealed: @Todo(typing.List alias) | ||
reveal_type(c) # revealed: @Todo(Unsupported or invalid type in a type expression) | ||
reveal_type(d) # revealed: @Todo(typing.Dict alias) | ||
reveal_type(e) # revealed: @Todo(Unsupported or invalid type in a type expression) | ||
reveal_type(f) # revealed: @Todo(typing.DefaultDict[] alias) | ||
reveal_type(g) # revealed: @Todo(Unsupported or invalid type in a type expression) | ||
reveal_type(h) # revealed: @Todo(typing.Set alias) | ||
reveal_type(i) # revealed: @Todo(Unsupported or invalid type in a type expression) | ||
reveal_type(j) # revealed: @Todo(typing.FrozenSet alias) | ||
reveal_type(k) # revealed: @Todo(Unsupported or invalid type in a type expression) | ||
reveal_type(l) # revealed: @Todo(typing.OrderedDict alias) | ||
reveal_type(m) # revealed: @Todo(Unsupported or invalid type in a type expression) | ||
reveal_type(n) # revealed: @Todo(typing.Counter[] alias) | ||
``` | ||
|
||
## Inheritance | ||
|
||
The aliases can be inherited from. Some of these are still partially or wholly TODOs. | ||
|
||
```py | ||
import typing | ||
|
||
class A(typing.Dict): ... | ||
|
||
# TODO: should have `Generic`, should not have `Unknown` | ||
reveal_type(A.__mro__) # revealed: tuple[Literal[A], Literal[dict], Unknown, Literal[object]] | ||
|
||
class B(typing.List): ... | ||
|
||
# TODO: should have `Generic`, should not have `Unknown` | ||
reveal_type(B.__mro__) # revealed: tuple[Literal[B], Literal[list], Unknown, Literal[object]] | ||
|
||
class C(typing.Set): ... | ||
|
||
# TODO: should have `Generic`, should not have `Unknown` | ||
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Literal[set], Unknown, Literal[object]] | ||
|
||
class D(typing.FrozenSet): ... | ||
|
||
# TODO: should have `Generic`, should not have `Unknown` | ||
reveal_type(D.__mro__) # revealed: tuple[Literal[D], Literal[frozenset], Unknown, Literal[object]] | ||
|
||
class E(typing.DefaultDict): ... | ||
|
||
reveal_type(E.__mro__) # revealed: tuple[Literal[E], @Todo(Support for more typing aliases as base classes), Literal[object]] | ||
|
||
class F(typing.OrderedDict): ... | ||
|
||
reveal_type(F.__mro__) # revealed: tuple[Literal[F], @Todo(Support for more typing aliases as base classes), Literal[object]] | ||
|
||
class G(typing.Counter): ... | ||
|
||
reveal_type(G.__mro__) # revealed: tuple[Literal[G], @Todo(Support for more typing aliases as base classes), Literal[object]] | ||
``` |
71 changes: 71 additions & 0 deletions
71
..._knot_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# Unsupported special forms | ||
|
||
## Not yet supported | ||
|
||
Several special forms are unsupported by red-knot currently. However, we also don't emit | ||
false-positive errors if you use one in an annotation: | ||
|
||
```py | ||
from typing_extensions import Self, TypeVarTuple, Unpack, TypeGuard, TypeIs, Concatenate, ParamSpec, TypeAlias, Callable, TypeVar | ||
|
||
P = ParamSpec("P") | ||
Ts = TypeVarTuple("Ts") | ||
R_co = TypeVar("R_co", covariant=True) | ||
|
||
Alias: TypeAlias = int | ||
|
||
def f(*args: Unpack[Ts]) -> tuple[Unpack[Ts]]: | ||
# TODO: should understand the annotation | ||
reveal_type(args) # revealed: tuple | ||
|
||
reveal_type(Alias) # revealed: @Todo(Unsupported or invalid type in a type expression) | ||
|
||
def g() -> TypeGuard[int]: ... | ||
def h() -> TypeIs[int]: ... | ||
def i(callback: Callable[Concatenate[int, P], R_co], *args: P.args, **kwargs: P.kwargs) -> R_co: | ||
# TODO: should understand the annotation | ||
reveal_type(args) # revealed: tuple | ||
|
||
# TODO: should understand the annotation | ||
reveal_type(kwargs) # revealed: dict | ||
|
||
return callback(42, *args, **kwargs) | ||
|
||
class Foo: | ||
def method(self, x: Self): | ||
reveal_type(x) # revealed: @Todo(Unsupported or invalid type in a type expression) | ||
``` | ||
|
||
## Inheritance | ||
|
||
You can't inherit from most of these. `typing.Callable` is an exception. | ||
|
||
```py | ||
from typing import Callable | ||
from typing_extensions import Self, Unpack, TypeGuard, TypeIs, Concatenate | ||
|
||
class A(Self): ... # error: [invalid-base] | ||
class B(Unpack): ... # error: [invalid-base] | ||
class C(TypeGuard): ... # error: [invalid-base] | ||
class D(TypeIs): ... # error: [invalid-base] | ||
class E(Concatenate): ... # error: [invalid-base] | ||
class F(Callable): ... | ||
|
||
reveal_type(F.__mro__) # revealed: tuple[Literal[F], @Todo(Support for more typing aliases as base classes), Literal[object]] | ||
``` | ||
|
||
## Subscriptability | ||
|
||
Some of these are not subscriptable: | ||
|
||
```py | ||
from typing_extensions import Self, TypeAlias | ||
|
||
X: TypeAlias[T] = int # error: [invalid-type-parameter] | ||
|
||
class Foo[T]: | ||
# error: [invalid-type-parameter] "Special form `typing.Self` expected no type parameter" | ||
# error: [invalid-type-parameter] "Special form `typing.Self` expected no type parameter" | ||
def method(self: Self[int]) -> Self[int]: | ||
reveal_type(self) # revealed: Unknown | ||
``` |
37 changes: 37 additions & 0 deletions
37
...not_python_semantic/resources/mdtest/annotations/unsupported_type_qualifiers.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Unsupported type qualifiers | ||
|
||
## Not yet supported | ||
|
||
Several type qualifiers are unsupported by red-knot currently. However, we also don't emit | ||
false-positive errors if you use one in an annotation: | ||
|
||
```py | ||
from typing_extensions import Final, ClassVar, Required, NotRequired, ReadOnly, TypedDict | ||
|
||
X: Final = 42 | ||
Y: Final[int] = 42 | ||
|
||
class Foo: | ||
A: ClassVar[int] = 42 | ||
|
||
# TODO: `TypedDict` is actually valid as a base | ||
# error: [invalid-base] | ||
class Bar(TypedDict): | ||
x: Required[int] | ||
y: NotRequired[str] | ||
z: ReadOnly[bytes] | ||
``` | ||
|
||
## Inheritance | ||
|
||
You can't inherit from a type qualifier. | ||
|
||
```py | ||
from typing_extensions import Final, ClassVar, Required, NotRequired, ReadOnly | ||
|
||
class A(Final): ... # error: [invalid-base] | ||
class B(ClassVar): ... # error: [invalid-base] | ||
class C(Required): ... # error: [invalid-base] | ||
class D(NotRequired): ... # error: [invalid-base] | ||
class E(ReadOnly): ... # error: [invalid-base] | ||
``` |
Oops, something went wrong.