[Python-checkins] [3.6] bpo-31232: Backport custom print rshift message (GH-3155)

Nick Coghlan webhook-mailer at python.org
Sat Aug 19 02:59:42 EDT 2017


https://github.com/python/cpython/commit/1a05e87ec75436d818f05a5dabcecaea67334cbd
commit: 1a05e87ec75436d818f05a5dabcecaea67334cbd
branch: 3.6
author: Nick Coghlan <ncoghlan at gmail.com>
committer: GitHub <noreply at github.com>
date: 2017-08-19T16:59:38+10:00
summary:

[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.

files:
A Misc/NEWS.d/next/Core and Builtins/2017-08-18-15-15-20.bpo-30721.Hmc56z.rst
M Lib/test/test_print.py
M Objects/abstract.c

diff --git a/Lib/test/test_print.py b/Lib/test/test_print.py
index 03f13b4edfc..e6434feaf5e 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 @@ 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"
+        self.assertIn('Did you mean "print(<message>, '
+                'file=<output_stream>)"?', 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(<message>, '
+                'file=<output_stream>)"?', 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 00000000000..da553d654ec
--- /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 38de774de3a..6c6c86cd44a 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(<message>, "
+                "file=<output_stream>)\"?",
+                op_name,
+                v->ob_type->tp_name,
+                w->ob_type->tp_name);
+            return NULL;
+        }
+
         return binop_type_error(v, w, op_name);
     }
     return result;



More information about the Python-checkins mailing list