summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSanyam Khurana <CuriousLearner@users.noreply.github.com>2017-06-20 19:01:32 +0530
committerSerhiy Storchaka <storchaka@gmail.com>2017-06-20 16:31:32 +0300
commit3a7f03584ab75afbf5507970711c87042e423bb4 (patch)
treeab193606a8d7371fdf1650a7be10b541979b61a9
parent90e01e50ef8a9e6c91f30d965563c378a4ad26de (diff)
downloadcpython-git-3a7f03584ab75afbf5507970711c87042e423bb4.tar.gz
bpo-30597: Show expected input in custom 'print' error message. (#2009)
-rw-r--r--Lib/test/test_print.py28
-rw-r--r--Misc/NEWS3
-rw-r--r--Objects/exceptions.c48
3 files changed, 76 insertions, 3 deletions
diff --git a/Lib/test/test_print.py b/Lib/test/test_print.py
index 7eea349115..03f13b4edf 100644
--- a/Lib/test/test_print.py
+++ b/Lib/test/test_print.py
@@ -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()
diff --git a/Misc/NEWS b/Misc/NEWS
index 47f3c37904..6469986b48 100644
--- 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'").
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index 858eff5fc2..190ad06540 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -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 */