From 1a05e87ec75436d818f05a5dabcecaea67334cbd Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Sat, 19 Aug 2017 16:59:38 +1000 Subject: [3.6] bpo-31232: Backport custom print rshift message (GH-3155) bpo-30721 added a "Did you mean ...?" suggestion to rshift TypeError messages that triggers when the LHS is a Python C function called "print". Since this custom error message is expected to be triggered primarily by attempts to use Python 2 print redirection syntax in Python 3, and is incredibly unlikely to be encountered otherwise, it is also being backported to the next 3.6 maintenance release. Initial patch by Sanyam Khurana. --- Lib/test/test_print.py | 33 ++++++++++++++++++++++ .../2017-08-18-15-15-20.bpo-30721.Hmc56z.rst | 2 ++ Objects/abstract.c | 15 ++++++++++ 3 files changed, 50 insertions(+) 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 03f13b4..e6434fe 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 @@ -155,6 +156,38 @@ class TestPy2MigrationHint(unittest.TestCase): 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" + self.assertIn('Did you mean "print(, ' + 'file=)"?', str(context.exception)) + + # Test correct hint is produced in the case where RHS implements + # __rrshift__ but returns NotImplemented + with self.assertRaises(TypeError) as context: + print >> 42 + self.assertIn('Did you mean "print(, ' + 'file=)"?', str(context.exception)) + + # Test stream redirection hint is specific to print + with self.assertRaises(TypeError) as context: + max >> sys.stderr + self.assertNotIn('Did you mean ', str(context.exception)) + + # Test stream redirection hint is specific to rshift + with self.assertRaises(TypeError) as context: + print << sys.stderr + self.assertNotIn('Did you mean', str(context.exception)) + + # Ensure right operand implementing rrshift still works + class OverrideRRShift: + def __rrshift__(self, lhs): + return 42 # Force result independent of LHS + + self.assertEqual(print >> OverrideRRShift(), 42) + + if __name__ == "__main__": unittest.main() 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 0000000..da553d6 --- /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. diff --git a/Objects/abstract.c b/Objects/abstract.c index 38de774..6c6c86c 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -809,6 +809,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 (op_slot == NB_SLOT(nb_rshift) && + PyCFunction_Check(v) && + strcmp(((PyCFunctionObject *)v)->m_ml->ml_name, "print") == 0) + { + PyErr_Format(PyExc_TypeError, + "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; + } + return binop_type_error(v, w, op_name); } return result; -- cgit v0.12