diff -r 782c3b4cbc88 Lib/test/test_grammar.py --- a/Lib/test/test_grammar.py Thu Jun 05 12:07:14 2014 +0200 +++ b/Lib/test/test_grammar.py Fri Jun 06 22:54:26 2014 +1000 @@ -384,6 +384,18 @@ check_syntax_error(self, "x + 1 = 1") check_syntax_error(self, "a + 1 = b + 2") + def test_print_statement_refers_to_builtin(self): + with self.assertRaisesRegex(SyntaxError, "call to 'print'"): + exec("print foo") + with self.assertRaisesRegex(SyntaxError, "invalid syntax"): + exec("print (foo.)") + + def test_exec_statement_refers_to_builtin(self): + with self.assertRaisesRegex(SyntaxError, "call to 'exec'"): + exec("exec foo") + with self.assertRaisesRegex(SyntaxError, "invalid syntax"): + exec("exec (foo.)") + def test_del_stmt(self): # 'del' exprlist abc = [1,2,3] diff -r 782c3b4cbc88 Objects/exceptions.c --- a/Objects/exceptions.c Thu Jun 05 12:07:14 2014 +0200 +++ b/Objects/exceptions.c Fri Jun 06 22:54:26 2014 +1000 @@ -1298,6 +1298,58 @@ Py_INCREF(self->text); Py_DECREF(info); + + /* Issue #21669: Custom error for 'print' & 'exec' as statements + * We take the simple option of assuming any syntax error where + * the program text starts with "print " or "exec " and does not + * contain a left parenthesis character is a result of attempting + * to write these operations as Python 2 style statements. + */ + if (self->text && PyUnicode_Check(self->text)) { + static PyObject *left_paren = NULL; + static PyObject *print_prefix = NULL; + static PyObject *exec_prefix = NULL; + Py_ssize_t text_len = PyUnicode_GET_LENGTH(self->text); + Py_ssize_t left_paren_index; + + if (left_paren == NULL) { + left_paren = PyUnicode_InternFromString("("); + if (left_paren == NULL) { + return -1; + } + } + left_paren_index = PyUnicode_Find(self->text, left_paren, + 0, text_len, 1); + if (left_paren_index < -1) { + return -1; + } else if (left_paren_index == -1) { + if (print_prefix == NULL) { + print_prefix = PyUnicode_InternFromString("print "); + if (print_prefix == NULL) { + return -1; + } + } + if (exec_prefix == NULL) { + exec_prefix = PyUnicode_InternFromString("exec "); + if (exec_prefix == NULL) { + return -1; + } + } + if (PyUnicode_Tailmatch(self->text, print_prefix, + 0, text_len, -1)) { + Py_CLEAR(self->msg); + self->msg = PyUnicode_FromString( + "Missing parentheses in call to 'print'"); + } + if (PyUnicode_Tailmatch(self->text, exec_prefix, + 0, text_len, -1)) { + Py_CLEAR(self->msg); + self->msg = PyUnicode_FromString( + "Missing parentheses in call to 'exec'"); + } + } + } + } return 0; }