]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-30597: Show expected input in custom 'print' error message. (#2009)
authorSanyam Khurana <CuriousLearner@users.noreply.github.com>
Tue, 20 Jun 2017 13:31:32 +0000 (19:01 +0530)
committerSerhiy Storchaka <storchaka@gmail.com>
Tue, 20 Jun 2017 13:31:32 +0000 (16:31 +0300)
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 47f3c379049b8fef4d166496ba406f9d6261b775..6469986b48ce20c2a065d245ec4224801c66b16c 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 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.
+
 - bpo-30682: Removed a too-strict assertion that failed for certain f-strings,
   such as eval("f'\\\n'") and eval("f'\\\r'").
 
index 858eff5fc26c344dc4a8e4114c458d01c4a99553..190ad0654024b09a52157a4dd784bc27685ca392 100644 (file)
@@ -2862,6 +2862,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)
 {
@@ -2897,9 +2940,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 */