-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Expand file tree
/
Copy pathannotate-basic.test
More file actions
477 lines (347 loc) · 11.9 KB
/
annotate-basic.test
File metadata and controls
477 lines (347 loc) · 11.9 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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
[case testAnnotateNonNativeAttribute]
from typing import Any
def f1(x):
return x.foo # A: Get non-native attribute "foo".
def f2(x: Any) -> object:
return x.foo # A: Get non-native attribute "foo".
def f3(x):
x.bar = 1 # A: Set non-native attribute "bar".
class C:
foo: int
def method(self) -> int:
return self.foo
def good1(x: C) -> int:
return x.foo
[case testAnnotateMethod]
class C:
def method(self, x):
return x + "y" # A: Generic "+" operation.
[case testAnnotateGenericBinaryOperations]
def generic_add(x):
return x + 1 # A: Generic "+" operation.
def generic_sub(x):
return x - 1 # A: Generic "-" operation.
def generic_mul(x):
return x * 1 # A: Generic "*" operation.
def generic_div(x):
return x / 1 # A: Generic "/" operation.
def generic_floor_div(x):
return x // 1 # A: Generic "//" operation.
def generic_unary_plus(x):
return +x # A: Generic unary "+" operation.
def generic_unary_minus(x):
return -x # A: Generic unary "-" operation.
def native_int_ops(x: int, y: int) -> int:
a = x + 1 - y
return x * a // y
[case testAnnotateGenericBitwiseOperations]
def generic_and(x):
return x & 1 # A: Generic "&" operation.
def generic_or(x):
return x | 1 # A: Generic "|" operation.
def generic_xor(x):
return x ^ 1 # A: Generic "^" operation.
def generic_left_shift(x):
return x << 1 # A: Generic "<<" operation.
def generic_right_shift(x):
return x >> 1 # A: Generic ">>" operation.
def generic_invert(x):
return ~x # A: Generic "~" operation.
def native_int_ops(x: int, y: int) -> int:
a = (x & 1) << y
return (x | a) >> (y ^ 1)
[case testAnnotateGenericComparisonOperations]
def generic_eq(x, y):
return x == y # A: Generic comparison operation.
def generic_ne(x, y):
return x != y # A: Generic comparison operation.
def generic_lt(x, y):
return x < y # A: Generic comparison operation.
def generic_le(x, y):
return x <= y # A: Generic comparison operation.
def generic_gt(x, y):
return x > y # A: Generic comparison operation.
def generic_ge(x, y):
return x >= y # A: Generic comparison operation.
def int_comparisons(x: int, y: int) -> int:
if x == y:
return 0
if x < y:
return 1
if x > y:
return 2
return 3
[case testAnnotateTwoOperationsOnLine]
def f(x):
return x.foo + 1 # A: Get non-native attribute "foo". Generic "+" operation.
[case testAnnotateNonNativeMethod]
from typing import Any
def f1(x):
return x.foo() # A: Call non-native method "foo" (it may be defined in a non-native class, or decorated).
def f2(x: Any) -> None:
x.foo(1) # A: Call non-native method "foo" (it may be defined in a non-native class, or decorated).
x.foo(a=1) # A: Call non-native method "foo" (it may be defined in a non-native class, or decorated).
t = (1, 'x')
x.foo(*t) # A: Get non-native attribute "foo". Generic call operation.
d = {"a": 1}
x.foo(*d) # A: Get non-native attribute "foo". Generic call operation.
class C:
def foo(self) -> int:
return 0
def g(c: C) -> int:
return c.foo()
[case testAnnotateGlobalVariableAccess]
from typing import Final
import nonnative
x = 0
y: Final = 0
def read() -> int:
return x # A: Access global "x" through namespace dictionary (hint: access is faster if you can make it Final).
def assign(a: int) -> None:
global x
x = a # A: Access global "x" through namespace dictionary (hint: access is faster if you can make it Final).
def read_final() -> int:
return y
def read_nonnative() -> int:
return nonnative.z # A: Get non-native attribute "z".
[file nonnative.py]
z = 2
[case testAnnotateNestedFunction]
def f1() -> None:
def g() -> None: # A: A nested function object is allocated each time statement is executed. A module-level function would be faster.
pass
g()
def f2() -> int:
l = lambda: 1 # A: A new object is allocated for lambda each time it is evaluated. A module-level function would be faster.
return l()
[case testAnnotateGetSetItem]
from typing import List, Dict
def f1(x, y):
return x[y] # A: Generic indexing operation.
def f2(x, y, z):
x[y] = z # A: Generic indexed assignment.
def list_get_item(x: List[int], y: int) -> int:
return x[y]
def list_set_item(x: List[int], y: int) -> None:
x[y] = 5
def dict_get_item(d: Dict[str, str]) -> str:
return d['x']
def dict_set_item(d: Dict[str, str]) -> None:
d['x'] = 'y'
[case testAnnotateStrMethods]
def startswith(x: str) -> bool:
return x.startswith('foo')
def islower(x: str) -> bool:
return x.islower() # A: Call non-native method "islower" (it may be defined in a non-native class, or decorated).
[case testAnnotateSpecificStdlibFeatures]
import functools
import itertools
from functools import partial
from itertools import chain, groupby, islice
def f(x: int, y: int) -> None: pass
def use_partial1() -> None:
p = partial(f, 1) # A: "functools.partial" is inefficient in compiled code.
p(2)
def use_partial2() -> None:
p = functools.partial(f, 1) # A: "functools.partial" is inefficient in compiled code.
p(2)
def use_chain1() -> None:
for x in chain([1, 3], [4, 5]): # A: "itertools.chain" is inefficient in compiled code (hint: replace with for loops).
pass
def use_chain2() -> None:
for x in itertools.chain([1, 3], [4, 5]): # A: "itertools.chain" is inefficient in compiled code (hint: replace with for loops).
pass
def use_groupby1() -> None:
for a, b in groupby([('A', 'B')]): # A: "itertools.groupby" is inefficient in compiled code.
pass
def use_groupby2() -> None:
for a, b in itertools.groupby([('A', 'B')]): # A: "itertools.groupby" is inefficient in compiled code.
pass
def use_islice() -> None:
for x in islice([1, 2, 3], 1, 2): # A: "itertools.islice" is inefficient in compiled code (hint: replace with for loop over index range).
pass
[case testAnnotateGenericForLoop]
from typing import Iterable, Sequence, Iterator, List
def f1(a):
for x in a: # A: For loop uses generic operations (iterable has type "Any").
pass
def f2(a: Iterable[str]) -> None:
for x in a: # A: For loop uses generic operations (iterable has the abstract type "typing.Iterable").
pass
def f3(a: Sequence[str]) -> None:
for x in a: # A: For loop uses generic operations (iterable has the abstract type "typing.Sequence").
pass
def f4(a: Iterator[str]) -> None:
for x in a: # A: For loop uses generic operations (iterable has the abstract type "typing.Iterator").
pass
def good1(a: List[str]) -> None:
for x in a:
pass
class C:
def __iter__(self) -> Iterator[str]:
assert False
def good2(a: List[str]) -> None:
for x in a:
pass
[case testAnnotateGenericComprehensionOrGenerator]
from typing import List, Iterable
def f1(a):
return [x for x in a] # A: Comprehension or generator uses generic operations (iterable has type "Any").
def f2(a: Iterable[int]):
return {x for x in a} # A: Comprehension or generator uses generic operations (iterable has the abstract type "typing.Iterable").
def f3(a):
return {x: 1 for x in a} # A: Comprehension uses generic operations (iterable has type "Any").
def f4(a):
return (x for x in a) # A: Comprehension or generator uses generic operations (iterable has type "Any").
def good1(a: List[int]) -> List[int]:
return [x + 1 for x in a]
[case testAnnotateIsinstance]
from typing import Protocol, runtime_checkable, Union
@runtime_checkable
class P(Protocol):
def foo(self) -> None: ...
class C: pass
class D(C):
def bar(self) -> None: pass
def bad1(x: object) -> bool:
return isinstance(x, P) # A: Expensive isinstance() check against protocol "P".
def bad2(x: object) -> bool:
return isinstance(x, (str, P)) # A: Expensive isinstance() check against protocol "P".
def good1(x: C) -> bool:
if isinstance(x, D):
x.bar()
return isinstance(x, D)
def good2(x: Union[int, str]) -> int:
if isinstance(x, int):
return x + 1
else:
return int(x + "1")
[typing fixtures/typing-full.pyi]
[case testAnnotateDeepcopy]
from typing import Any
import copy
def f(x: Any) -> Any:
return copy.deepcopy(x) # A: "copy.deepcopy" tends to be slow. Make a shallow copy if possible.
[case testAnnotateContextManager]
from typing import Iterator
from contextlib import contextmanager
@contextmanager
def slow_ctx_manager() -> Iterator[None]:
yield
class FastCtxManager:
def __enter__(self) -> None: pass
def __exit__(self, a, b, c) -> None: pass
def f1(x) -> None:
with slow_ctx_manager(): # A: "slow_ctx_manager" uses @contextmanager, which is slow in compiled code. Use a native class with "__enter__" and "__exit__" methods instead.
x.foo # A: Get non-native attribute "foo".
def f2(x) -> None:
with FastCtxManager():
x.foo # A: Get non-native attribute "foo".
[case testAnnotateAvoidNoiseAtTopLevel]
from typing import Final
class C(object):
x = "s"
y: Final = 1
x = "s"
y: Final = 1
def f1() -> None:
x = object # A: Get non-native attribute "object".
[case testAnnotateCreateNonNativeInstance]
from typing import NamedTuple
from dataclasses import dataclass
from nonnative import C
def f1() -> None:
c = C() # A: Creating an instance of non-native class "C" is slow.
c.foo() # A: Call non-native method "foo" (it may be defined in a non-native class, or decorated).
class NT(NamedTuple):
x: int
y: str
def f2() -> int:
o = NT(1, "x") # A: Creating an instance of non-native class "NT" is slow.
return o.x
def f3() -> int:
o = NT(x=1, y="x") # A: Creating an instance of non-native class "NT" is slow.
a, b = o
return a
@dataclass
class D:
x: int
def f4() -> int:
o = D(1) # A: Class "D" is only partially native, and constructing an instance is slow.
return o.x
class Nat:
x: int
class Deriv(Nat):
def __init__(self, y: int) -> None:
self.y = y
def good1() -> int:
n = Nat()
d = Deriv(y=1)
return n.x + d.x + d.y
[file nonnative.py]
class C:
def foo(self) -> None: pass
[case testAnnotateGetAttrAndSetAttrBuiltins]
def f1(x, s: str):
return getattr("x", s) # A: Dynamic attribute lookup.
def f2(x, s: str):
setattr(x, s, None) # A: Dynamic attribute set.
[case testAnnotateSpecialAssignments]
from typing import TypeVar, NamedTuple, List, TypedDict, NewType
# Even though these are slow, we don't complain about them since there is generally
# no better way (and at module top level these are very unlikely to be bottlenecks)
A = List[int]
T = TypeVar("T", bound=List[int])
NT = NamedTuple("NT", [("x", List[int])])
TD = TypedDict("TD", {"x": List[int]})
New = NewType("New", List[int])
[typing fixtures/typing-full.pyi]
[case testAnnotateCallDecoratedNativeFunctionOrMethod]
from typing import TypeVar, Callable, Any
F = TypeVar("F", bound=Callable[..., Any])
def mydeco(f: F) -> F:
return f
@mydeco
def d(x: int) -> int:
return x
def f1() -> int:
return d(1) # A: Calling a decorated function ("d") is inefficient, even if it's native.
class C:
@mydeco
def d(self) -> None:
pass
def f2() -> None:
c = C()
c.d() # A: Call non-native method "d" (it may be defined in a non-native class, or decorated).
[case testAnnotateCallDifferentKindsOfMethods]
from abc import ABC, abstractmethod
class C:
@staticmethod
def s() -> None: ...
@classmethod
def c(cls) -> None: ...
@property
def p(self) -> int:
return 0
@property
def p2(self) -> int:
return 0
@p2.setter
def p2(self, x: int) -> None:
pass
def f1() -> int:
c = C()
c.s()
c.c()
c.p2 = 1
return c.p + c.p2
class A(ABC):
@abstractmethod
def m(self) -> int:
raise NotImplementedError # A: Get non-native attribute "NotImplementedError".
class D(A):
def m(self) -> int:
return 1
def f2() -> int:
d = D()
return d.m()