[Python-checkins] cpython (merge 3.6 -> default): Merge 3.6 (issue #26182)

yury.selivanov python-checkins at python.org
Thu Sep 15 12:50:56 EDT 2016


https://hg.python.org/cpython/rev/3f8b75173543
changeset:   103809:3f8b75173543
parent:      103807:b6ca2d734f8e
parent:      103808:82e6017dc841
user:        Yury Selivanov <yury at magic.io>
date:        Thu Sep 15 12:50:51 2016 -0400
summary:
  Merge 3.6 (issue #26182)

files:
  Lib/asyncio/tasks.py        |    7 +-
  Lib/test/test_coroutines.py |  133 ++++++++++++++++-------
  Lib/test/test_grammar.py    |   12 --
  Lib/xml/dom/xmlbuilder.py   |    6 +-
  Misc/NEWS                   |    3 +
  Python/ast.c                |   20 +++
  6 files changed, 125 insertions(+), 56 deletions(-)


diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -519,7 +519,7 @@
         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 @@
 
     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.
diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py
--- a/Lib/test/test_coroutines.py
+++ b/Lib/test/test_coroutines.py
@@ -358,57 +358,110 @@
             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):
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -1345,18 +1345,6 @@
         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
diff --git a/Lib/xml/dom/xmlbuilder.py b/Lib/xml/dom/xmlbuilder.py
--- a/Lib/xml/dom/xmlbuilder.py
+++ b/Lib/xml/dom/xmlbuilder.py
@@ -353,14 +353,14 @@
 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")
 
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -21,6 +21,9 @@
 - 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
 -------
 
diff --git a/Python/ast.c b/Python/ast.c
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -938,6 +938,26 @@
         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++) {

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list