[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()