bpo-30721: Show correct syntax hint in Py3 when using Py2 redirection… · python/cpython@5e2eb35 (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
@@ -819,6 +819,21 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name)
819 819 PyObject *result = binary_op1(v, w, op_slot);
820 820 if (result == Py_NotImplemented) {
821 821 Py_DECREF(result);
822 +
823 +if (op_slot == NB_SLOT(nb_rshift) &&
824 +PyCFunction_Check(v) &&
825 +strcmp(((PyCFunctionObject *)v)->m_ml->ml_name, "print") == 0)
826 + {
827 +PyErr_Format(PyExc_TypeError,
828 +"unsupported operand type(s) for %.100s: "
829 +"'%.100s' and '%.100s'. Did you mean \"print(, "
830 +"file=<output_stream>)\"",
831 +op_name,
832 +v->ob_type->tp_name,
833 +w->ob_type->tp_name);
834 +return NULL;
835 + }
836 +
822 837 return binop_type_error(v, w, op_name);
823 838 }
824 839 return result;