[Python-checkins] cpython: compiler now ignores constant statements

victor.stinner python-checkins at python.org
Mon Feb 8 12:22:29 EST 2016


https://hg.python.org/cpython/rev/4bdb21380743
changeset:   100192:4bdb21380743
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Mon Feb 08 18:17:58 2016 +0100
summary:
  compiler now ignores constant statements

The compile ignores constant statements and emit a SyntaxWarning warning.

Don't emit the warning for string statement because triple quoted string is a
common syntax for multiline comments.

Don't emit the warning on ellipis neither: 'def f(): ...' is a legit syntax for
abstract functions.

Changes:

* test_ast: ignore SyntaxWarning when compiling test statements. Modify
  test_load_const() to use assignment expressions rather than constant
  expression.
* test_code: add more kinds of constant statements, ignore SyntaxWarning when
  testing that the compiler removes constant statements.
* test_grammar: ignore SyntaxWarning on the statement "1"

files:
  Lib/test/test_ast.py     |  33 +++++++--------
  Lib/test/test_code.py    |  58 +++++++++++++++++++--------
  Lib/test/test_grammar.py |   6 ++-
  Misc/NEWS                |   4 +
  Python/compile.c         |  41 ++++++++++++++-----
  5 files changed, 95 insertions(+), 47 deletions(-)


diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -3,6 +3,7 @@
 import os
 import sys
 import unittest
+import warnings
 import weakref
 
 from test import support
@@ -239,8 +240,10 @@
                     ast_tree = compile(i, "?", kind, ast.PyCF_ONLY_AST)
                     self.assertEqual(to_tuple(ast_tree), o)
                     self._assertTrueorder(ast_tree, (0, 0))
-                with self.subTest(action="compiling", input=i):
-                    compile(ast_tree, "?", kind)
+                with warnings.catch_warnings():
+                    warnings.filterwarnings('ignore', category=SyntaxWarning)
+                    with self.subTest(action="compiling", input=i, kind=kind):
+                        compile(ast_tree, "?", kind)
 
     def test_slice(self):
         slc = ast.parse("x[::]").body[0].value.slice
@@ -1020,27 +1023,23 @@
                   b'bytes',
                   (1, 2, 3)]
 
-        code = '\n'.join(map(repr, consts))
-        code += '\n...'
-
-        code_consts = [const for const in consts
-                       if (not isinstance(const, (str, int, float, complex))
-                           or isinstance(const, bool))]
-        code_consts.append(Ellipsis)
-        # the compiler adds a final "LOAD_CONST None"
-        code_consts.append(None)
+        code = '\n'.join(['x={!r}'.format(const) for const in consts])
+        code += '\nx = ...'
+        consts.extend((Ellipsis, None))
 
         tree = ast.parse(code)
-        self.assertEqual(self.get_load_const(tree), code_consts)
+        self.assertEqual(self.get_load_const(tree),
+                         consts)
 
         # Replace expression nodes with constants
-        for expr_node, const in zip(tree.body, consts):
-            assert isinstance(expr_node, ast.Expr)
+        for assign, const in zip(tree.body, consts):
+            assert isinstance(assign, ast.Assign), ast.dump(assign)
             new_node = ast.Constant(value=const)
-            ast.copy_location(new_node, expr_node.value)
-            expr_node.value = new_node
+            ast.copy_location(new_node, assign.value)
+            assign.value = new_node
 
-        self.assertEqual(self.get_load_const(tree), code_consts)
+        self.assertEqual(self.get_load_const(tree),
+                         consts)
 
     def test_literal_eval(self):
         tree = ast.parse("1 + 2")
diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py
--- a/Lib/test/test_code.py
+++ b/Lib/test/test_code.py
@@ -66,24 +66,6 @@
 flags: 67
 consts: ('None',)
 
->>> def optimize_away():
-...     'doc string'
-...     'not a docstring'
-...     53
-...     0x53
-
->>> dump(optimize_away.__code__)
-name: optimize_away
-argcount: 0
-kwonlyargcount: 0
-names: ()
-varnames: ()
-cellvars: ()
-freevars: ()
-nlocals: 0
-flags: 67
-consts: ("'doc string'", 'None')
-
 >>> def keywordonly_args(a,b,*,k1):
 ...     return a,b,k1
 ...
@@ -102,8 +84,10 @@
 
 """
 
+import textwrap
 import unittest
 import weakref
+import warnings
 from test.support import run_doctest, run_unittest, cpython_only
 
 
@@ -134,6 +118,44 @@
         self.assertEqual(co.co_name, "funcname")
         self.assertEqual(co.co_firstlineno, 15)
 
+    def dump(self, co):
+        dump = {}
+        for attr in ["name", "argcount", "kwonlyargcount", "names", "varnames",
+                     "cellvars", "freevars", "nlocals", "flags"]:
+            dump[attr] = getattr(co, "co_" + attr)
+        dump['consts'] = tuple(consts(co.co_consts))
+        return dump
+
+    def test_optimize_away(self):
+        ns = {}
+        with warnings.catch_warnings():
+            warnings.filterwarnings('ignore', category=SyntaxWarning)
+            exec(textwrap.dedent('''
+                def optimize_away():
+                    'doc string'
+                    'not a docstring'
+                    53
+                    0x53
+                    b'bytes'
+                    1.0
+                    True
+                    False
+                    None
+                    ...
+            '''), ns)
+
+        self.assertEqual(self.dump(ns['optimize_away'].__code__),
+                        {'name': 'optimize_away',
+                         'argcount': 0,
+                         'kwonlyargcount': 0,
+                         'names': (),
+                         'varnames': (),
+                         'cellvars': (),
+                         'freevars': (),
+                         'nlocals': 0,
+                         'flags': 67,
+                         'consts': ("'doc string'", 'None')})
+
 
 class CodeWeakRefTest(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
@@ -7,6 +7,7 @@
 import sys
 # testing import *
 from sys import *
+from test import support
 
 
 class TokenTests(unittest.TestCase):
@@ -424,8 +425,11 @@
     # Tested below
 
     def test_expr_stmt(self):
+        msg = 'ignore constant statement'
+        with support.check_warnings((msg, SyntaxWarning)):
+            exec("1")
+
         # (exprlist '=')* exprlist
-        1
         1, 2, 3
         x = 1
         x = 1, 2, 3
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,10 @@
 Core and Builtins
 -----------------
 
+- Issue #26204: The compiler now ignores constant statements (ex: "def f(): 1")
+  and emit a SyntaxWarning warning. The warning is not emitted for string and
+  ellipsis (...) statements.
+
 - Issue #4806: Avoid masking the original TypeError exception when using star
   (*) unpacking in function calls.  Based on patch by Hagen Fürstenau and
   Daniel Urban.
diff --git a/Python/compile.c b/Python/compile.c
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -2616,20 +2616,39 @@
         return 1;
     }
 
-    if (value->kind == Str_kind || value->kind == Num_kind) {
-        /* ignore strings and numbers */
+    switch (value->kind)
+    {
+    case Str_kind:
+    case Ellipsis_kind:
+        /* Issue #26204: ignore string statement, but don't emit a
+         * SyntaxWarning. Triple quoted strings is a common syntax for
+         * multiline comments.
+         *
+         * Don't emit warning on "def f(): ..." neither. It's a legit syntax
+         * for abstract function. */
+        return 1;
+
+    case Bytes_kind:
+    case Num_kind:
+    case NameConstant_kind:
+    case Constant_kind:
+    {
+        PyObject *msg = PyUnicode_FromString("ignore constant statement");
+        if (msg == NULL)
+            return 0;
+        if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning,
+                                     msg,
+                                     c->c_filename, c->u->u_lineno,
+                                     NULL, NULL) == -1) {
+            Py_DECREF(msg);
+            return 0;
+        }
+        Py_DECREF(msg);
         return 1;
     }
 
-    if (value->kind == Constant_kind) {
-        PyObject *cst = value->v.Constant.value;
-        if (PyUnicode_CheckExact(cst)
-            || PyLong_CheckExact(cst)
-            || PyFloat_CheckExact(cst)
-            || PyComplex_CheckExact(cst)) {
-            /* ignore strings and numbers */
-            return 1;
-        }
+    default:
+        break;
     }
 
     VISIT(c, expr, value);

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


More information about the Python-checkins mailing list