Issue #26182: Raise DeprecationWarning for improper use of async/await keywords

This commit is contained in:
Yury Selivanov 2016-09-15 12:50:23 -04:00
parent 6775231597
commit 8987c9d219
6 changed files with 125 additions and 56 deletions

View File

@ -519,7 +519,7 @@ def sleep(delay, result=None, *, loop=None):
h.cancel()
def async(coro_or_future, *, loop=None):
def async_(coro_or_future, *, loop=None):
"""Wrap a coroutine in a future.
If the argument is a Future, it is returned directly.
@ -532,6 +532,11 @@ def async(coro_or_future, *, loop=None):
return ensure_future(coro_or_future, loop=loop)
# Silence DeprecationWarning:
globals()['async'] = async_
async_.__name__ = 'async'
del async_
def ensure_future(coro_or_future, *, loop=None):
"""Wrap a coroutine or an awaitable in a future.

View File

@ -358,57 +358,110 @@ class AsyncBadSyntaxTest(unittest.TestCase):
with self.subTest(code=code), self.assertRaises(SyntaxError):
compile(code, "<test>", "exec")
def test_badsyntax_2(self):
samples = [
"""def foo():
await = 1
""",
"""class Bar:
def async(): pass
""",
"""class Bar:
async = 1
""",
"""class async:
pass
""",
"""class await:
pass
""",
"""import math as await""",
"""def async():
pass""",
"""def foo(*, await=1):
pass"""
"""async = 1""",
"""print(await=1)"""
]
for code in samples:
with self.subTest(code=code), self.assertWarnsRegex(
DeprecationWarning,
"'await' will become reserved keywords"):
compile(code, "<test>", "exec")
def test_badsyntax_3(self):
with self.assertRaises(DeprecationWarning):
with warnings.catch_warnings():
warnings.simplefilter("error")
compile("async = 1", "<test>", "exec")
def test_goodsyntax_1(self):
# Tests for issue 24619
def foo(await):
async def foo(): pass
async def foo():
pass
return await + 1
self.assertEqual(foo(10), 11)
samples = [
'''def foo(await):
async def foo(): pass
async def foo():
pass
return await + 1
''',
def foo(await):
async def foo(): pass
async def foo(): pass
return await + 2
self.assertEqual(foo(20), 22)
'''def foo(await):
async def foo(): pass
async def foo(): pass
return await + 1
''',
def foo(await):
'''def foo(await):
async def foo(): pass
async def foo(): pass
async def foo(): pass
async def foo(): pass
return await + 2
self.assertEqual(foo(20), 22)
return await + 1
''',
def foo(await):
"""spam"""
async def foo(): \
pass
# 123
async def foo(): pass
# 456
return await + 2
self.assertEqual(foo(20), 22)
'''def foo(await):
"""spam"""
async def foo(): \
pass
# 123
async def foo(): pass
# 456
return await + 1
''',
def foo(await):
def foo(): pass
def foo(): pass
async def bar(): return await_
await_ = await
try:
bar().send(None)
except StopIteration as ex:
return ex.args[0]
self.assertEqual(foo(42), 42)
'''def foo(await):
def foo(): pass
def foo(): pass
async def bar(): return await_
await_ = await
try:
bar().send(None)
except StopIteration as ex:
return ex.args[0] + 1
'''
]
async def f():
async def g(): pass
await z
await = 1
self.assertTrue(inspect.iscoroutinefunction(f))
for code in samples:
with self.subTest(code=code):
loc = {}
with warnings.catch_warnings():
warnings.simplefilter("ignore")
exec(code, loc, loc)
self.assertEqual(loc['foo'](10), 11)
class TokenizerRegrTest(unittest.TestCase):

View File

@ -1345,18 +1345,6 @@ class GrammarTests(unittest.TestCase):
self.assertEqual(m.other, 42)
def test_async_await(self):
async = 1
await = 2
self.assertEqual(async, 1)
def async():
nonlocal await
await = 10
async()
self.assertEqual(await, 10)
self.assertFalse(bool(async.__code__.co_flags & inspect.CO_COROUTINE))
async def test():
def sum():
pass

View File

@ -353,14 +353,14 @@ class _AsyncDeprecatedProperty:
class DocumentLS:
"""Mixin to create documents that conform to the load/save spec."""
async = _AsyncDeprecatedProperty()
async_ = False
locals()['async'] = _AsyncDeprecatedProperty() # Avoid DeprecationWarning
def _get_async(self):
return False
def _set_async(self, async):
if async:
def _set_async(self, flag):
if flag:
raise xml.dom.NotSupportedErr(
"asynchronous document loading is not supported")

View File

@ -21,6 +21,9 @@ Core and Builtins
- Issue #28120: Fix dict.pop() for splitted dictionary when trying to remove a
"pending key" (Not yet inserted in split-table). Patch by Xiang Zhang.
- Issue #26182: Raise DeprecationWarning when async and await keywords are
used as variable/attribute/class/function name.
Library
-------

View File

@ -938,6 +938,26 @@ forbidden_name(struct compiling *c, identifier name, const node *n,
ast_error(c, n, "assignment to keyword");
return 1;
}
if (PyUnicode_CompareWithASCIIString(name, "async") == 0 ||
PyUnicode_CompareWithASCIIString(name, "await") == 0)
{
PyObject *message = PyUnicode_FromString(
"'async' and 'await' will become reserved keywords"
" in Python 3.7");
if (message == NULL) {
return 1;
}
if (PyErr_WarnExplicitObject(
PyExc_DeprecationWarning,
message,
c->c_filename,
LINENO(n),
NULL,
NULL) < 0)
{
return 1;
}
}
if (full_checks) {
const char * const *p;
for (p = FORBIDDEN; *p; p++) {