8000 bpo-39965: Correctly raise SyntaxError if await is used outside async… · python/cpython@f7e32fc · GitHub
[go: up one dir, main page]

Skip to content

Commit f7e32fc

Browse filesBrowse files
bpo-39965: Correctly raise SyntaxError if await is used outside async functions when PyCF_ALLOW_TOP_LEVEL_AWAIT is set (GH-19010)
(cherry picked from commit 9023581) Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
1 parent 4abe77c commit f7e32fc

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

Lib/test/test_builtin.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,44 @@ async def arange(n):
421421
finally:
422422
asyncio.set_event_loop_policy(policy)
423423

424+
def test_compile_top_level_await_invalid_cases(self):
425+
# helper function just to check we can run top=level async-for
426+
async def arange(n):
427+
for i in range(n):
428+
yield i
429+
430+
modes = ('single', 'exec')
431+
code_samples = [
432+
'''def f(): await arange(10)\n''',
433+
'''def f(): [x async for x in arange(10)]\n''',
434+
'''def f(): [await x async for x in arange(10)]\n''',
435+
'''def f():
436+
async for i in arange(1):
437+
a = 1
438+
''',
439+
'''def f():
440+
async with asyncio.Lock() as l:
441+
a = 1
442+
'''
443+
]
444+
policy = maybe_get_event_loop_policy()
445+
try:
446+
for mode, code_sample in product(modes, code_samples):
447+
source = dedent(code_sample)
448+
with self.assertRaises(
449+
SyntaxError, msg=f"source={source} mode={mode}"):
450+
compile(source, '?', mode)
451+
452+
with self.assertRaises(
453+
SyntaxError, msg=f"source={source} mode={mode}"):
454+
co = compile(source,
455+
'?',
456+
mode,
457+
flags=ast.PyCF_ALLOW_TOP_LEVEL_AWAIT)
458+
finally:
459+
asyncio.set_event_loop_policy(policy)
460+
461+
424462
def test_compile_async_generator(self):
425463
"""
426464
With the PyCF_ALLOW_TOP_LEVEL_AWAIT flag added in 3.8, we want to
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Correctly raise ``SyntaxError`` if *await* is used inside non-async
2+
functions and ``PyCF_ALLOW_TOP_LEVEL_AWAIT`` is set (like in the asyncio
3+
REPL). Patch by Pablo Galindo.

Python/compile.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
#define COMP_SETCOMP 2
4242
#define COMP_DICTCOMP 3
4343

44+
#define IS_TOP_LEVEL_AWAIT(c) ( \
45+
(c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \
46+
&& (c->u->u_ste->ste_type == ModuleBlock))
47+
4448
struct instr {
4549
unsigned i_jabs : 1;
4650
unsigned i_jrel : 1;
@@ -2682,7 +2686,7 @@ static int
26822686
compiler_async_for(struct compiler *c, stmt_ty s)
26832687
{
26842688
basicblock *start, *except, *end;
2685-
if (c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT){
2689+
if (IS_TOP_LEVEL_AWAIT(c)){
26862690
c->u->u_ste->ste_coroutine = 1;
26872691
} else if (c->u->u_scope_type != COMPILER_SCOPE_ASYNC_FUNCTION) {
26882692
return compiler_error(c, "'async for' outside async function");
@@ -4666,7 +4670,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
46664670
withitem_ty item = asdl_seq_GET(s->v.AsyncWith.items, pos);
46674671

46684672
assert(s->kind == AsyncWith_kind);
4669-
if (c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT){
4673+
if (IS_TOP_LEVEL_AWAIT(c)){
46704674
c->u->u_ste->ste_coroutine = 1;
46714675
} else if (c->u->u_scope_type != COMPILER_SCOPE_ASYNC_FUNCTION){
46724676
return compiler_error(c, "'async with' outside async function");
@@ -4877,7 +4881,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
48774881
ADDOP(c, YIELD_FROM);
48784882
break;
48794883
case Await_kind:
4880-
if (!(c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT)){
4884+
if (!IS_TOP_LEVEL_AWAIT(c)){
48814885
if (c->u->u_ste->ste_type != FunctionBlock){
48824886
return compiler_error(c, "'await' outside function");
48834887
}
@@ -5820,7 +5824,7 @@ compute_code_flags(struct compiler *c)
58205824
/* (Only) inherit compilerflags in PyCF_MASK */
58215825
flags |= (c->c_flags->cf_flags & PyCF_MASK);
58225826

5823-
if ((c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) &&
5827+
if ((IS_TOP_LEVEL_AWAIT(c)) &&
58245828
ste->ste_coroutine &&
58255829
!ste->ste_generator) {
58265830
flags |= CO_COROUTINE;

0 commit comments

Comments
 (0)
0