From 0b3326be8f0f48aad304b5963bd7dd08edb6e496 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 28 Feb 2023 12:11:51 +0300 Subject: [PATCH] Add a separate error code for top level `await`, refs #14763 --- mypy/errorcodes.py | 3 +++ mypy/semanal.py | 4 +++- test-data/unit/check-async-await.test | 6 +++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index 3d8b1096ed4f..2eb2d5c624b6 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -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( diff --git a/mypy/semanal.py b/mypy/semanal.py index d2fd92499679..f41fe8140413 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -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) diff --git a/test-data/unit/check-async-await.test b/test-data/unit/check-async-await.test index 40efe2d2cece..7356fa59c86d 100644 --- a/test-data/unit/check-async-await.test +++ b/test-data/unit/check-async-await.test @@ -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