Skip to content

Commit 483acc9

Browse files
author
Guido van Rossum
committed
Fledgeling async with support.
1 parent 9677fb6 commit 483acc9

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

mypy/checker.py

+26-5
Original file line numberDiff line numberDiff line change
@@ -1687,10 +1687,12 @@ def analyze_async_iterable_item_type(self, expr: Node) -> Type:
16871687
awaitable = echk.check_call(method, [], [], expr)[0]
16881688
method = echk.analyze_external_member_access('__await__', awaitable, expr)
16891689
generator = echk.check_call(method, [], [], expr)[0]
1690+
# XXX TODO Use get_generator_return_type()?
16901691
if (isinstance(generator, Instance) and len(generator.args) == 3
16911692
and generator.type.fullname() == 'typing.Generator'):
16921693
return generator.args[2]
16931694
else:
1695+
# XXX TODO What if it's a subclass of Awaitable?
16941696
return AnyType()
16951697

16961698
def analyze_iterable_item_type(self, expr: Node) -> Type:
@@ -1801,15 +1803,32 @@ def check_incompatible_property_override(self, e: Decorator) -> None:
18011803

18021804
def visit_with_stmt(self, s: WithStmt) -> Type:
18031805
echk = self.expr_checker
1806+
if s.is_async:
1807+
m_enter = '__aenter__'
1808+
m_exit = '__aexit__'
1809+
else:
1810+
m_enter = '__enter__'
1811+
m_exit = '__exit__'
18041812
for expr, target in zip(s.expr, s.target):
18051813
ctx = self.accept(expr)
1806-
enter = echk.analyze_external_member_access('__enter__', ctx, expr)
1814+
enter = echk.analyze_external_member_access(m_enter, ctx, expr)
18071815
obj = echk.check_call(enter, [], [], expr)[0]
1816+
if s.is_async:
1817+
self.check_subtype(obj, self.named_type('typing.Awaitable'), expr)
18081818
if target:
1819+
if s.is_async:
1820+
# XXX TODO What if it's a subclass of Awaitable?
1821+
if (isinstance(obj, Instance) and len(obj.args) == 1
1822+
and obj.type.fullname() == 'typing.Awaitable'):
1823+
obj = obj.args[0]
1824+
else:
1825+
obj = AnyType()
18091826
self.check_assignment(target, self.temp_node(obj, expr))
1810-
exit = echk.analyze_external_member_access('__exit__', ctx, expr)
1827+
exit = echk.analyze_external_member_access(m_exit, ctx, expr)
18111828
arg = self.temp_node(AnyType(), expr)
1812-
echk.check_call(exit, [arg] * 3, [nodes.ARG_POS] * 3, expr)
1829+
res = echk.check_call(exit, [arg] * 3, [nodes.ARG_POS] * 3, expr)[0]
1830+
if s.is_async:
1831+
self.check_subtype(res, self.named_type('typing.Awaitable'), expr)
18131832
self.accept(s.body)
18141833

18151834
def visit_print_stmt(self, s: PrintStmt) -> Type:
@@ -2004,12 +2023,14 @@ def visit_await_expr(self, e: AwaitExpr) -> Type:
20042023
if isinstance(actual_type, AnyType):
20052024
return any_type
20062025
if is_subtype(actual_type, generator_type):
2007-
if isinstance(actual_type, Instance) and len(actual_type.args) == 3:
2026+
if (isinstance(actual_type, Instance) and len(actual_type.args) == 3
2027+
and actual_type.type.fullname() == 'typing.Generator'):
20082028
return actual_type.args[2]
20092029
else:
20102030
return any_type # Must've been unparameterized Generator.
20112031
elif is_subtype(actual_type, awaitable_type):
2012-
if isinstance(actual_type, Instance) and len(actual_type.args) == 1:
2032+
if (isinstance(actual_type, Instance) and len(actual_type.args) == 1
2033+
and actual_type.type.fullname() == 'typing.Awaitable'):
20132034
return actual_type.args[0]
20142035
else:
20152036
return any_type # Must've been unparameterized Awaitable.

test-data/unit/check-async-await.test

+12
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,15 @@ async def f() -> None:
6767
[builtins fixtures/async_await.py]
6868
[out]
6969
main: note: In function "f":
70+
71+
[case testAsyncWith]
72+
# options: fast_parser
73+
class C:
74+
async def __aenter__(self) -> int: pass
75+
async def __aexit__(self, x, y, z) -> None: pass
76+
async def f() -> None:
77+
async with C() as x:
78+
reveal_type(x) # E: Revealed type is 'builtins.int'
79+
[builtins fixtures/async_await.py]
80+
[out]
81+
main: note: In function "f":

0 commit comments

Comments
 (0)