Skip to content

Commit 8987c9d

Browse files
committed
Issue python#26182: Raise DeprecationWarning for improper use of async/await keywords
1 parent 6775231 commit 8987c9d

6 files changed

Lines changed: 127 additions & 58 deletions

File tree

Lib/asyncio/tasks.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ def sleep(delay, result=None, *, loop=None):
519519
h.cancel()
520520

521521

522-
def async(coro_or_future, *, loop=None):
522+
def async_(coro_or_future, *, loop=None):
523523
"""Wrap a coroutine in a future.
524524
525525
If the argument is a Future, it is returned directly.
@@ -532,6 +532,11 @@ def async(coro_or_future, *, loop=None):
532532

533533
return ensure_future(coro_or_future, loop=loop)
534534

535+
# Silence DeprecationWarning:
536+
globals()['async'] = async_
537+
async_.__name__ = 'async'
538+
del async_
539+
535540

536541
def ensure_future(coro_or_future, *, loop=None):
537542
"""Wrap a coroutine or an awaitable in a future.

Lib/test/test_coroutines.py

Lines changed: 95 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -358,57 +358,110 @@ async def bar():
358358
with self.subTest(code=code), self.assertRaises(SyntaxError):
359359
compile(code, "<test>", "exec")
360360

361-
def test_goodsyntax_1(self):
362-
# Tests for issue 24619
361+
def test_badsyntax_2(self):
362+
samples = [
363+
"""def foo():
364+
await = 1
365+
""",
366+
367+
"""class Bar:
368+
def async(): pass
369+
""",
363370

364-
def foo(await):
365-
async def foo(): pass
366-
async def foo():
371+
"""class Bar:
372+
async = 1
373+
""",
374+
375+
"""class async:
367376
pass
368-
return await + 1
369-
self.assertEqual(foo(10), 11)
377+
""",
370378

371-
def foo(await):
372-
async def foo(): pass
373-
async def foo(): pass
374-
return await + 2
375-
self.assertEqual(foo(20), 22)
379+
"""class await:
380+
pass
381+
""",
376382

377-
def foo(await):
383+
"""import math as await""",
378384

379-
async def foo(): pass
385+
"""def async():
386+
pass""",
380387

381-
async def foo(): pass
388+
"""def foo(*, await=1):
389+
pass"""
382390

383-
return await + 2
384-
self.assertEqual(foo(20), 22)
391+
"""async = 1""",
385392

386-
def foo(await):
387-
"""spam"""
388-
async def foo(): \
389-
pass
390-
# 123
391-
async def foo(): pass
392-
# 456
393-
return await + 2
394-
self.assertEqual(foo(20), 22)
395-
396-
def foo(await):
397-
def foo(): pass
398-
def foo(): pass
399-
async def bar(): return await_
400-
await_ = await
401-
try:
402-
bar().send(None)
403-
except StopIteration as ex:
404-
return ex.args[0]
405-
self.assertEqual(foo(42), 42)
393+
"""print(await=1)"""
394+
]
406395

407-
async def f():
408-
async def g(): pass
409-
await z
410-
await = 1
411-
self.assertTrue(inspect.iscoroutinefunction(f))
396+
for code in samples:
397+
with self.subTest(code=code), self.assertWarnsRegex(
398+
DeprecationWarning,
399+
"'await' will become reserved keywords"):
400+
compile(code, "<test>", "exec")
401+
402+
def test_badsyntax_3(self):
403+
with self.assertRaises(DeprecationWarning):
404+
with warnings.catch_warnings():
405+
warnings.simplefilter("error")
406+
compile("async = 1", "<test>", "exec")
407+
408+
def test_goodsyntax_1(self):
409+
# Tests for issue 24619
410+
411+
samples = [
412+
'''def foo(await):
413+
async def foo(): pass
414+
async def foo():
415+
pass
416+
return await + 1
417+
''',
418+
419+
'''def foo(await):
420+
async def foo(): pass
421+
async def foo(): pass
422+
return await + 1
423+
''',
424+
425+
'''def foo(await):
426+
427+
async def foo(): pass
428+
429+
async def foo(): pass
430+
431+
return await + 1
432+
''',
433+
434+
'''def foo(await):
435+
"""spam"""
436+
async def foo(): \
437+
pass
438+
# 123
439+
async def foo(): pass
440+
# 456
441+
return await + 1
442+
''',
443+
444+
'''def foo(await):
445+
def foo(): pass
446+
def foo(): pass
447+
async def bar(): return await_
448+
await_ = await
449+
try:
450+
bar().send(None)
451+
except StopIteration as ex:
452+
return ex.args[0] + 1
453+
'''
454+
]
455+
456+
for code in samples:
457+
with self.subTest(code=code):
458+
loc = {}
459+
460+
with warnings.catch_warnings():
461+
warnings.simplefilter("ignore")
462+
exec(code, loc, loc)
463+
464+
self.assertEqual(loc['foo'](10), 11)
412465

413466

414467
class TokenizerRegrTest(unittest.TestCase):

Lib/test/test_grammar.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,18 +1345,6 @@ def __imatmul__(self, o):
13451345
self.assertEqual(m.other, 42)
13461346

13471347
def test_async_await(self):
1348-
async = 1
1349-
await = 2
1350-
self.assertEqual(async, 1)
1351-
1352-
def async():
1353-
nonlocal await
1354-
await = 10
1355-
async()
1356-
self.assertEqual(await, 10)
1357-
1358-
self.assertFalse(bool(async.__code__.co_flags & inspect.CO_COROUTINE))
1359-
13601348
async def test():
13611349
def sum():
13621350
pass

Lib/xml/dom/xmlbuilder.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,14 +353,14 @@ def __set__(self, instance, value):
353353
class DocumentLS:
354354
"""Mixin to create documents that conform to the load/save spec."""
355355

356-
async = _AsyncDeprecatedProperty()
357356
async_ = False
357+
locals()['async'] = _AsyncDeprecatedProperty() # Avoid DeprecationWarning
358358

359359
def _get_async(self):
360360
return False
361361

362-
def _set_async(self, async):
363-
if async:
362+
def _set_async(self, flag):
363+
if flag:
364364
raise xml.dom.NotSupportedErr(
365365
"asynchronous document loading is not supported")
366366

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ Core and Builtins
2121
- Issue #28120: Fix dict.pop() for splitted dictionary when trying to remove a
2222
"pending key" (Not yet inserted in split-table). Patch by Xiang Zhang.
2323

24+
- Issue #26182: Raise DeprecationWarning when async and await keywords are
25+
used as variable/attribute/class/function name.
26+
2427
Library
2528
-------
2629

Python/ast.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,26 @@ forbidden_name(struct compiling *c, identifier name, const node *n,
938938
ast_error(c, n, "assignment to keyword");
939939
return 1;
940940
}
941+
if (PyUnicode_CompareWithASCIIString(name, "async") == 0 ||
942+
PyUnicode_CompareWithASCIIString(name, "await") == 0)
943+
{
944+
PyObject *message = PyUnicode_FromString(
945+
"'async' and 'await' will become reserved keywords"
946+
" in Python 3.7");
947+
if (message == NULL) {
948+
return 1;
949+
}
950+
if (PyErr_WarnExplicitObject(
951+
PyExc_DeprecationWarning,
952+
message,
953+
c->c_filename,
954+
LINENO(n),
955+
NULL,
956+
NULL) < 0)
957+
{
958+
return 1;
959+
}
960+
}
941961
if (full_checks) {
942962
const char * const *p;
943963
for (p = FORBIDDEN; *p; p++) {

0 commit comments

Comments
 (0)