-
Notifications
You must be signed in to change notification settings - Fork 293
Expand file tree
/
Copy pathannotations_generators.py
More file actions
195 lines (122 loc) · 3.88 KB
/
annotations_generators.py
File metadata and controls
195 lines (122 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
"""
Tests for annotating generators.
"""
# Specification: https://typing.readthedocs.io/en/latest/spec/annotations.html#annotating-generator-functions-and-coroutines
# The return type of generator functions can be annotated by the generic type
# Generator[yield_type, send_type, return_type] provided by typing.py module.
import asyncio
from typing import (
Any,
AsyncGenerator,
AsyncIterable,
AsyncIterator,
Awaitable,
Callable,
Coroutine,
Generator,
Iterable,
Iterator,
Protocol,
TypeVar,
assert_type,
)
T = TypeVar("T")
class A:
pass
class B:
def should_continue(self) -> bool:
return True
class C:
pass
def generator1() -> Generator[A, B, C]:
cont = B()
while cont.should_continue():
yield A()
return C()
def generator2() -> Generator[A, B, C]: # E: missing return
cont = B()
if cont.should_continue():
return False # E: incompatible return type
while cont.should_continue():
yield 3 # E: incompatible yield type
def generator3() -> Generator[A, int, Any]:
cont = B()
if cont.should_continue():
return 3
while cont.should_continue():
yield 3 # E: Incompatible yield type
def generator4() -> Iterable[A]:
yield A()
return True # E?: No return value expected
def generator5() -> Iterator[A]:
yield B() # E: incompatible yield type
def generator6() -> Generator[None, None, None]:
yield
def generator7() -> Iterator[dict[str, int]]:
yield {"": 0} # OK
def generator8() -> int: # E: incompatible return type
yield None # E?
return 0
async def generator9() -> int: # E: incompatible return type
yield None # E?
class IntIterator(Protocol):
def __next__(self, /) -> int:
...
def generator15() -> IntIterator: # OK
yield 0
class AsyncIntIterator(Protocol):
def __anext__(self, /) -> Awaitable[int]:
...
async def generator16() -> AsyncIntIterator: # OK
yield 0
def generator17() -> Iterator[A]: # OK
yield from generator17()
def generator18() -> Iterator[B]:
yield from generator17() # E: incompatible generator type
yield from [1] # E: incompatible generator type
def generator19() -> Generator[None, float, None]: # OK
x: float = yield
def generator20() -> Generator[None, int, None]: # OK
yield from generator19()
def generator21() -> Generator[None, int, None]:
x: float = yield
def generator22() -> Generator[None, str, None]:
yield from generator21() # E: incompatible send type
def generator23() -> Iterable[str]: # OK
return
yield "" # Unreachable
async def generator24() -> AsyncIterable[str]: # OK
return
yield "" # Unreachable
def generator25(ints1: list[int], ints2: list[int]) -> Generator[int, None, None]: # OK
yield from ints1
yield from ints2
async def get_data() -> list[int]:
await asyncio.sleep(1)
return [1, 2, 3]
async def generator26(nums: list[int]) -> AsyncGenerator[str, None]:
for n in nums:
await asyncio.sleep(1)
yield f"The number is {n}"
async def generator27() -> AsyncGenerator[str, None]:
data = await get_data()
v1 = generator26(data)
assert_type(v1, AsyncGenerator[str, None])
return v1
async def generator28() -> AsyncIterator[str]:
data = await get_data()
v1 = generator26(data)
assert_type(v1, AsyncGenerator[str, None])
return v1
async def generator29() -> AsyncIterator[int]:
raise NotImplementedError
# Don't use assert_type here because some type checkers infer
# the narrower type types.CoroutineType rather than typing.Coroutine
# in this case.
v1: Callable[[], Coroutine[Any, Any, AsyncIterator[int]]] = generator29
async def generator30() -> AsyncIterator[int]:
raise NotImplementedError
yield
async def uses_generator30() -> None:
async for x in generator30():
assert_type(x, int)