[3.6] bpo-31232: Backport custom print rshift message (GH-3155) · python/cpython@1a05e87 (original) (raw)

3 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
1 1 import unittest
2 +import sys
2 3 from io import StringIO
3 4
4 5 from test import support
@@ -155,6 +156,38 @@ def test_string_with_excessive_whitespace(self):
155 156
156 157 self.assertIn('print("Hello World", end=" ")', str(context.exception))
157 158
159 +def test_stream_redirection_hint_for_py2_migration(self):
160 +# Test correct hint produced for Py2 redirection syntax
161 +with self.assertRaises(TypeError) as context:
162 +print >> sys.stderr, "message"
163 +self.assertIn('Did you mean "print(, '
164 +'file=<output_stream>)"?', str(context.exception))
165 +
166 +# Test correct hint is produced in the case where RHS implements
167 +# __rrshift__ but returns NotImplemented
168 +with self.assertRaises(TypeError) as context:
169 +print >> 42
170 +self.assertIn('Did you mean "print(, '
171 +'file=<output_stream>)"?', str(context.exception))
172 +
173 +# Test stream redirection hint is specific to print
174 +with self.assertRaises(TypeError) as context:
175 +max >> sys.stderr
176 +self.assertNotIn('Did you mean ', str(context.exception))
177 +
178 +# Test stream redirection hint is specific to rshift
179 +with self.assertRaises(TypeError) as context:
180 +print << sys.stderr
181 +self.assertNotIn('Did you mean', str(context.exception))
182 +
183 +# Ensure right operand implementing rrshift still works
184 +class OverrideRRShift:
185 +def __rrshift__(self, lhs):
186 +return 42 # Force result independent of LHS
187 +
188 +self.assertEqual(print >> OverrideRRShift(), 42)
189 +
190 +
158 191
159 192 if __name__ == "__main__":
160 193 unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1 +``print`` now shows correct usage hint for using Python 2 redirection
2 +syntax. Patch by Sanyam Khurana.
Original file line number Diff line number Diff line change
@@ -809,6 +809,21 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name)
809 809 PyObject *result = binary_op1(v, w, op_slot);
810 810 if (result == Py_NotImplemented) {
811 811 Py_DECREF(result);
812 +
813 +if (op_slot == NB_SLOT(nb_rshift) &&
814 +PyCFunction_Check(v) &&
815 +strcmp(((PyCFunctionObject *)v)->m_ml->ml_name, "print") == 0)
816 + {
817 +PyErr_Format(PyExc_TypeError,
818 +"unsupported operand type(s) for %.100s: "
819 +"'%.100s' and '%.100s'. Did you mean \"print(, "
820 +"file=<output_stream>)\"?",
821 +op_name,
822 +v->ob_type->tp_name,
823 +w->ob_type->tp_name);
824 +return NULL;
825 + }
826 +
812 827 return binop_type_error(v, w, op_name);
813 828 }
814 829 return result;