From f87f983ad88cd07e8b21b39ada9635e14ea1c8fe 2013-08-29 21:33:32 From: Thomas Kluyver Date: 2013-08-29 21:33:32 Subject: [PATCH] Merge pull request #4120 from minrk/input-py2 support `input` in Python 2 kernels --- diff --git a/IPython/kernel/tests/test_kernel.py b/IPython/kernel/tests/test_kernel.py index 305dce7..253ce15 100644 --- a/IPython/kernel/tests/test_kernel.py +++ b/IPython/kernel/tests/test_kernel.py @@ -24,7 +24,7 @@ import nose.tools as nt from IPython.kernel import KernelManager from IPython.kernel.tests.test_message_spec import execute, flush_channels from IPython.testing import decorators as dec -from IPython.utils import path +from IPython.utils import path, py3compat #------------------------------------------------------------------------------- # Tests @@ -33,6 +33,9 @@ IPYTHONDIR = None save_env = None save_get_ipython_dir = None +STARTUP_TIMEOUT = 60 +TIMEOUT = 15 + def setup(): """setup temporary IPYTHONDIR for tests""" global IPYTHONDIR @@ -75,7 +78,7 @@ def new_kernel(): # wait for kernel to be ready KC.shell_channel.execute("import sys") - KC.shell_channel.get_msg(block=True, timeout=5) + KC.shell_channel.get_msg(block=True, timeout=STARTUP_TIMEOUT) flush_channels(KC) try: yield KC @@ -116,6 +119,8 @@ def _check_mp_mode(kc, expected=False, stream="stdout"): nt.assert_equal(eval(stdout.strip()), expected) +# printing tests + def test_simple_print(): """simple print statement in kernel""" with new_kernel() as kc: @@ -125,7 +130,6 @@ def test_simple_print(): nt.assert_equal(stdout, 'hi\n') nt.assert_equal(stderr, '') _check_mp_mode(kc, expected=False) - print ('hello') @dec.knownfailureif(sys.platform == 'win32', "subprocess prints fail on Windows") @@ -202,3 +206,47 @@ def test_subprocess_error(): _check_mp_mode(kc, expected=False) _check_mp_mode(kc, expected=False, stream="stderr") + +# raw_input tests + +def test_raw_input(): + """test [raw_]input""" + with new_kernel() as kc: + iopub = kc.iopub_channel + + input_f = "input" if py3compat.PY3 else "raw_input" + theprompt = "prompt> " + code = 'print({input_f}("{theprompt}"))'.format(**locals()) + msg_id = kc.execute(code, allow_stdin=True) + msg = kc.get_stdin_msg(block=True, timeout=TIMEOUT) + nt.assert_equal(msg['header']['msg_type'], u'input_request') + content = msg['content'] + nt.assert_equal(content['prompt'], theprompt) + text = "some text" + kc.input(text) + reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) + nt.assert_equal(reply['content']['status'], 'ok') + stdout, stderr = assemble_output(iopub) + nt.assert_equal(stdout, text + "\n") + + +@dec.skipif(py3compat.PY3) +def test_eval_input(): + """test input() on Python 2""" + with new_kernel() as kc: + iopub = kc.iopub_channel + + input_f = "input" if py3compat.PY3 else "raw_input" + theprompt = "prompt> " + code = 'print(input("{theprompt}"))'.format(**locals()) + msg_id = kc.execute(code, allow_stdin=True) + msg = kc.get_stdin_msg(block=True, timeout=TIMEOUT) + nt.assert_equal(msg['header']['msg_type'], u'input_request') + content = msg['content'] + nt.assert_equal(content['prompt'], theprompt) + kc.input("1+1") + reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) + nt.assert_equal(reply['content']['status'], 'ok') + stdout, stderr = assemble_output(iopub) + nt.assert_equal(stdout, "2\n") + diff --git a/IPython/kernel/zmq/ipkernel.py b/IPython/kernel/zmq/ipkernel.py index 8445ec4..a65b05d 100755 --- a/IPython/kernel/zmq/ipkernel.py +++ b/IPython/kernel/zmq/ipkernel.py @@ -131,6 +131,7 @@ class Kernel(Configurable): # A reference to the Python builtin 'raw_input' function. # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3) _sys_raw_input = Any() + _sys_eval_input = Any() # set of aborted msg_ids aborted = Set() @@ -352,15 +353,18 @@ class Kernel(Configurable): # raw_input in the user namespace. if content.get('allow_stdin', False): raw_input = lambda prompt='': self._raw_input(prompt, ident, parent) + input = lambda prompt='': eval(raw_input(prompt)) else: - raw_input = lambda prompt='' : self._no_raw_input() + raw_input = input = lambda prompt='' : self._no_raw_input() if py3compat.PY3: self._sys_raw_input = __builtin__.input __builtin__.input = raw_input else: self._sys_raw_input = __builtin__.raw_input + self._sys_eval_input = __builtin__.input __builtin__.raw_input = raw_input + __builtin__.input = input # Set the parent message of the display hook and out streams. shell.displayhook.set_parent(parent) @@ -403,6 +407,7 @@ class Kernel(Configurable): __builtin__.input = self._sys_raw_input else: __builtin__.raw_input = self._sys_raw_input + __builtin__.input = self._sys_eval_input reply_content[u'status'] = status diff --git a/examples/notebooks/Frontend-Kernel Model.ipynb b/examples/notebooks/Frontend-Kernel Model.ipynb index e176151..249788b 100644 --- a/examples/notebooks/Frontend-Kernel Model.ipynb +++ b/examples/notebooks/Frontend-Kernel Model.ipynb @@ -1,6 +1,6 @@ { "metadata": { - "name": "Frontend-Kernel Model" + "name": "" }, "nbformat": 3, "nbformat_minor": 0, @@ -152,6 +152,21 @@ "cell_type": "code", "collapsed": false, "input": [ + "# Python 3 compat\n", + "try:\n", + " raw_input\n", + "except NameError:\n", + " raw_input = input" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ "name = raw_input(\"What is your name? \")\n", "name" ], @@ -169,13 +184,49 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 1, + "prompt_number": 2, "text": [ - "u'Sir Robin'" + "'Sir Robin'" ] } ], - "prompt_number": 1 + "prompt_number": 2 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Python 2-only**: the eval input works as well (`input` is just `eval(raw_input(prompt))`)" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "fingers = input(\"How many fingers? \")\n", + "fingers, type(fingers)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "stream": "stdout", + "text": [ + "How many fingers? 4\n" + ] + }, + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 3, + "text": [ + "(4, int)" + ] + } + ], + "prompt_number": 3 }, { "cell_type": "code", @@ -195,13 +246,13 @@ "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;32m\u001b[0m in \u001b[0;36mdiv\u001b[1;34m(x, y)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;32m\u001b[0m in \u001b[0;36mdiv\u001b[1;34m(x, y)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mZeroDivisionError\u001b[0m: integer division or modulo by zero" ] } ], - "prompt_number": 2 + "prompt_number": 4 }, { "cell_type": "code", @@ -216,7 +267,7 @@ "output_type": "stream", "stream": "stdout", "text": [ - "> \u001b[1;32m\u001b[0m(2)\u001b[0;36mdiv\u001b[1;34m()\u001b[0m\n", + "> \u001b[1;32m\u001b[0m(2)\u001b[0;36mdiv\u001b[1;34m()\u001b[0m\n", "\u001b[1;32m 1 \u001b[1;33m\u001b[1;32mdef\u001b[0m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[0m\u001b[1;32m----> 2 \u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[0m\u001b[1;32m 3 \u001b[1;33m\u001b[1;33m\u001b[0m\u001b[0m\n", @@ -262,7 +313,7 @@ ] } ], - "prompt_number": 3 + "prompt_number": 5 } ], "metadata": {}