From b26d729f2efac3f4912d58439758f8b27769be7b Mon Sep 17 00:00:00 2001 From: CuriousLearner Date: Fri, 23 Jun 2017 10:51:53 +0530 Subject: [PATCH 01/11] bpo-30721: WIP for showing hint in Py3 when using Py2 redirection syntax --- Lib/test/test_print.py | 8 ++++++++ Objects/abstract.c | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/Lib/test/test_print.py b/Lib/test/test_print.py index 03f13b4edfc598..61acc5e53a12bc 100644 --- a/Lib/test/test_print.py +++ b/Lib/test/test_print.py @@ -155,6 +155,14 @@ def test_string_with_excessive_whitespace(self): self.assertIn('print("Hello World", end=" ")', str(context.exception)) + def test_string_with_stream_redirection(self): + import sys + python2_print_str = 'print >> sys.stderr, "message"' + with self.assertRaises(TypeError) as context: + exec(python2_print_str) + + self.assertIn('print(message, file={:100!r}).format(sys.stderr)', str(context.exception)) + if __name__ == "__main__": unittest.main() diff --git a/Objects/abstract.c b/Objects/abstract.c index cb026c0df5daf6..eb83e4ca78e022 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -819,6 +819,21 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) PyObject *result = binary_op1(v, w, op_slot); if (result == Py_NotImplemented) { Py_DECREF(result); + + if (strcmp(op_name, ">>") == 0 && \ + strcmp(v->ob_type->tp_name, "builtin_function_or_method") == 0) { + PyErr_Format(PyExc_TypeError, + "unsupported operand type(s) for %.100s: " + "'%.100s' and '%.100s'. Did you mean \"print(%s, " + "file={:100!r}).format(%s))\"", + op_name, + v->ob_type->tp_name, + w->ob_type->tp_name, + "message", + "sys.stderr"); + return NULL; + } + return binop_type_error(v, w, op_name); } return result; From aa5cc110967da028a2a4051bc12917f7a50497ae Mon Sep 17 00:00:00 2001 From: CuriousLearner Date: Fri, 23 Jun 2017 14:00:27 +0530 Subject: [PATCH 02/11] bpo-30721: Address review comments --- Lib/test/test_print.py | 3 ++- Objects/abstract.c | 17 ++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_print.py b/Lib/test/test_print.py index 61acc5e53a12bc..fa2b0f68527a0a 100644 --- a/Lib/test/test_print.py +++ b/Lib/test/test_print.py @@ -161,7 +161,8 @@ def test_string_with_stream_redirection(self): with self.assertRaises(TypeError) as context: exec(python2_print_str) - self.assertIn('print(message, file={:100!r}).format(sys.stderr)', str(context.exception)) + self.assertIn('Did you mean "print(, ' + 'file=)', str(context.exception)) if __name__ == "__main__": diff --git a/Objects/abstract.c b/Objects/abstract.c index eb83e4ca78e022..f173004e7459b8 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -820,17 +820,16 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) if (result == Py_NotImplemented) { Py_DECREF(result); - if (strcmp(op_name, ">>") == 0 && \ + if (op_slot == 96 && \ strcmp(v->ob_type->tp_name, "builtin_function_or_method") == 0) { + PyErr_Format(PyExc_TypeError, - "unsupported operand type(s) for %.100s: " - "'%.100s' and '%.100s'. Did you mean \"print(%s, " - "file={:100!r}).format(%s))\"", - op_name, - v->ob_type->tp_name, - w->ob_type->tp_name, - "message", - "sys.stderr"); + "unsupported operand type(s) for %.100s: " + "'%.100s' and '%.100s'. Did you mean \"print(, " + "file=)\"", + op_name, + v->ob_type->tp_name, + w->ob_type->tp_name); return NULL; } From 7db3e71b073dd6cca860926d678126e6c8356edc Mon Sep 17 00:00:00 2001 From: CuriousLearner Date: Mon, 31 Jul 2017 11:47:06 +0530 Subject: [PATCH 03/11] bpo-30721: Address review comments --- Objects/abstract.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index f173004e7459b8..262ae4227ff073 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -820,7 +820,7 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) if (result == Py_NotImplemented) { Py_DECREF(result); - if (op_slot == 96 && \ + if (op_slot == NB_SLOT(nb_rshift) && \ strcmp(v->ob_type->tp_name, "builtin_function_or_method") == 0) { PyErr_Format(PyExc_TypeError, From 6eaf00597e821b7501e48e682e90d83d5d462efe Mon Sep 17 00:00:00 2001 From: CuriousLearner Date: Mon, 7 Aug 2017 22:34:31 +0530 Subject: [PATCH 04/11] bpo-30721: Address review comments --- Lib/test/test_print.py | 28 +++++++++++++++++++++++++++- Objects/abstract.c | 2 +- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_print.py b/Lib/test/test_print.py index fa2b0f68527a0a..d3c2a835354c71 100644 --- a/Lib/test/test_print.py +++ b/Lib/test/test_print.py @@ -155,7 +155,7 @@ def test_string_with_excessive_whitespace(self): self.assertIn('print("Hello World", end=" ")', str(context.exception)) - def test_string_with_stream_redirection(self): + def test_print_string_with_stream_redirection(self): import sys python2_print_str = 'print >> sys.stderr, "message"' with self.assertRaises(TypeError) as context: @@ -164,6 +164,32 @@ def test_string_with_stream_redirection(self): self.assertIn('Did you mean "print(, ' 'file=)', str(context.exception)) + def test_print_with_stream_redirection_using_max(self): + import sys + python2_print_str = 'max >> sys.stderr' + with self.assertRaises(TypeError) as context: + exec(python2_print_str) + + self.assertNotIn('Did you mean "print(, ' + 'file=)', str(context.exception)) + + def test_print_with_stream_redirection_using_rrshift(self): + import sys + + class OverrideRRShift: + + def __rrshift__(self, lhs): + return 0 # Force result independent of LHS + + self.assertEqual(print >> OverrideRRShift(), 0) + + python2_print_str = 'print >> 42' + with self.assertRaises(TypeError) as context: + exec(python2_print_str) + + self.assertIn('Did you mean "print(, ' + 'file=)', str(context.exception)) + if __name__ == "__main__": unittest.main() diff --git a/Objects/abstract.c b/Objects/abstract.c index 262ae4227ff073..728516ab8c5308 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -821,7 +821,7 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) Py_DECREF(result); if (op_slot == NB_SLOT(nb_rshift) && \ - strcmp(v->ob_type->tp_name, "builtin_function_or_method") == 0) { + PyCFunction_Check(v) && strcmp(((PyCFunctionObject *)v) -> m_ml -> ml_name, "print") == 0) { PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for %.100s: " From 766511557430ecf626e6ffd8ad65c2d46be35b15 Mon Sep 17 00:00:00 2001 From: CuriousLearner Date: Fri, 18 Aug 2017 12:53:29 +0530 Subject: [PATCH 05/11] bpo-30721: Address review comments --- Lib/test/test_print.py | 37 +++++++++++++++++++++++-------------- Objects/abstract.c | 6 ++++-- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_print.py b/Lib/test/test_print.py index d3c2a835354c71..71d7e397918f9c 100644 --- a/Lib/test/test_print.py +++ b/Lib/test/test_print.py @@ -155,8 +155,10 @@ def test_string_with_excessive_whitespace(self): self.assertIn('print("Hello World", end=" ")', str(context.exception)) - def test_print_string_with_stream_redirection(self): + def test_stream_redirection_hint_for_py2_migration(self): import sys + + # Test correct hint produced for Py2 redirection syntax python2_print_str = 'print >> sys.stderr, "message"' with self.assertRaises(TypeError) as context: exec(python2_print_str) @@ -164,31 +166,38 @@ def test_print_string_with_stream_redirection(self): self.assertIn('Did you mean "print(, ' 'file=)', str(context.exception)) - def test_print_with_stream_redirection_using_max(self): - import sys + # Test correct hint is produced in thecase where RHS implements + # __rrshift__ but returns NotImplemented + python2_print_str = 'print >> 42' + with self.assertRaises(TypeError) as context: + exec(python2_print_str) + + self.assertIn('Did you mean "print(, ' + 'file=)', str(context.exception)) + + # Test stream redirection hint is specific to print python2_print_str = 'max >> sys.stderr' with self.assertRaises(TypeError) as context: exec(python2_print_str) + self.assertNotIn('Did you mean ', str(context.exception)) + + # Test stream redirection hint is specific to rrshift + python2_print_str = 'print << sys.stderr' + with self.assertRaises(TypeError) as context: + exec(python2_print_str) + self.assertNotIn('Did you mean "print(, ' 'file=)', str(context.exception)) - def test_print_with_stream_redirection_using_rrshift(self): - import sys - + # Test stream redirection with right argument implemented __rrshift__ class OverrideRRShift: def __rrshift__(self, lhs): - return 0 # Force result independent of LHS - - self.assertEqual(print >> OverrideRRShift(), 0) + return 42 # Force result independent of LHS - python2_print_str = 'print >> 42' - with self.assertRaises(TypeError) as context: - exec(python2_print_str) + self.assertEqual(print >> OverrideRRShift(), 42) - self.assertIn('Did you mean "print(, ' - 'file=)', str(context.exception)) if __name__ == "__main__": diff --git a/Objects/abstract.c b/Objects/abstract.c index 728516ab8c5308..1181261806d493 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -820,8 +820,10 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) if (result == Py_NotImplemented) { Py_DECREF(result); - if (op_slot == NB_SLOT(nb_rshift) && \ - PyCFunction_Check(v) && strcmp(((PyCFunctionObject *)v) -> m_ml -> ml_name, "print") == 0) { + if (op_slot == NB_SLOT(nb_rshift) && + PyCFunction_Check(v) && + strncmp(((PyCFunctionObject *)v) -> m_ml -> ml_name, "print", 6) == 0) + { PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for %.100s: " From da0fbabf756b670cca7ff43a93af34980373430a Mon Sep 17 00:00:00 2001 From: CuriousLearner Date: Fri, 18 Aug 2017 13:48:31 +0530 Subject: [PATCH 06/11] bpo-30721: Address review comments --- Lib/test/test_print.py | 26 ++++++++------------------ Misc/NEWS | 3 +++ Objects/abstract.c | 5 ++--- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/Lib/test/test_print.py b/Lib/test/test_print.py index 71d7e397918f9c..3f27cae5903bb1 100644 --- a/Lib/test/test_print.py +++ b/Lib/test/test_print.py @@ -1,4 +1,5 @@ import unittest +import sys from io import StringIO from test import support @@ -156,43 +157,32 @@ def test_string_with_excessive_whitespace(self): self.assertIn('print("Hello World", end=" ")', str(context.exception)) def test_stream_redirection_hint_for_py2_migration(self): - import sys # Test correct hint produced for Py2 redirection syntax - python2_print_str = 'print >> sys.stderr, "message"' with self.assertRaises(TypeError) as context: - exec(python2_print_str) - + print >> sys.stderr, "message" self.assertIn('Did you mean "print(, ' 'file=)', str(context.exception)) - # Test correct hint is produced in thecase where RHS implements + # Test correct hint is produced in the case where RHS implements # __rrshift__ but returns NotImplemented - python2_print_str = 'print >> 42' with self.assertRaises(TypeError) as context: - exec(python2_print_str) - + print >> 42 self.assertIn('Did you mean "print(, ' 'file=)', str(context.exception)) # Test stream redirection hint is specific to print - python2_print_str = 'max >> sys.stderr' with self.assertRaises(TypeError) as context: - exec(python2_print_str) - + max >> sys.stderr self.assertNotIn('Did you mean ', str(context.exception)) - # Test stream redirection hint is specific to rrshift - python2_print_str = 'print << sys.stderr' + # Test stream redirection hint is specific to rshift with self.assertRaises(TypeError) as context: - exec(python2_print_str) - - self.assertNotIn('Did you mean "print(, ' - 'file=)', str(context.exception)) + print << sys.stderr + self.assertNotIn('Did you mean', str(context.exception)) # Test stream redirection with right argument implemented __rrshift__ class OverrideRRShift: - def __rrshift__(self, lhs): return 42 # Force result independent of LHS diff --git a/Misc/NEWS b/Misc/NEWS index ce4874ac36df6a..7bbe3d99c42ba2 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-30721: ``print`` now shows correct usage hint for using Python 2 + redirection syntax. Patch by Sanyam Khurana. + - bpo-30814: Fixed a race condition when import a submodule from a package. - bpo-30736: The internal unicodedata database has been upgraded to Unicode diff --git a/Objects/abstract.c b/Objects/abstract.c index 1181261806d493..d65a33e7254138 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -821,10 +821,9 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) Py_DECREF(result); if (op_slot == NB_SLOT(nb_rshift) && - PyCFunction_Check(v) && - strncmp(((PyCFunctionObject *)v) -> m_ml -> ml_name, "print", 6) == 0) + PyCFunction_Check(v) && + strncmp(((PyCFunctionObject *)v)->m_ml->ml_name, "print", 6) == 0) { - PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for %.100s: " "'%.100s' and '%.100s'. Did you mean \"print(, " From c43e23ce617960fd795b372be6349430811b5095 Mon Sep 17 00:00:00 2001 From: CuriousLearner Date: Fri, 18 Aug 2017 15:16:24 +0530 Subject: [PATCH 07/11] bpo-30721: Adds NEWS entry and minor fixes --- Lib/test/test_print.py | 3 +-- .../Core and Builtins/2017-08-18-15-15-20.bpo-30721.Hmc56z.rst | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2017-08-18-15-15-20.bpo-30721.Hmc56z.rst diff --git a/Lib/test/test_print.py b/Lib/test/test_print.py index 3f27cae5903bb1..80993279b8d028 100644 --- a/Lib/test/test_print.py +++ b/Lib/test/test_print.py @@ -157,7 +157,6 @@ def test_string_with_excessive_whitespace(self): self.assertIn('print("Hello World", end=" ")', str(context.exception)) def test_stream_redirection_hint_for_py2_migration(self): - # Test correct hint produced for Py2 redirection syntax with self.assertRaises(TypeError) as context: print >> sys.stderr, "message" @@ -181,7 +180,7 @@ def test_stream_redirection_hint_for_py2_migration(self): print << sys.stderr self.assertNotIn('Did you mean', str(context.exception)) - # Test stream redirection with right argument implemented __rrshift__ + # Ensure right operand implementing rrshift still works class OverrideRRShift: def __rrshift__(self, lhs): return 42 # Force result independent of LHS diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-08-18-15-15-20.bpo-30721.Hmc56z.rst b/Misc/NEWS.d/next/Core and Builtins/2017-08-18-15-15-20.bpo-30721.Hmc56z.rst new file mode 100644 index 00000000000000..e3595d4d4437aa --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-08-18-15-15-20.bpo-30721.Hmc56z.rst @@ -0,0 +1,2 @@ +``print`` now shows correct usage hint for using Python 2 redirection +syntax. Patch by Sanyam Khurana. From bad1d7b522937c791064f406bbf002e57a619a44 Mon Sep 17 00:00:00 2001 From: CuriousLearner Date: Fri, 18 Aug 2017 15:23:16 +0530 Subject: [PATCH 08/11] bpo-30721: Fixes rST news entry --- .../Core and Builtins/2017-08-18-15-15-20.bpo-30721.Hmc56z.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-08-18-15-15-20.bpo-30721.Hmc56z.rst b/Misc/NEWS.d/next/Core and Builtins/2017-08-18-15-15-20.bpo-30721.Hmc56z.rst index e3595d4d4437aa..da553d654ec76c 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2017-08-18-15-15-20.bpo-30721.Hmc56z.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2017-08-18-15-15-20.bpo-30721.Hmc56z.rst @@ -1,2 +1,2 @@ ``print`` now shows correct usage hint for using Python 2 redirection -syntax. Patch by Sanyam Khurana. +syntax. Patch by Sanyam Khurana. From 74eff16caa42f3851515b72ac691d0c000c7c582 Mon Sep 17 00:00:00 2001 From: CuriousLearner Date: Fri, 18 Aug 2017 15:25:52 +0530 Subject: [PATCH 09/11] bpo-30721: Reverts strncmp to strcmp --- Objects/abstract.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index d65a33e7254138..eb67d3cbabdaca 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -822,7 +822,7 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) if (op_slot == NB_SLOT(nb_rshift) && PyCFunction_Check(v) && - strncmp(((PyCFunctionObject *)v)->m_ml->ml_name, "print", 6) == 0) + strcmp(((PyCFunctionObject *)v) -> m_ml -> ml_name, "print") == 0) { PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for %.100s: " From d1a96417d4471e5753dc9729dc82711226a2189c Mon Sep 17 00:00:00 2001 From: CuriousLearner Date: Fri, 18 Aug 2017 15:29:46 +0530 Subject: [PATCH 10/11] bpo-30721: Removes manual entry to MISC/NEWS --- Misc/NEWS | 3 --- 1 file changed, 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index 7bbe3d99c42ba2..ce4874ac36df6a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,9 +10,6 @@ What's New in Python 3.7.0 alpha 1? Core and Builtins ----------------- -- bpo-30721: ``print`` now shows correct usage hint for using Python 2 - redirection syntax. Patch by Sanyam Khurana. - - bpo-30814: Fixed a race condition when import a submodule from a package. - bpo-30736: The internal unicodedata database has been upgraded to Unicode From 185050eafe742393bbc84aafa6d3afe67e985af2 Mon Sep 17 00:00:00 2001 From: CuriousLearner Date: Fri, 18 Aug 2017 15:32:45 +0530 Subject: [PATCH 11/11] bpo-30721: Removes spaces around pointers --- Objects/abstract.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index eb67d3cbabdaca..abd97953bd9edf 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -822,7 +822,7 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) if (op_slot == NB_SLOT(nb_rshift) && PyCFunction_Check(v) && - strcmp(((PyCFunctionObject *)v) -> m_ml -> ml_name, "print") == 0) + strcmp(((PyCFunctionObject *)v)->m_ml->ml_name, "print") == 0) { PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for %.100s: "