-
- Notifications
You must be signed in to change notification settings - Fork 33.7k
bpo-30597: Shows expected input in custom 'print' error message #2009
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
fcd1a05 737ff28 3d08859 80d96b2 07d2943 1711975 99ad8da 0a1de7d 3401409 097aa87 825741b d3efcd0 File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| | @@ -128,5 +128,26 @@ def flush(self): | |
| 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.assertTrue('print("Hello World")' in 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.assertTrue('print("Hello World", end=" ")' in str(context.exception)) | ||
| ||
| | ||
| Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add also tests for excessive whitespaces: | ||
| | ||
| if __name__ == "__main__": | ||
| unittest.main() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| | @@ -2862,6 +2862,51 @@ _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("\r\n"); | ||
| ||
| Py_UCS4 soft_space_check = PyUnicode_READ_CHAR(PyUnicode_FromString(","), 0); | ||
| ||
| | ||
| 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) | ||
| return -1; | ||
| Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. strip_sep_obj is leaked here. | ||
| | ||
| data = _PyUnicode_XStrip(data, 1, strip_sep_obj); | ||
| ||
| | ||
| Py_DECREF(strip_sep_obj); | ||
| | ||
| // gets the modified text_len after stripping `print ` | ||
| text_len = PyUnicode_GET_LENGTH(data); | ||
| const char *maybe_end_arg = ""; | ||
| | ||
| if (text_len > 0) { | ||
| if (PyUnicode_READ_CHAR(data, text_len-1) == soft_space_check) { | ||
| ||
| maybe_end_arg = " end=\" \""; | ||
| } | ||
| } | ||
| | ||
| PyObject *error_msg = PyUnicode_FromFormat( | ||
| Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The result is not checked for error. | ||
| "Missing parentheses in call to 'print'. Did you mean print(%U%s)?", | ||
| data, maybe_end_arg); | ||
| | ||
| Py_DECREF(data); | ||
| | ||
| Py_XSETREF(self->msg, error_msg); | ||
| | ||
| return 1; | ||
| Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At that point multiple results of | ||
| } | ||
| | ||
| static int | ||
| _check_for_legacy_statements(PySyntaxErrorObject *self, Py_ssize_t start) | ||
| { | ||
| | @@ -2897,9 +2942,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 */ | ||
| | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use
assertIn().Or use
assertRaisesRegex()with the argumentr'print\("Hello World"\)'orre.escape('print("Hello World")').