Skip to content

Commit

Permalink
Add a separate error code for top level await, refs #14763
Browse files Browse the repository at this point in the history
  • Loading branch information
sobolevn committed Feb 28, 2023
1 parent 243f584 commit 3ed4d14
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 2 deletions.
4 changes: 4 additions & 0 deletions ex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
async def foo():
pass

x = [await foo() for _ in range(1)]
3 changes: 3 additions & 0 deletions mypy/errorcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ def __str__(self) -> str:
SAFE_SUPER: Final = ErrorCode(
"safe-super", "Warn about calls to abstract methods with empty/trivial bodies", "General"
)
TOP_LEVEL_AWAIT: Final = ErrorCode(
"top-level-await", "Warn about top level await experessions", "General"
)

# These error codes aren't enabled by default.
NO_UNTYPED_DEF: Final[ErrorCode] = ErrorCode(
Expand Down
4 changes: 3 additions & 1 deletion mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -5249,7 +5249,9 @@ def visit_yield_expr(self, e: YieldExpr) -> None:
def visit_await_expr(self, expr: AwaitExpr) -> None:
if not self.is_func_scope() or not self.function_stack:
# We check both because is_function_scope() returns True inside comprehensions.
self.fail('"await" outside function', expr, serious=True, blocker=True)
# This is not a blocker, because some enviroments (like ipython)
# support top level awaits.
self.fail('"await" outside function', expr, serious=True, code=codes.TOP_LEVEL_AWAIT)
elif not self.function_stack[-1].is_coroutine:
self.fail('"await" outside coroutine ("async def")', expr, serious=True, blocker=True)
expr.expr.accept(self)
Expand Down
6 changes: 5 additions & 1 deletion test-data/unit/check-async-await.test
Original file line number Diff line number Diff line change
Expand Up @@ -945,11 +945,15 @@ async def bar(x: Union[A, B]) -> None:
[typing fixtures/typing-async.pyi]

[case testInvalidComprehensionNoCrash]
# flags: --show-error-codes
async def foo(x: int) -> int: ...

crasher = [await foo(x) for x in [1, 2, 3]] # E: "await" outside function
# These are allowed in some cases:
top_level = await foo(1) # E: "await" outside function [top-level-await]
crasher = [await foo(x) for x in [1, 2, 3]] # E: "await" outside function [top-level-await]

def bad() -> None:
# These are always critical / syntax issues:
y = [await foo(x) for x in [1, 2, 3]] # E: "await" outside coroutine ("async def")
async def good() -> None:
y = [await foo(x) for x in [1, 2, 3]] # OK
Expand Down

0 comments on commit 3ed4d14

Please sign in to comment.