blob: 48b9bd3a0bb7030fd66e37edbcebd86d5ca11f2f [file] [log] [blame] [edit]
-- Test cases for type checking mypy programs using full stubs and running
-- using CPython.
--
-- These are mostly regression tests -- no attempt is made to make these
-- complete.
--
-- This test file check Asyncio and yield from interaction
[case testImportAsyncio]
import asyncio
print('Imported')
[out]
Imported
[case testSimpleCoroutineSleep]
from typing import Any, Generator
import asyncio
from asyncio import Future
@asyncio.coroutine
def greet_every_two_seconds() -> 'Generator[Any, None, None]':
n = 0
while n < 5:
print('Prev', n)
yield from asyncio.sleep(0.1)
print('After', n)
n += 1
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(greet_every_two_seconds())
finally:
loop.close()
[out]
Prev 0
After 0
Prev 1
After 1
Prev 2
After 2
Prev 3
After 3
Prev 4
After 4
[case testCoroutineCallingOtherCoroutine]
from typing import Generator, Any
import asyncio
from asyncio import Future
@asyncio.coroutine
def compute(x: int, y: int) -> 'Generator[Any, None, int]':
print("Compute %s + %s ..." % (x, y))
yield from asyncio.sleep(0.1)
return x + y # Here the int is wrapped in Future[int]
@asyncio.coroutine
def print_sum(x: int, y: int) -> 'Generator[Any, None, None]':
result = yield from compute(x, y) # The type of result will be int (is extracted from Future[int]
print("%s + %s = %s" % (x, y, result))
loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()
[out]
Compute 1 + 2 ...
1 + 2 = 3
[case testCoroutineChangingFuture]
from typing import Generator, Any
import asyncio
from asyncio import Future
@asyncio.coroutine
def slow_operation(future: 'Future[str]') -> 'Generator[Any, None, None]':
yield from asyncio.sleep(0.1)
future.set_result('Future is done!')
loop = asyncio.get_event_loop()
future = asyncio.Future() # type: Future[str]
asyncio.Task(slow_operation(future))
loop.run_until_complete(future)
print(future.result())
loop.close()
[out]
Future is done!
[case testFunctionAssignedAsCallback]
import typing
from typing import Generator, Any
import asyncio
from asyncio import Future, AbstractEventLoop
@asyncio.coroutine
def slow_operation(future: 'Future[str]') -> 'Generator[Any, None, None]':
yield from asyncio.sleep(1)
future.set_result('Callback works!')
def got_result(future: 'Future[str]') -> None:
print(future.result())
loop.stop()
loop = asyncio.get_event_loop() # type: AbstractEventLoop
future = asyncio.Future() # type: Future[str]
asyncio.Task(slow_operation(future)) # Here create a task with the function. (The Task need a Future[T] as first argument)
future.add_done_callback(got_result) # and assign the callback to the future
try:
loop.run_forever()
finally:
loop.close()
[out]
Callback works!
[case testMultipleTasks]
import typing
from typing import Generator, Any
import asyncio
from asyncio import Task, Future
@asyncio.coroutine
def factorial(name, number) -> 'Generator[Any, None, None]':
f = 1
for i in range(2, number+1):
print("Task %s: Compute factorial(%s)..." % (name, i))
yield from asyncio.sleep(0.1)
f *= i
print("Task %s: factorial(%s) = %s" % (name, number, f))
loop = asyncio.get_event_loop()
tasks = [
asyncio.Task(factorial("A", 2)),
asyncio.Task(factorial("B", 3)),
asyncio.Task(factorial("C", 4))]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
[out]
Task A: Compute factorial(2)...
Task B: Compute factorial(2)...
Task C: Compute factorial(2)...
Task A: factorial(2) = 2
Task B: Compute factorial(3)...
Task C: Compute factorial(3)...
Task B: factorial(3) = 6
Task C: Compute factorial(4)...
Task C: factorial(4) = 24
[case testConcatenatedCoroutines]
import typing
from typing import Generator, Any
import asyncio
from asyncio import Future
@asyncio.coroutine
def h4() -> 'Generator[Any, None, int]':
x = yield from future
return x
@asyncio.coroutine
def h3() -> 'Generator[Any, None, int]':
x = yield from h4()
print("h3: %s" % x)
return x
@asyncio.coroutine
def h2() -> 'Generator[Any, None, int]':
x = yield from h3()
print("h2: %s" % x)
return x
@asyncio.coroutine
def h() -> 'Generator[Any, None, None]':
x = yield from h2()
print("h: %s" % x)
loop = asyncio.get_event_loop()
future = asyncio.Future() # type: Future[int]
future.set_result(42)
loop.run_until_complete(h())
print("Outside %s" % future.result())
loop.close()
[out]
h3: 42
h2: 42
h: 42
Outside 42
[case testConcatenatedCoroutinesReturningFutures]
import typing
from typing import Generator, Any
import asyncio
from asyncio import Future
@asyncio.coroutine
def h4() -> 'Generator[Any, None, Future[int]]':
yield from asyncio.sleep(0.1)
f = asyncio.Future() #type: Future[int]
return f
@asyncio.coroutine
def h3() -> 'Generator[Any, None, Future[Future[int]]]':
x = yield from h4()
x.set_result(42)
f = asyncio.Future() #type: Future[Future[int]]
f.set_result(x)
return f
@asyncio.coroutine
def h() -> 'Generator[Any, None, None]':
print("Before")
x = yield from h3()
y = yield from x
z = yield from y
print(z)
def normalize(future):
# The str conversion seems inconsistent; not sure exactly why. Normalize
# the result.
return str(future).replace('<Future finished ', 'Future<')
print(normalize(y))
print(normalize(x))
loop = asyncio.get_event_loop()
loop.run_until_complete(h())
loop.close()
[out]
Before
42
Future<result=42>
Future<result=Future<result=42>>
[case testCoroutineWithOwnClass]
import typing
from typing import Generator, Any
import asyncio
from asyncio import Future
class A:
def __init__(self, x: int) -> None:
self.x = x
@asyncio.coroutine
def h() -> 'Generator[Any, None, None]':
x = yield from future
print("h: %s" % x.x)
loop = asyncio.get_event_loop()
future = asyncio.Future() # type: Future[A]
future.set_result(A(42))
loop.run_until_complete(h())
print("Outside %s" % future.result().x)
loop.close()
[out]
h: 42
Outside 42
-- Errors
[case testErrorAssigningCoroutineThatDontReturn]
from typing import Generator, Any
import asyncio
from asyncio import Future
@asyncio.coroutine
def greet() -> 'Generator[Any, None, None]':
yield from asyncio.sleep(0.2)
print('Hello World')
@asyncio.coroutine
def test() -> 'Generator[Any, None, None]':
yield from greet()
x = yield from greet() # Error
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(test())
finally:
loop.close()
[out]
_program.py:13: error: Function does not return a value
[case testErrorReturnIsNotTheSameType]
from typing import Generator, Any
import asyncio
from asyncio import Future
@asyncio.coroutine
def compute(x: int, y: int) -> 'Generator[Any, None, int]':
print("Compute %s + %s ..." % (x, y))
yield from asyncio.sleep(0.1)
return str(x + y) # Error
@asyncio.coroutine
def print_sum(x: int, y: int) -> 'Generator[Any, None, None]':
result = yield from compute(x, y)
print("%s + %s = %s" % (x, y, result))
loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()
[out]
_program.py:9: error: Incompatible return value type (got "str", expected "int")
[case testErrorSetFutureDifferentInternalType]
from typing import Generator, Any
import asyncio
from asyncio import Future
@asyncio.coroutine
def slow_operation(future: 'Future[str]') -> 'Generator[Any, None, None]':
yield from asyncio.sleep(1)
future.set_result(42) # Error
loop = asyncio.get_event_loop()
future = asyncio.Future() # type: Future[str]
asyncio.Task(slow_operation(future))
loop.run_until_complete(future)
print(future.result())
loop.close()
[out]
_program.py:8: error: Argument 1 to "set_result" of "Future" has incompatible type "int"; expected "str"
[case testErrorUsingDifferentFutureType]
from typing import Any, Generator
import asyncio
from asyncio import Future
@asyncio.coroutine
def slow_operation(future: 'Future[int]') -> 'Generator[Any, None, None]':
yield from asyncio.sleep(1)
future.set_result(42)
loop = asyncio.get_event_loop()
future = asyncio.Future() # type: Future[str]
asyncio.Task(slow_operation(future)) # Error
loop.run_until_complete(future)
print(future.result())
loop.close()
[out]
_program.py:12: error: Argument 1 to "slow_operation" has incompatible type "Future[str]"; expected "Future[int]"
[case testErrorUsingDifferentFutureTypeAndSetFutureDifferentInternalType]
from typing import Generator, Any
import asyncio
from asyncio import Future
asyncio.coroutine
def slow_operation(future: 'Future[int]') -> 'Generator[Any, None, None]':
yield from asyncio.sleep(1)
future.set_result('42') #Try to set an str as result to a Future[int]
loop = asyncio.get_event_loop()
future = asyncio.Future() # type: Future[str]
asyncio.Task(slow_operation(future)) # Error
loop.run_until_complete(future)
print(future.result())
loop.close()
[out]
_program.py:8: error: Argument 1 to "set_result" of "Future" has incompatible type "str"; expected "int"
_program.py:12: error: Argument 1 to "slow_operation" has incompatible type "Future[str]"; expected "Future[int]"
[case testErrorSettingCallbackWithDifferentFutureType]
import typing
from typing import Generator, Any
import asyncio
from asyncio import Future, AbstractEventLoop
@asyncio.coroutine
def slow_operation(future: 'Future[str]') -> 'Generator[Any, None, None]':
yield from asyncio.sleep(1)
future.set_result('Future is done!')
def got_result(future: 'Future[int]') -> None:
print(future.result())
loop.stop()
loop = asyncio.get_event_loop() # type: AbstractEventLoop
future = asyncio.Future() # type: Future[str]
asyncio.Task(slow_operation(future))
future.add_done_callback(got_result) # Error
try:
loop.run_forever()
finally:
loop.close()
[out]
_program.py:18: error: Argument 1 to "add_done_callback" of "Future" has incompatible type "Callable[[Future[int]], None]"; expected "Callable[[Future[str]], Any]"
[case testErrorOneMoreFutureInReturnType]
import typing
from typing import Any, Generator
import asyncio
from asyncio import Future
@asyncio.coroutine
def h4() -> 'Generator[Any, None, Future[int]]':
yield from asyncio.sleep(1)
f = asyncio.Future() #type: Future[int]
return f
@asyncio.coroutine
def h3() -> 'Generator[Any, None, Future[Future[Future[int]]]]':
x = yield from h4()
x.set_result(42)
f = asyncio.Future() #type: Future[Future[int]]
f.set_result(x)
return f
@asyncio.coroutine
def h() -> 'Generator[Any, None, None]':
print("Before")
x = yield from h3()
y = yield from x
z = yield from y
print(z)
print(y)
print(x)
loop = asyncio.get_event_loop()
loop.run_until_complete(h())
loop.close()
[out]
_program.py:18: error: Incompatible return value type (got "Future[Future[int]]", expected "Future[Future[Future[int]]]")
[case testErrorOneLessFutureInReturnType]
import typing
from typing import Any, Generator
import asyncio
from asyncio import Future
@asyncio.coroutine
def h4() -> 'Generator[Any, None, Future[int]]':
yield from asyncio.sleep(1)
f = asyncio.Future() #type: Future[int]
return f
@asyncio.coroutine
def h3() -> 'Generator[Any, None, Future[int]]':
x = yield from h4()
x.set_result(42)
f = asyncio.Future() #type: Future[Future[int]]
f.set_result(x)
return f
@asyncio.coroutine
def h() -> 'Generator[Any, None, None]':
print("Before")
x = yield from h3()
y = yield from x
print(y)
print(x)
loop = asyncio.get_event_loop()
loop.run_until_complete(h())
loop.close()
[out]
_program.py:18: error: Incompatible return value type (got "Future[Future[int]]", expected "Future[int]")
[case testErrorAssignmentDifferentType]
import typing
from typing import Generator, Any
import asyncio
from asyncio import Future
class A:
def __init__(self, x: int) -> None:
self.x = x
class B:
def __init__(self, x: int) -> None:
self.x = x
@asyncio.coroutine
def h() -> 'Generator[Any, None, None]':
x = yield from future # type: B # Error
print("h: %s" % x.x)
loop = asyncio.get_event_loop()
future = asyncio.Future() # type: Future[A]
future.set_result(A(42))
loop.run_until_complete(h())
loop.close()
[out]
_program.py:16: error: Incompatible types in assignment (expression has type "A", variable has type "B")
[case testForwardRefToBadAsyncShouldNotCrash_newsemanal]
from typing import TypeVar
import asyncio
T = TypeVar('T')
P = whatever # type: ignore
def test() -> None:
reveal_type(bad)
bad(0)
@asyncio.coroutine
def bad(arg: P) -> T:
pass
[out]
_program.py:8: note: Revealed type is 'def [T] (arg: P?) -> T`-1'
_program.py:12: error: Variable "_testForwardRefToBadAsyncShouldNotCrash_newsemanal.P" is not valid as a type
_program.py:12: note: See https://mypy.readthedocs.io/en/latest/common_issues.html#variables-vs-type-aliases