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"
import os
import sys
import unittest
+import warnings
import weakref
from test import support
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
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")
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
...
"""
+import textwrap
import unittest
import weakref
+import warnings
from test.support import run_doctest, run_unittest, cpython_only
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):
import sys
# testing import *
from sys import *
+from test import support
class TokenTests(unittest.TestCase):
# 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
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.
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;
- }
- 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;
+ 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;
+ }
+
+ default:
+ break;
}
VISIT(c, expr, value);