Skip to content

Commit bfdc6fd

Browse files
authored
[3.6] bpo-30597: Show expected input in custom 'print' error message. (GH-2531)
(cherry picked from commit 3a7f035)
1 parent 03af428 commit bfdc6fd

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

Lib/test/test_print.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,5 +128,33 @@ def flush(self):
128128
raise RuntimeError
129129
self.assertRaises(RuntimeError, print, 1, file=noflush(), flush=True)
130130

131+
132+
class TestPy2MigrationHint(unittest.TestCase):
133+
"""Test that correct hint is produced analogous to Python3 syntax,
134+
if print statement is executed as in Python 2.
135+
"""
136+
137+
def test_normal_string(self):
138+
python2_print_str = 'print "Hello World"'
139+
with self.assertRaises(SyntaxError) as context:
140+
exec(python2_print_str)
141+
142+
self.assertIn('print("Hello World")', str(context.exception))
143+
144+
def test_string_with_soft_space(self):
145+
python2_print_str = 'print "Hello World",'
146+
with self.assertRaises(SyntaxError) as context:
147+
exec(python2_print_str)
148+
149+
self.assertIn('print("Hello World", end=" ")', str(context.exception))
150+
151+
def test_string_with_excessive_whitespace(self):
152+
python2_print_str = 'print "Hello World", '
153+
with self.assertRaises(SyntaxError) as context:
154+
exec(python2_print_str)
155+
156+
self.assertIn('print("Hello World", end=" ")', str(context.exception))
157+
158+
131159
if __name__ == "__main__":
132160
unittest.main()

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.6.3 release candidate 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- bpo-30597: ``print`` now shows expected input in custom error message when
14+
used as a Python 2 statement. Patch by Sanyam Khurana.
15+
1316
Library
1417
-------
1518

Objects/exceptions.c

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2881,6 +2881,49 @@ _PyErr_TrySetFromCause(const char *format, ...)
28812881
* or minus, using the stream redirection syntax).
28822882
*/
28832883

2884+
2885+
// Static helper for setting legacy print error message
2886+
static int
2887+
_set_legacy_print_statement_msg(PySyntaxErrorObject *self, Py_ssize_t start)
2888+
{
2889+
PyObject *strip_sep_obj = PyUnicode_FromString(" \t\r\n");
2890+
if (strip_sep_obj == NULL)
2891+
return -1;
2892+
2893+
// PRINT_OFFSET is to remove `print ` word from the data.
2894+
const int PRINT_OFFSET = 6;
2895+
Py_ssize_t text_len = PyUnicode_GET_LENGTH(self->text);
2896+
PyObject *data = PyUnicode_Substring(self->text, PRINT_OFFSET, text_len);
2897+
2898+
if (data == NULL) {
2899+
Py_DECREF(strip_sep_obj);
2900+
return -1;
2901+
}
2902+
PyObject *new_data = _PyUnicode_XStrip(data, 2, strip_sep_obj);
2903+
Py_DECREF(data);
2904+
Py_DECREF(strip_sep_obj);
2905+
2906+
if (new_data == NULL) {
2907+
return -1;
2908+
}
2909+
// gets the modified text_len after stripping `print `
2910+
text_len = PyUnicode_GET_LENGTH(new_data);
2911+
const char *maybe_end_arg = "";
2912+
if (text_len > 0 && PyUnicode_READ_CHAR(new_data, text_len-1) == ',') {
2913+
maybe_end_arg = " end=\" \"";
2914+
}
2915+
PyObject *error_msg = PyUnicode_FromFormat(
2916+
"Missing parentheses in call to 'print'. Did you mean print(%U%s)?",
2917+
new_data, maybe_end_arg
2918+
);
2919+
Py_DECREF(new_data);
2920+
if (error_msg == NULL)
2921+
return -1;
2922+
2923+
Py_XSETREF(self->msg, error_msg);
2924+
return 1;
2925+
}
2926+
28842927
static int
28852928
_check_for_legacy_statements(PySyntaxErrorObject *self, Py_ssize_t start)
28862929
{
@@ -2916,9 +2959,8 @@ _check_for_legacy_statements(PySyntaxErrorObject *self, Py_ssize_t start)
29162959
}
29172960
if (PyUnicode_Tailmatch(self->text, print_prefix,
29182961
start, text_len, -1)) {
2919-
Py_XSETREF(self->msg,
2920-
PyUnicode_FromString("Missing parentheses in call to 'print'"));
2921-
return 1;
2962+
2963+
return _set_legacy_print_statement_msg(self, start);
29222964
}
29232965

29242966
/* Check for legacy exec statements */

0 commit comments

Comments
 (0)