From e171aacd88a28bd044c2055efdcbe0154191af73 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Thu, 1 Jun 2017 12:50:50 +0100 Subject: [PATCH] Speed up tests by simplifying the stub for typing Don't include async types in the default `typing` stub used in tests since it's only needed for a small fraction of test cases. Make it possible to write `[typing fixtures/typing-full.pyi]` in tests to use a more complete complete stub that includes the async types. In the future we can move additional rarely used features to this stub. Also replace the definition of `NewType` in the test fixtures with a simpler one to speed things up slightly. These changes improved the running time of `pytest mypy` by about 35% for me (on macOS). --- mypy/test/data.py | 9 +- test-data/unit/README.md | 9 +- test-data/unit/check-async-await.test | 44 +++++++-- test-data/unit/check-class-namedtuple.test | 1 + test-data/unit/fixtures/typing-full.pyi | 110 +++++++++++++++++++++ test-data/unit/lib-stub/typing.pyi | 38 +------ 6 files changed, 163 insertions(+), 48 deletions(-) create mode 100644 test-data/unit/fixtures/typing-full.pyi diff --git a/mypy/test/data.py b/mypy/test/data.py index d5051dc653fd..ccee92eac276 100644 --- a/mypy/test/data.py +++ b/mypy/test/data.py @@ -68,7 +68,7 @@ def parse_test_cases( elif p[i].id == 'outfile': output_files.append(file_entry) elif p[i].id in ('builtins', 'builtins_py2'): - # Use a custom source file for the std module. + # Use an alternative stub file for the builtins module. arg = p[i].arg assert arg is not None mpath = join(os.path.dirname(path), arg) @@ -79,6 +79,13 @@ def parse_test_cases( fnam = '__builtin__.pyi' with open(mpath) as f: files.append((join(base_path, fnam), f.read())) + elif p[i].id == 'typing': + # Use an alternative stub file for the typing module. + arg = p[i].arg + assert arg is not None + src_path = join(os.path.dirname(path), arg) + with open(src_path) as f: + files.append((join(base_path, 'typing.pyi'), f.read())) elif re.match(r'stale[0-9]*$', p[i].id): if p[i].id == 'stale': passnum = 1 diff --git a/test-data/unit/README.md b/test-data/unit/README.md index baa62784c7b5..693e7f4d8719 100644 --- a/test-data/unit/README.md +++ b/test-data/unit/README.md @@ -61,9 +61,12 @@ Where the stubs for builtins come from for a given test: - The builtins used by default in unit tests live in `test-data/unit/lib-stub`. -- Individual test cases can override the stubs by using `[builtins fixtures/foo.pyi]`; - this targets files in `test-data/unit/fixtures`. Feel free to modify existing files - there or create new ones as you deem fit. +- Individual test cases can override the builtins stubs by using + `[builtins fixtures/foo.pyi]`; this targets files in `test-data/unit/fixtures`. + Feel free to modify existing files there or create new ones as you deem fit. + +- Test cases can also use `[typing fixtures/typing-full.pyi]` to use a more + complete stub for `typing` that contains the async types, among other things. - Feel free to add additional stubs to that `fixtures` directory, but generally don't expand files in `lib-stub` without first discussing the diff --git a/test-data/unit/check-async-await.test b/test-data/unit/check-async-await.test index 672bf2b408b8..f8ac01d8c830 100644 --- a/test-data/unit/check-async-await.test +++ b/test-data/unit/check-async-await.test @@ -6,6 +6,7 @@ async def f() -> int: pass [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [case testAsyncDefReturn] @@ -13,12 +14,14 @@ async def f() -> int: return 0 reveal_type(f()) # E: Revealed type is 'typing.Awaitable[builtins.int]' [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [case testAsyncDefMissingReturn] # flags: --warn-no-return async def f() -> int: make_this_not_trivial = 1 [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [out] main:2: error: Missing return statement @@ -28,6 +31,7 @@ async def f() -> int: make_this_not_trivial = 1 return [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [out] main:4: error: Return value expected @@ -38,6 +42,7 @@ async def f() -> int: reveal_type(x) # E: Revealed type is 'builtins.int*' return x [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [out] [case testAwaitDefaultContext] @@ -48,6 +53,7 @@ async def f(x: T) -> T: y = await f(x) reveal_type(y) return y +[typing fixtures/typing-full.pyi] [out] main:6: error: Revealed type is 'T`-1' @@ -59,6 +65,7 @@ async def f(x: T) -> T: y = await f(x) # type: Any reveal_type(y) return y +[typing fixtures/typing-full.pyi] [out] main:6: error: Revealed type is 'Any' @@ -70,6 +77,7 @@ async def f(x: T) -> T: y = await f(x) # type: int reveal_type(y) return x +[typing fixtures/typing-full.pyi] [out] main:5: error: Argument 1 to "f" has incompatible type "T"; expected "int" main:6: error: Revealed type is 'builtins.int' @@ -83,6 +91,7 @@ def g() -> Generator[int, None, str]: async def f() -> int: x = await g() return x +[typing fixtures/typing-full.pyi] [out] main:7: error: Incompatible types in await (actual type Generator[int, None, str], expected type Awaitable[Any]) @@ -94,6 +103,7 @@ def g() -> Iterator[Any]: async def f() -> int: x = await g() return x +[typing fixtures/typing-full.pyi] [out] main:6: error: Incompatible types in await (actual type Iterator[Any], expected type Awaitable[Any]) @@ -105,6 +115,7 @@ async def f() -> int: x = await g() return x [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [out] main:5: error: Incompatible types in await (actual type "int", expected type Awaitable[Any]) @@ -116,6 +127,7 @@ async def f() -> str: x = await g() # type: str return x [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [out] main:5: error: Incompatible types in assignment (expression has type "int", variable has type "str") @@ -127,6 +139,7 @@ async def f() -> str: x = await g() return x [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [out] main:6: error: Incompatible return value type (got "int", expected "str") @@ -139,7 +152,7 @@ async def f() -> None: async for x in C(): reveal_type(x) # E: Revealed type is 'builtins.int*' [builtins fixtures/async_await.pyi] -[out] +[typing fixtures/typing-full.pyi] [case testAsyncForError] @@ -148,6 +161,7 @@ async def f() -> None: async for x in [1]: pass [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [out] main:4: error: AsyncIterable expected main:4: error: List[int] has no attribute "__aiter__" @@ -167,6 +181,7 @@ async def f() -> None: async for z in C(): # type: Union[int, str] reveal_type(z) # E: Revealed type is 'Union[builtins.int, builtins.str]' [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [case testAsyncForComprehension] # flags: --fast-parser --python-version 3.6 @@ -206,6 +221,7 @@ async def generatorexp(obj: Iterable[int]): reveal_type(lst2) # E: Revealed type is 'typing.AsyncIterator[builtins.int*]' [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [case testAsyncForComprehensionErrors] # flags: --fast-parser --python-version 3.6 @@ -240,6 +256,7 @@ main:20: error: Iterable[int] has no attribute "__aiter__"; maybe "__iter__"? main:21: error: Iterable expected main:21: error: asyncify[int] has no attribute "__iter__"; maybe "__aiter__"? [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [case testAsyncWith] @@ -250,6 +267,7 @@ async def f() -> None: async with C() as x: reveal_type(x) # E: Revealed type is 'builtins.int*' [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [case testAsyncWithError] @@ -261,6 +279,7 @@ async def f() -> None: async with C() as x: pass [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [out] main:6: error: "C" has no attribute "__aenter__"; maybe "__enter__"? main:6: error: "C" has no attribute "__aexit__"; maybe "__exit__"? @@ -274,7 +293,7 @@ async def f() -> None: async with C() as x: # E: Incompatible types in "async with" for __aenter__ (actual type "int", expected type Awaitable[Any]) pass [builtins fixtures/async_await.pyi] -[out] +[typing fixtures/typing-full.pyi] [case testAsyncWithErrorBadAenter2] @@ -285,7 +304,7 @@ async def f() -> None: async with C() as x: # E: None has no attribute "__await__" pass [builtins fixtures/async_await.pyi] -[out] +[typing fixtures/typing-full.pyi] [case testAsyncWithErrorBadAexit] @@ -296,7 +315,7 @@ async def f() -> None: async with C() as x: # E: Incompatible types in "async with" for __aexit__ (actual type "int", expected type Awaitable[Any]) pass [builtins fixtures/async_await.pyi] -[out] +[typing fixtures/typing-full.pyi] [case testAsyncWithErrorBadAexit2] @@ -307,7 +326,7 @@ async def f() -> None: async with C() as x: # E: None has no attribute "__await__" pass [builtins fixtures/async_await.pyi] -[out] +[typing fixtures/typing-full.pyi] [case testAsyncWithTypeComments] @@ -324,6 +343,7 @@ async def f() -> None: async with C() as a: # type: int, int # E: Invalid tuple literal type pass [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [case testNoYieldInAsyncDef] # flags: --python-version 3.5 @@ -361,6 +381,7 @@ def g() -> Generator[Any, None, str]: x = yield from f() return x [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [out] main:6: error: "yield from" can't be applied to Awaitable[str] @@ -389,7 +410,7 @@ async def main() -> None: async for z in I(): reveal_type(z) # E: Revealed type is 'builtins.int' [builtins fixtures/async_await.pyi] -[out] +[typing fixtures/typing-full.pyi] [case testYieldTypeCheckInDecoratedCoroutine] @@ -405,7 +426,7 @@ def f() -> Generator[int, str, int]: else: return '' # E: Incompatible return value type (got "str", expected "int") [builtins fixtures/async_await.pyi] -[out] +[typing fixtures/typing-full.pyi] -- Async generators (PEP 525), some test cases adapted from the PEP text -- --------------------------------------------------------------------- @@ -436,6 +457,7 @@ async def wrong_return() -> Generator[int, None, None]: # E: The return type of yield 3 [builtins fixtures/dict.pyi] +[typing fixtures/typing-full.pyi] [case testAsyncGeneratorReturnIterator] # flags: --python-version 3.6 @@ -451,6 +473,7 @@ async def use_gen() -> None: reveal_type(item) # E: Revealed type is 'builtins.int*' [builtins fixtures/dict.pyi] +[typing fixtures/typing-full.pyi] [case testAsyncGeneratorManualIter] # flags: --python-version 3.6 @@ -468,6 +491,7 @@ async def user() -> None: reveal_type(await gen.__anext__()) # E: Revealed type is 'builtins.int*' [builtins fixtures/dict.pyi] +[typing fixtures/typing-full.pyi] [case testAsyncGeneratorAsend] # flags: --fast-parser --python-version 3.6 @@ -488,6 +512,7 @@ async def h() -> None: reveal_type(await g.asend('hello')) # E: Revealed type is 'builtins.int*' [builtins fixtures/dict.pyi] +[typing fixtures/typing-full.pyi] [case testAsyncGeneratorAthrow] # flags: --fast-parser --python-version 3.6 @@ -506,6 +531,7 @@ async def h() -> None: reveal_type(await g.athrow(BaseException)) # E: Revealed type is 'builtins.str*' [builtins fixtures/dict.pyi] +[typing fixtures/typing-full.pyi] [case testAsyncGeneratorNoSyncIteration] # flags: --fast-parser --python-version 3.6 @@ -520,6 +546,7 @@ def h() -> None: pass [builtins fixtures/dict.pyi] +[typing fixtures/typing-full.pyi] [out] main:9: error: Iterable expected @@ -536,6 +563,7 @@ async def gen() -> AsyncGenerator[int, None]: yield from f() # E: 'yield from' in async function [builtins fixtures/dict.pyi] +[typing fixtures/typing-full.pyi] [case testAsyncGeneratorNoReturnWithValue] # flags: --fast-parser --python-version 3.6 @@ -557,6 +585,7 @@ async def return_f() -> AsyncGenerator[int, None]: return f() # E: 'return' with value in async generator is not allowed [builtins fixtures/dict.pyi] +[typing fixtures/typing-full.pyi] -- The full matrix of coroutine compatibility -- ------------------------------------------ @@ -644,4 +673,5 @@ async def decorated_host_coroutine() -> None: x = await other_coroutine() [builtins fixtures/async_await.pyi] +[typing fixtures/typing-full.pyi] [out] diff --git a/test-data/unit/check-class-namedtuple.test b/test-data/unit/check-class-namedtuple.test index 7a81adb0a672..ffb727972c90 100644 --- a/test-data/unit/check-class-namedtuple.test +++ b/test-data/unit/check-class-namedtuple.test @@ -507,6 +507,7 @@ reveal_type(XMeth(1).asyncdouble()) # E: Revealed type is 'typing.Awaitable[bui reveal_type(XMeth(42).x) # E: Revealed type is 'builtins.int' reveal_type(XRepr(42).__str__()) # E: Revealed type is 'builtins.str' reveal_type(XRepr(1, 2).__add__(XRepr(3))) # E: Revealed type is 'builtins.int' +[typing fixtures/typing-full.pyi] [case testNewNamedTupleOverloading] from typing import NamedTuple, overload diff --git a/test-data/unit/fixtures/typing-full.pyi b/test-data/unit/fixtures/typing-full.pyi new file mode 100644 index 000000000000..87b51cd0d340 --- /dev/null +++ b/test-data/unit/fixtures/typing-full.pyi @@ -0,0 +1,110 @@ +# More complete stub for typing module. +# +# Use [typing fixtures/typing-full.pyi] to use this instead of lib-stub/typing.pyi +# in a particular test case. +# +# Many of the definitions have special handling in the type checker, so they +# can just be initialized to anything. + +from abc import abstractmethod + +class GenericMeta(type): pass + +cast = 0 +overload = 0 +Any = 0 +Union = 0 +Optional = 0 +TypeVar = 0 +Generic = 0 +Tuple = 0 +Callable = 0 +_promote = 0 +NamedTuple = 0 +Type = 0 +no_type_check = 0 +ClassVar = 0 +NoReturn = 0 +NewType = 0 + +# Type aliases. +List = 0 +Dict = 0 +Set = 0 + +T = TypeVar('T') +U = TypeVar('U') +V = TypeVar('V') +S = TypeVar('S') + +class Container(Generic[T]): + @abstractmethod + # Use int because bool isn't in the default test builtins + def __contains__(self, arg: T) -> int: pass + +class Sized: + @abstractmethod + def __len__(self) -> int: pass + +class Iterable(Generic[T]): + @abstractmethod + def __iter__(self) -> 'Iterator[T]': pass + +class Iterator(Iterable[T], Generic[T]): + @abstractmethod + def __next__(self) -> T: pass + +class Generator(Iterator[T], Generic[T, U, V]): + @abstractmethod + def send(self, value: U) -> T: pass + + @abstractmethod + def throw(self, typ: Any, val: Any=None, tb=None) -> None: pass + + @abstractmethod + def close(self) -> None: pass + + @abstractmethod + def __iter__(self) -> 'Generator[T, U, V]': pass + +class AsyncGenerator(AsyncIterator[T], Generic[T, U]): + @abstractmethod + def __anext__(self) -> Awaitable[T]: pass + + @abstractmethod + def asend(self, value: U) -> Awaitable[T]: pass + + @abstractmethod + def athrow(self, typ: Any, val: Any=None, tb: Any=None) -> Awaitable[T]: pass + + @abstractmethod + def aclose(self) -> Awaitable[T]: pass + + @abstractmethod + def __aiter__(self) -> 'AsyncGenerator[T, U]': pass + +class Awaitable(Generic[T]): + @abstractmethod + def __await__(self) -> Generator[Any, Any, T]: pass + +class AwaitableGenerator(Generator[T, U, V], Awaitable[V], Generic[T, U, V, S]): + pass + +class AsyncIterable(Generic[T]): + @abstractmethod + def __aiter__(self) -> 'AsyncIterator[T]': pass + +class AsyncIterator(AsyncIterable[T], Generic[T]): + def __aiter__(self) -> 'AsyncIterator[T]': return self + @abstractmethod + def __anext__(self) -> Awaitable[T]: pass + +class Sequence(Iterable[T], Generic[T]): + @abstractmethod + def __getitem__(self, n: Any) -> T: pass + +class Mapping(Generic[T, U]): pass + +class MutableMapping(Generic[T, U]): pass + +TYPE_CHECKING = 1 diff --git a/test-data/unit/lib-stub/typing.pyi b/test-data/unit/lib-stub/typing.pyi index 754c32c8d23e..58b28836bf69 100644 --- a/test-data/unit/lib-stub/typing.pyi +++ b/test-data/unit/lib-stub/typing.pyi @@ -20,6 +20,7 @@ Type = 0 no_type_check = 0 ClassVar = 0 NoReturn = 0 +NewType = 0 # Type aliases. List = 0 @@ -61,38 +62,6 @@ class Generator(Iterator[T], Generic[T, U, V]): @abstractmethod def __iter__(self) -> 'Generator[T, U, V]': pass -class AsyncGenerator(AsyncIterator[T], Generic[T, U]): - @abstractmethod - def __anext__(self) -> Awaitable[T]: pass - - @abstractmethod - def asend(self, value: U) -> Awaitable[T]: pass - - @abstractmethod - def athrow(self, typ: Any, val: Any=None, tb: Any=None) -> Awaitable[T]: pass - - @abstractmethod - def aclose(self) -> Awaitable[T]: pass - - @abstractmethod - def __aiter__(self) -> 'AsyncGenerator[T, U]': pass - -class Awaitable(Generic[T]): - @abstractmethod - def __await__(self) -> Generator[Any, Any, T]: pass - -class AwaitableGenerator(Generator[T, U, V], Awaitable[V], Generic[T, U, V, S]): - pass - -class AsyncIterable(Generic[T]): - @abstractmethod - def __aiter__(self) -> 'AsyncIterator[T]': pass - -class AsyncIterator(AsyncIterable[T], Generic[T]): - def __aiter__(self) -> 'AsyncIterator[T]': return self - @abstractmethod - def __anext__(self) -> Awaitable[T]: pass - class Sequence(Iterable[T], Generic[T]): @abstractmethod def __getitem__(self, n: Any) -> T: pass @@ -101,9 +70,4 @@ class Mapping(Generic[T, U]): pass class MutableMapping(Generic[T, U]): pass -def NewType(name: str, tp: Type[T]) -> Callable[[T], T]: - def new_type(x): - return x - return new_type - TYPE_CHECKING = 1