]> granicus.if.org Git - python/commitdiff
[3.6] bpo-30597: Show expected input in custom 'print' error message. (GH-2531)
authorNick Coghlan <ncoghlan@gmail.com>
Mon, 3 Jul 2017 07:49:50 +0000 (17:49 +1000)
committerGitHub <noreply@github.com>
Mon, 3 Jul 2017 07:49:50 +0000 (17:49 +1000)
(cherry picked from commit 3a7f03584ab75afbf5507970711c87042e423bb4)

Lib/test/test_print.py
Misc/NEWS
Objects/exceptions.c

index 7eea349115a9471cbfdfd01712398d9fbe9aacd5..03f13b4edfc598d8f8653d9e24aeada7870a46d5 100644 (file)
@@ -128,5 +128,33 @@ class TestPrint(unittest.TestCase):
                 raise RuntimeError
         self.assertRaises(RuntimeError, print, 1, file=noflush(), flush=True)
 
+
+class TestPy2MigrationHint(unittest.TestCase):
+    """Test that correct hint is produced analogous to Python3 syntax,
+    if print statement is executed as in Python 2.
+    """
+
+    def test_normal_string(self):
+        python2_print_str = 'print "Hello World"'
+        with self.assertRaises(SyntaxError) as context:
+            exec(python2_print_str)
+
+        self.assertIn('print("Hello World")', str(context.exception))
+
+    def test_string_with_soft_space(self):
+        python2_print_str = 'print "Hello World",'
+        with self.assertRaises(SyntaxError) as context:
+            exec(python2_print_str)
+
+        self.assertIn('print("Hello World", end=" ")', str(context.exception))
+
+    def test_string_with_excessive_whitespace(self):
+        python2_print_str = 'print  "Hello World", '
+        with self.assertRaises(SyntaxError) as context:
+            exec(python2_print_str)
+
+        self.assertIn('print("Hello World", end=" ")', str(context.exception))
+
+
 if __name__ == "__main__":
     unittest.main()
index a3a32ae6c60810442aa54e4ff61a358eed77592d..92ccf52149aac1d9fdbdb905dfed2b4797c7f7bb 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 3.6.3 release candidate 1?
 Core and Builtins
 -----------------
 
+- bpo-30597: ``print`` now shows expected input in custom error message when
+  used as a Python 2 statement. Patch by Sanyam Khurana.
+
 Library
 -------
 
index d158b9768d45f50663d620b3c91a87aebadcaddd..f286ec076f8286a3b1b5f2bc2bca0be6585166d6 100644 (file)
@@ -2881,6 +2881,49 @@ _PyErr_TrySetFromCause(const char *format, ...)
  * or minus, using the stream redirection syntax).
  */
 
+
+// Static helper for setting legacy print error message
+static int
+_set_legacy_print_statement_msg(PySyntaxErrorObject *self, Py_ssize_t start)
+{
+    PyObject *strip_sep_obj = PyUnicode_FromString(" \t\r\n");
+    if (strip_sep_obj == NULL)
+        return -1;
+
+    // PRINT_OFFSET is to remove `print ` word from the data.
+    const int PRINT_OFFSET = 6;
+    Py_ssize_t text_len = PyUnicode_GET_LENGTH(self->text);
+    PyObject *data = PyUnicode_Substring(self->text, PRINT_OFFSET, text_len);
+
+    if (data == NULL) {
+        Py_DECREF(strip_sep_obj);
+        return -1;
+    }
+    PyObject *new_data = _PyUnicode_XStrip(data, 2, strip_sep_obj);
+    Py_DECREF(data);
+    Py_DECREF(strip_sep_obj);
+
+    if (new_data == NULL) {
+        return -1;
+    }
+    // gets the modified text_len after stripping `print `
+    text_len = PyUnicode_GET_LENGTH(new_data);
+    const char *maybe_end_arg = "";
+    if (text_len > 0 && PyUnicode_READ_CHAR(new_data, text_len-1) == ',') {
+        maybe_end_arg = " end=\" \"";
+    }
+    PyObject *error_msg = PyUnicode_FromFormat(
+        "Missing parentheses in call to 'print'. Did you mean print(%U%s)?",
+        new_data, maybe_end_arg
+    );
+    Py_DECREF(new_data);
+    if (error_msg == NULL)
+        return -1;
+
+    Py_XSETREF(self->msg, error_msg);
+    return 1;
+}
+
 static int
 _check_for_legacy_statements(PySyntaxErrorObject *self, Py_ssize_t start)
 {
@@ -2916,9 +2959,8 @@ _check_for_legacy_statements(PySyntaxErrorObject *self, Py_ssize_t start)
     }
     if (PyUnicode_Tailmatch(self->text, print_prefix,
                             start, text_len, -1)) {
-        Py_XSETREF(self->msg,
-                  PyUnicode_FromString("Missing parentheses in call to 'print'"));
-        return 1;
+
+        return _set_legacy_print_statement_msg(self, start);
     }
 
     /* Check for legacy exec statements */