##// END OF EJS Templates
only complete on current line...
MinRK -
Show More
@@ -1,224 +1,228 b''
1 1 # coding: utf-8
2 2 """test the IPython Kernel"""
3 3
4 #-------------------------------------------------------------------------------
5 # Copyright (C) 2013 The IPython Development Team
6 #
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
9 #-------------------------------------------------------------------------------
10
11 #-------------------------------------------------------------------------------
12 # Imports
13 #-------------------------------------------------------------------------------
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
14 6
15 7 import io
16 8 import os.path
17 9 import sys
18 10
19 11 import nose.tools as nt
20 12
21 13 from IPython.testing import decorators as dec, tools as tt
22 14 from IPython.utils import py3compat
23 15 from IPython.utils.path import locate_profile
24 16 from IPython.utils.tempdir import TemporaryDirectory
25 17
26 18 from .utils import (new_kernel, kernel, TIMEOUT, assemble_output, execute,
27 19 flush_channels, wait_for_idle)
28 20
29 #-------------------------------------------------------------------------------
30 # Tests
31 #-------------------------------------------------------------------------------
32
33 21
34 22 def _check_mp_mode(kc, expected=False, stream="stdout"):
35 23 execute(kc=kc, code="import sys")
36 24 flush_channels(kc)
37 25 msg_id, content = execute(kc=kc, code="print (sys.%s._check_mp_mode())" % stream)
38 26 stdout, stderr = assemble_output(kc.iopub_channel)
39 27 nt.assert_equal(eval(stdout.strip()), expected)
40 28
41 29
42 30 # printing tests
43 31
44 32 def test_simple_print():
45 33 """simple print statement in kernel"""
46 34 with kernel() as kc:
47 35 iopub = kc.iopub_channel
48 36 msg_id, content = execute(kc=kc, code="print ('hi')")
49 37 stdout, stderr = assemble_output(iopub)
50 38 nt.assert_equal(stdout, 'hi\n')
51 39 nt.assert_equal(stderr, '')
52 40 _check_mp_mode(kc, expected=False)
53 41
54 42
55 43 def test_sys_path():
56 44 """test that sys.path doesn't get messed up by default"""
57 45 with kernel() as kc:
58 46 msg_id, content = execute(kc=kc, code="import sys; print (repr(sys.path[0]))")
59 47 stdout, stderr = assemble_output(kc.iopub_channel)
60 48 nt.assert_equal(stdout, "''\n")
61 49
62 50 def test_sys_path_profile_dir():
63 51 """test that sys.path doesn't get messed up when `--profile-dir` is specified"""
64 52
65 53 with new_kernel(['--profile-dir', locate_profile('default')]) as kc:
66 54 msg_id, content = execute(kc=kc, code="import sys; print (repr(sys.path[0]))")
67 55 stdout, stderr = assemble_output(kc.iopub_channel)
68 56 nt.assert_equal(stdout, "''\n")
69 57
70 58 @dec.knownfailureif(sys.platform == 'win32', "subprocess prints fail on Windows")
71 59 def test_subprocess_print():
72 60 """printing from forked mp.Process"""
73 61 with new_kernel() as kc:
74 62 iopub = kc.iopub_channel
75 63
76 64 _check_mp_mode(kc, expected=False)
77 65 flush_channels(kc)
78 66 np = 5
79 67 code = '\n'.join([
80 68 "from __future__ import print_function",
81 69 "import multiprocessing as mp",
82 70 "pool = [mp.Process(target=print, args=('hello', i,)) for i in range(%i)]" % np,
83 71 "for p in pool: p.start()",
84 72 "for p in pool: p.join()"
85 73 ])
86 74
87 75 expected = '\n'.join([
88 76 "hello %s" % i for i in range(np)
89 77 ]) + '\n'
90 78
91 79 msg_id, content = execute(kc=kc, code=code)
92 80 stdout, stderr = assemble_output(iopub)
93 81 nt.assert_equal(stdout.count("hello"), np, stdout)
94 82 for n in range(np):
95 83 nt.assert_equal(stdout.count(str(n)), 1, stdout)
96 84 nt.assert_equal(stderr, '')
97 85 _check_mp_mode(kc, expected=False)
98 86 _check_mp_mode(kc, expected=False, stream="stderr")
99 87
100 88
101 89 def test_subprocess_noprint():
102 90 """mp.Process without print doesn't trigger iostream mp_mode"""
103 91 with kernel() as kc:
104 92 iopub = kc.iopub_channel
105 93
106 94 np = 5
107 95 code = '\n'.join([
108 96 "import multiprocessing as mp",
109 97 "pool = [mp.Process(target=range, args=(i,)) for i in range(%i)]" % np,
110 98 "for p in pool: p.start()",
111 99 "for p in pool: p.join()"
112 100 ])
113 101
114 102 msg_id, content = execute(kc=kc, code=code)
115 103 stdout, stderr = assemble_output(iopub)
116 104 nt.assert_equal(stdout, '')
117 105 nt.assert_equal(stderr, '')
118 106
119 107 _check_mp_mode(kc, expected=False)
120 108 _check_mp_mode(kc, expected=False, stream="stderr")
121 109
122 110
123 111 @dec.knownfailureif(sys.platform == 'win32', "subprocess prints fail on Windows")
124 112 def test_subprocess_error():
125 113 """error in mp.Process doesn't crash"""
126 114 with new_kernel() as kc:
127 115 iopub = kc.iopub_channel
128 116
129 117 code = '\n'.join([
130 118 "import multiprocessing as mp",
131 119 "p = mp.Process(target=int, args=('hi',))",
132 120 "p.start()",
133 121 "p.join()",
134 122 ])
135 123
136 124 msg_id, content = execute(kc=kc, code=code)
137 125 stdout, stderr = assemble_output(iopub)
138 126 nt.assert_equal(stdout, '')
139 127 nt.assert_true("ValueError" in stderr, stderr)
140 128
141 129 _check_mp_mode(kc, expected=False)
142 130 _check_mp_mode(kc, expected=False, stream="stderr")
143 131
144 132 # raw_input tests
145 133
146 134 def test_raw_input():
147 135 """test [raw_]input"""
148 136 with kernel() as kc:
149 137 iopub = kc.iopub_channel
150 138
151 139 input_f = "input" if py3compat.PY3 else "raw_input"
152 140 theprompt = "prompt> "
153 141 code = 'print({input_f}("{theprompt}"))'.format(**locals())
154 142 msg_id = kc.execute(code, allow_stdin=True)
155 143 msg = kc.get_stdin_msg(block=True, timeout=TIMEOUT)
156 144 nt.assert_equal(msg['header']['msg_type'], u'input_request')
157 145 content = msg['content']
158 146 nt.assert_equal(content['prompt'], theprompt)
159 147 text = "some text"
160 148 kc.input(text)
161 149 reply = kc.get_shell_msg(block=True, timeout=TIMEOUT)
162 150 nt.assert_equal(reply['content']['status'], 'ok')
163 151 stdout, stderr = assemble_output(iopub)
164 152 nt.assert_equal(stdout, text + "\n")
165 153
166 154
167 155 @dec.skipif(py3compat.PY3)
168 156 def test_eval_input():
169 157 """test input() on Python 2"""
170 158 with kernel() as kc:
171 159 iopub = kc.iopub_channel
172 160
173 161 input_f = "input" if py3compat.PY3 else "raw_input"
174 162 theprompt = "prompt> "
175 163 code = 'print(input("{theprompt}"))'.format(**locals())
176 164 msg_id = kc.execute(code, allow_stdin=True)
177 165 msg = kc.get_stdin_msg(block=True, timeout=TIMEOUT)
178 166 nt.assert_equal(msg['header']['msg_type'], u'input_request')
179 167 content = msg['content']
180 168 nt.assert_equal(content['prompt'], theprompt)
181 169 kc.input("1+1")
182 170 reply = kc.get_shell_msg(block=True, timeout=TIMEOUT)
183 171 nt.assert_equal(reply['content']['status'], 'ok')
184 172 stdout, stderr = assemble_output(iopub)
185 173 nt.assert_equal(stdout, "2\n")
186 174
187 175
188 176 def test_save_history():
189 177 # Saving history from the kernel with %hist -f was failing because of
190 178 # unicode problems on Python 2.
191 179 with kernel() as kc, TemporaryDirectory() as td:
192 180 file = os.path.join(td, 'hist.out')
193 181 execute(u'a=1', kc=kc)
194 182 wait_for_idle(kc)
195 183 execute(u'b=u"abcΓΎ"', kc=kc)
196 184 wait_for_idle(kc)
197 185 _, reply = execute("%hist -f " + file, kc=kc)
198 186 nt.assert_equal(reply['status'], 'ok')
199 187 with io.open(file, encoding='utf-8') as f:
200 188 content = f.read()
201 189 nt.assert_in(u'a=1', content)
202 190 nt.assert_in(u'b=u"abcΓΎ"', content)
203 191
204 192 def test_help_output():
205 193 """ipython kernel --help-all works"""
206 194 tt.help_all_output_test('kernel')
207 195
208 196 def test_is_complete():
209 197 with kernel() as kc:
210 198 # There are more test cases for this in core - here we just check
211 199 # that the kernel exposes the interface correctly.
212 200 kc.is_complete('2+2')
213 201 reply = kc.get_shell_msg(block=True, timeout=TIMEOUT)
214 202 assert reply['content']['status'] == 'complete'
215 203
216 # SyntaxError should mean it's complete
204 # SyntaxError should mean it's complete
217 205 kc.is_complete('raise = 2')
218 206 reply = kc.get_shell_msg(block=True, timeout=TIMEOUT)
219 207 assert reply['content']['status'] == 'invalid'
220 208
221 209 kc.is_complete('a = [1,\n2,')
222 210 reply = kc.get_shell_msg(block=True, timeout=TIMEOUT)
223 211 assert reply['content']['status'] == 'incomplete'
224 assert reply['content']['indent'] == '' No newline at end of file
212 assert reply['content']['indent'] == ''
213
214 def test_complete():
215 with kernel() as kc:
216 execute(u'a = 1', kc=kc)
217 wait_for_idle(kc)
218 cell = 'import IPython\nb = a.'
219 kc.complete(cell)
220 reply = kc.get_shell_msg(block=True, timeout=TIMEOUT)
221 c = reply['content']
222 nt.assert_equal(c['status'], 'ok')
223 nt.assert_equal(c['cursor_start'], cell.find('a.'))
224 nt.assert_equal(c['cursor_end'], cell.find('a.') + 2)
225 matches = c['matches']
226 nt.assert_greater(len(matches), 0)
227 for match in matches:
228 nt.assert_equal(match[:2], 'a.')
@@ -1,159 +1,161 b''
1 1 """utilities for testing IPython kernels"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import atexit
7 7
8 8 from contextlib import contextmanager
9 9 from subprocess import PIPE, STDOUT
10 10 try:
11 11 from queue import Empty # Py 3
12 12 except ImportError:
13 13 from Queue import Empty # Py 2
14 14
15 15 import nose
16 16 import nose.tools as nt
17 17
18 18 from IPython.kernel import manager
19 19
20 20 #-------------------------------------------------------------------------------
21 21 # Globals
22 22 #-------------------------------------------------------------------------------
23 23
24 24 STARTUP_TIMEOUT = 60
25 25 TIMEOUT = 15
26 26
27 27 KM = None
28 28 KC = None
29 29
30 30 #-------------------------------------------------------------------------------
31 31 # code
32 32 #-------------------------------------------------------------------------------
33 33 def start_new_kernel(**kwargs):
34 34 """start a new kernel, and return its Manager and Client
35 35
36 36 Integrates with our output capturing for tests.
37 37 """
38 38 kwargs.update(dict(stdout=nose.iptest_stdstreams_fileno(), stderr=STDOUT))
39 39 return manager.start_new_kernel(startup_timeout=STARTUP_TIMEOUT, **kwargs)
40 40
41 41 def flush_channels(kc=None):
42 42 """flush any messages waiting on the queue"""
43 43 from .test_message_spec import validate_message
44 44
45 45 if kc is None:
46 46 kc = KC
47 47 for channel in (kc.shell_channel, kc.iopub_channel):
48 48 while True:
49 49 try:
50 50 msg = channel.get_msg(block=True, timeout=0.1)
51 51 except Empty:
52 52 break
53 53 else:
54 54 validate_message(msg)
55 55
56 56
57 57 def execute(code='', kc=None, **kwargs):
58 58 """wrapper for doing common steps for validating an execution request"""
59 59 from .test_message_spec import validate_message
60 60 if kc is None:
61 61 kc = KC
62 62 msg_id = kc.execute(code=code, **kwargs)
63 63 reply = kc.get_shell_msg(timeout=TIMEOUT)
64 64 validate_message(reply, 'execute_reply', msg_id)
65 65 busy = kc.get_iopub_msg(timeout=TIMEOUT)
66 66 validate_message(busy, 'status', msg_id)
67 67 nt.assert_equal(busy['content']['execution_state'], 'busy')
68 68
69 69 if not kwargs.get('silent'):
70 70 execute_input = kc.get_iopub_msg(timeout=TIMEOUT)
71 71 validate_message(execute_input, 'execute_input', msg_id)
72 72 nt.assert_equal(execute_input['content']['code'], code)
73 73
74 74 return msg_id, reply['content']
75 75
76 76 def start_global_kernel():
77 77 """start the global kernel (if it isn't running) and return its client"""
78 78 global KM, KC
79 79 if KM is None:
80 80 KM, KC = start_new_kernel()
81 81 atexit.register(stop_global_kernel)
82 else:
83 flush_channels(KC)
82 84 return KC
83 85
84 86 @contextmanager
85 87 def kernel():
86 88 """Context manager for the global kernel instance
87 89
88 90 Should be used for most kernel tests
89 91
90 92 Returns
91 93 -------
92 94 kernel_client: connected KernelClient instance
93 95 """
94 96 yield start_global_kernel()
95 97
96 98 def uses_kernel(test_f):
97 99 """Decorator for tests that use the global kernel"""
98 100 def wrapped_test():
99 101 with kernel() as kc:
100 102 test_f(kc)
101 103 wrapped_test.__doc__ = test_f.__doc__
102 104 wrapped_test.__name__ = test_f.__name__
103 105 return wrapped_test
104 106
105 107 def stop_global_kernel():
106 108 """Stop the global shared kernel instance, if it exists"""
107 109 global KM, KC
108 110 KC.stop_channels()
109 111 KC = None
110 112 if KM is None:
111 113 return
112 114 KM.shutdown_kernel(now=True)
113 115 KM = None
114 116
115 117 def new_kernel(argv=None):
116 118 """Context manager for a new kernel in a subprocess
117 119
118 120 Should only be used for tests where the kernel must not be re-used.
119 121
120 122 Returns
121 123 -------
122 124 kernel_client: connected KernelClient instance
123 125 """
124 126 kwargs = dict(stdout=nose.iptest_stdstreams_fileno(), stderr=STDOUT,
125 127 startup_timeout=STARTUP_TIMEOUT)
126 128 if argv is not None:
127 129 kwargs['extra_arguments'] = argv
128 130 return manager.run_kernel(**kwargs)
129 131
130 132 def assemble_output(iopub):
131 133 """assemble stdout/err from an execution"""
132 134 stdout = ''
133 135 stderr = ''
134 136 while True:
135 137 msg = iopub.get_msg(block=True, timeout=1)
136 138 msg_type = msg['msg_type']
137 139 content = msg['content']
138 140 if msg_type == 'status' and content['execution_state'] == 'idle':
139 141 # idle message signals end of output
140 142 break
141 143 elif msg['msg_type'] == 'stream':
142 144 if content['name'] == 'stdout':
143 145 stdout += content['text']
144 146 elif content['name'] == 'stderr':
145 147 stderr += content['text']
146 148 else:
147 149 raise KeyError("bad stream: %r" % content['name'])
148 150 else:
149 151 # other output, ignored
150 152 pass
151 153 return stdout, stderr
152 154
153 155 def wait_for_idle(kc):
154 156 while True:
155 157 msg = kc.iopub_channel.get_msg(block=True, timeout=1)
156 158 msg_type = msg['msg_type']
157 159 content = msg['content']
158 160 if msg_type == 'status' and content['execution_state'] == 'idle':
159 161 break
@@ -1,312 +1,320 b''
1 1 """The IPython kernel implementation"""
2 2
3 3 import getpass
4 4 import sys
5 5 import traceback
6 6
7 7 from IPython.core import release
8 8 from IPython.utils.py3compat import builtin_mod, PY3
9 from IPython.utils.tokenutil import token_at_cursor
9 from IPython.utils.tokenutil import token_at_cursor, line_at_cursor
10 10 from IPython.utils.traitlets import Instance, Type, Any
11 11 from IPython.utils.decorators import undoc
12 12
13 13 from ..comm import CommManager
14 14 from .kernelbase import Kernel as KernelBase
15 15 from .serialize import serialize_object, unpack_apply_message
16 16 from .zmqshell import ZMQInteractiveShell
17 17
18 18 class IPythonKernel(KernelBase):
19 19 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
20 20 shell_class = Type(ZMQInteractiveShell)
21 21
22 22 user_module = Any()
23 23 def _user_module_changed(self, name, old, new):
24 24 if self.shell is not None:
25 25 self.shell.user_module = new
26 26
27 27 user_ns = Instance(dict, args=None, allow_none=True)
28 28 def _user_ns_changed(self, name, old, new):
29 29 if self.shell is not None:
30 30 self.shell.user_ns = new
31 31 self.shell.init_user_ns()
32 32
33 33 # A reference to the Python builtin 'raw_input' function.
34 34 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
35 35 _sys_raw_input = Any()
36 36 _sys_eval_input = Any()
37 37
38 38 def __init__(self, **kwargs):
39 39 super(IPythonKernel, self).__init__(**kwargs)
40 40
41 41 # Initialize the InteractiveShell subclass
42 42 self.shell = self.shell_class.instance(parent=self,
43 43 profile_dir = self.profile_dir,
44 44 user_module = self.user_module,
45 45 user_ns = self.user_ns,
46 46 kernel = self,
47 47 )
48 48 self.shell.displayhook.session = self.session
49 49 self.shell.displayhook.pub_socket = self.iopub_socket
50 50 self.shell.displayhook.topic = self._topic('execute_result')
51 51 self.shell.display_pub.session = self.session
52 52 self.shell.display_pub.pub_socket = self.iopub_socket
53 53 self.shell.data_pub.session = self.session
54 54 self.shell.data_pub.pub_socket = self.iopub_socket
55 55
56 56 # TMP - hack while developing
57 57 self.shell._reply_content = None
58 58
59 59 self.comm_manager = CommManager(shell=self.shell, parent=self,
60 60 kernel=self)
61 61 self.shell.configurables.append(self.comm_manager)
62 62 comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
63 63 for msg_type in comm_msg_types:
64 64 self.shell_handlers[msg_type] = getattr(self.comm_manager, msg_type)
65 65
66 66 # Kernel info fields
67 67 implementation = 'ipython'
68 68 implementation_version = release.version
69 69 language = 'python'
70 70 language_version = sys.version.split()[0]
71 71 @property
72 72 def banner(self):
73 73 return self.shell.banner
74 74
75 75 def start(self):
76 76 self.shell.exit_now = False
77 77 super(IPythonKernel, self).start()
78 78
79 79 def set_parent(self, ident, parent):
80 80 """Overridden from parent to tell the display hook and output streams
81 81 about the parent message.
82 82 """
83 83 super(IPythonKernel, self).set_parent(ident, parent)
84 84 self.shell.set_parent(parent)
85 85
86 86 def _forward_input(self, allow_stdin=False):
87 87 """Forward raw_input and getpass to the current frontend.
88 88
89 89 via input_request
90 90 """
91 91 self._allow_stdin = allow_stdin
92 92
93 93 if PY3:
94 94 self._sys_raw_input = builtin_mod.input
95 95 builtin_mod.input = self.raw_input
96 96 else:
97 97 self._sys_raw_input = builtin_mod.raw_input
98 98 self._sys_eval_input = builtin_mod.input
99 99 builtin_mod.raw_input = self.raw_input
100 100 builtin_mod.input = lambda prompt='': eval(self.raw_input(prompt))
101 101 self._save_getpass = getpass.getpass
102 102 getpass.getpass = self.getpass
103 103
104 104 def _restore_input(self):
105 105 """Restore raw_input, getpass"""
106 106 if PY3:
107 107 builtin_mod.input = self._sys_raw_input
108 108 else:
109 109 builtin_mod.raw_input = self._sys_raw_input
110 110 builtin_mod.input = self._sys_eval_input
111 111
112 112 getpass.getpass = self._save_getpass
113 113
114 114 @property
115 115 def execution_count(self):
116 116 return self.shell.execution_count
117 117
118 118 @execution_count.setter
119 119 def execution_count(self, value):
120 120 # Ignore the incrememnting done by KernelBase, in favour of our shell's
121 121 # execution counter.
122 122 pass
123 123
124 124 def do_execute(self, code, silent, store_history=True,
125 125 user_expressions=None, allow_stdin=False):
126 126 shell = self.shell # we'll need this a lot here
127 127
128 128 self._forward_input(allow_stdin)
129 129
130 130 reply_content = {}
131 131 # FIXME: the shell calls the exception handler itself.
132 132 shell._reply_content = None
133 133 try:
134 134 shell.run_cell(code, store_history=store_history, silent=silent)
135 135 except:
136 136 status = u'error'
137 137 # FIXME: this code right now isn't being used yet by default,
138 138 # because the run_cell() call above directly fires off exception
139 139 # reporting. This code, therefore, is only active in the scenario
140 140 # where runlines itself has an unhandled exception. We need to
141 141 # uniformize this, for all exception construction to come from a
142 142 # single location in the codbase.
143 143 etype, evalue, tb = sys.exc_info()
144 144 tb_list = traceback.format_exception(etype, evalue, tb)
145 145 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
146 146 else:
147 147 status = u'ok'
148 148 finally:
149 149 self._restore_input()
150 150
151 151 reply_content[u'status'] = status
152 152
153 153 # Return the execution counter so clients can display prompts
154 154 reply_content['execution_count'] = shell.execution_count - 1
155 155
156 156 # FIXME - fish exception info out of shell, possibly left there by
157 157 # runlines. We'll need to clean up this logic later.
158 158 if shell._reply_content is not None:
159 159 reply_content.update(shell._reply_content)
160 160 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
161 161 reply_content['engine_info'] = e_info
162 162 # reset after use
163 163 shell._reply_content = None
164 164
165 165 if 'traceback' in reply_content:
166 166 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
167 167
168 168
169 169 # At this point, we can tell whether the main code execution succeeded
170 170 # or not. If it did, we proceed to evaluate user_expressions
171 171 if reply_content['status'] == 'ok':
172 172 reply_content[u'user_expressions'] = \
173 173 shell.user_expressions(user_expressions or {})
174 174 else:
175 175 # If there was an error, don't even try to compute expressions
176 176 reply_content[u'user_expressions'] = {}
177 177
178 178 # Payloads should be retrieved regardless of outcome, so we can both
179 179 # recover partial output (that could have been generated early in a
180 180 # block, before an error) and clear the payload system always.
181 181 reply_content[u'payload'] = shell.payload_manager.read_payload()
182 182 # Be agressive about clearing the payload because we don't want
183 183 # it to sit in memory until the next execute_request comes in.
184 184 shell.payload_manager.clear_payload()
185 185
186 186 return reply_content
187 187
188 188 def do_complete(self, code, cursor_pos):
189 txt, matches = self.shell.complete('', code, cursor_pos)
189 # FIXME: IPython completers currently assume single line,
190 # but completion messages give multi-line context
191 # For now, extract line from cell, based on cursor_pos:
192 if cursor_pos is None:
193 cursor_pos = len(code)
194 line, offset = line_at_cursor(code, cursor_pos)
195 line_cursor = cursor_pos - offset
196
197 txt, matches = self.shell.complete('', line, line_cursor)
190 198 return {'matches' : matches,
191 199 'cursor_end' : cursor_pos,
192 200 'cursor_start' : cursor_pos - len(txt),
193 201 'metadata' : {},
194 202 'status' : 'ok'}
195 203
196 204 def do_inspect(self, code, cursor_pos, detail_level=0):
197 205 name = token_at_cursor(code, cursor_pos)
198 206 info = self.shell.object_inspect(name)
199 207
200 208 reply_content = {'status' : 'ok'}
201 209 reply_content['data'] = data = {}
202 210 reply_content['metadata'] = {}
203 211 reply_content['found'] = info['found']
204 212 if info['found']:
205 213 info_text = self.shell.object_inspect_text(
206 214 name,
207 215 detail_level=detail_level,
208 216 )
209 217 data['text/plain'] = info_text
210 218
211 219 return reply_content
212 220
213 221 def do_history(self, hist_access_type, output, raw, session=None, start=None,
214 222 stop=None, n=None, pattern=None, unique=False):
215 223 if hist_access_type == 'tail':
216 224 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
217 225 include_latest=True)
218 226
219 227 elif hist_access_type == 'range':
220 228 hist = self.shell.history_manager.get_range(session, start, stop,
221 229 raw=raw, output=output)
222 230
223 231 elif hist_access_type == 'search':
224 232 hist = self.shell.history_manager.search(
225 233 pattern, raw=raw, output=output, n=n, unique=unique)
226 234 else:
227 235 hist = []
228 236
229 237 return {'history' : list(hist)}
230 238
231 239 def do_shutdown(self, restart):
232 240 self.shell.exit_now = True
233 241 return dict(status='ok', restart=restart)
234 242
235 243 def do_is_complete(self, code):
236 244 status, indent_spaces = self.shell.input_transformer_manager.check_complete(code)
237 245 r = {'status': status}
238 246 if status == 'incomplete':
239 247 r['indent'] = ' ' * indent_spaces
240 248 return r
241 249
242 250 def do_apply(self, content, bufs, msg_id, reply_metadata):
243 251 shell = self.shell
244 252 try:
245 253 working = shell.user_ns
246 254
247 255 prefix = "_"+str(msg_id).replace("-","")+"_"
248 256
249 257 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
250 258
251 259 fname = getattr(f, '__name__', 'f')
252 260
253 261 fname = prefix+"f"
254 262 argname = prefix+"args"
255 263 kwargname = prefix+"kwargs"
256 264 resultname = prefix+"result"
257 265
258 266 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
259 267 # print ns
260 268 working.update(ns)
261 269 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
262 270 try:
263 271 exec(code, shell.user_global_ns, shell.user_ns)
264 272 result = working.get(resultname)
265 273 finally:
266 274 for key in ns:
267 275 working.pop(key)
268 276
269 277 result_buf = serialize_object(result,
270 278 buffer_threshold=self.session.buffer_threshold,
271 279 item_threshold=self.session.item_threshold,
272 280 )
273 281
274 282 except:
275 283 # invoke IPython traceback formatting
276 284 shell.showtraceback()
277 285 # FIXME - fish exception info out of shell, possibly left there by
278 286 # run_code. We'll need to clean up this logic later.
279 287 reply_content = {}
280 288 if shell._reply_content is not None:
281 289 reply_content.update(shell._reply_content)
282 290 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
283 291 reply_content['engine_info'] = e_info
284 292 # reset after use
285 293 shell._reply_content = None
286 294
287 295 self.send_response(self.iopub_socket, u'error', reply_content,
288 296 ident=self._topic('error'))
289 297 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
290 298 result_buf = []
291 299
292 300 if reply_content['ename'] == 'UnmetDependency':
293 301 reply_metadata['dependencies_met'] = False
294 302 else:
295 303 reply_content = {'status' : 'ok'}
296 304
297 305 return reply_content, result_buf
298 306
299 307 def do_clear(self):
300 308 self.shell.reset(False)
301 309 return dict(status='ok')
302 310
303 311
304 312 # This exists only for backwards compatibility - use IPythonKernel instead
305 313
306 314 @undoc
307 315 class Kernel(IPythonKernel):
308 316 def __init__(self, *args, **kwargs):
309 317 import warnings
310 318 warnings.warn('Kernel is a deprecated alias of IPython.kernel.zmq.ipkernel.IPythonKernel',
311 319 DeprecationWarning)
312 320 super(Kernel, self).__init__(*args, **kwargs) No newline at end of file
@@ -1,80 +1,108 b''
1 1 """Token-related utilities"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 from __future__ import absolute_import, print_function
7 7
8 8 from collections import namedtuple
9 9 from io import StringIO
10 10 from keyword import iskeyword
11 11
12 12 from . import tokenize2
13 13 from .py3compat import cast_unicode_py2
14 14
15 15 Token = namedtuple('Token', ['token', 'text', 'start', 'end', 'line'])
16 16
17 17 def generate_tokens(readline):
18 18 """wrap generate_tokens to catch EOF errors"""
19 19 try:
20 20 for token in tokenize2.generate_tokens(readline):
21 21 yield token
22 22 except tokenize2.TokenError:
23 23 # catch EOF error
24 24 return
25 25
26 def line_at_cursor(cell, cursor_pos=0):
27 """Return the line in a cell at a given cursor position
28
29 Used for calling line-based APIs that don't support multi-line input, yet.
30
31 Parameters
32 ----------
33
34 cell: text
35 multiline block of text
36 cursor_pos: integer
37 the cursor position
38
39 Returns
40 -------
41
42 (line, offset): (text, integer)
43 The line with the current cursor, and the character offset of the start of the line.
44 """
45 offset = 0
46 lines = cell.splitlines(True)
47 for line in lines:
48 next_offset = offset + len(line)
49 if next_offset >= cursor_pos:
50 break
51 offset = next_offset
52 return (line, offset)
53
26 54 def token_at_cursor(cell, cursor_pos=0):
27 55 """Get the token at a given cursor
28 56
29 57 Used for introspection.
30 58
31 59 Parameters
32 60 ----------
33 61
34 62 cell : unicode
35 63 A block of Python code
36 64 cursor_pos : int
37 65 The location of the cursor in the block where the token should be found
38 66 """
39 67 cell = cast_unicode_py2(cell)
40 68 names = []
41 69 tokens = []
42 70 offset = 0
43 71 for tup in generate_tokens(StringIO(cell).readline):
44 72
45 73 tok = Token(*tup)
46 74
47 75 # token, text, start, end, line = tup
48 76 start_col = tok.start[1]
49 77 end_col = tok.end[1]
50 78 # allow '|foo' to find 'foo' at the beginning of a line
51 79 boundary = cursor_pos + 1 if start_col == 0 else cursor_pos
52 80 if offset + start_col >= boundary:
53 81 # current token starts after the cursor,
54 82 # don't consume it
55 83 break
56 84
57 85 if tok.token == tokenize2.NAME and not iskeyword(tok.text):
58 86 if names and tokens and tokens[-1].token == tokenize2.OP and tokens[-1].text == '.':
59 87 names[-1] = "%s.%s" % (names[-1], tok.text)
60 88 else:
61 89 names.append(tok.text)
62 90 elif tok.token == tokenize2.OP:
63 91 if tok.text == '=' and names:
64 92 # don't inspect the lhs of an assignment
65 93 names.pop(-1)
66 94
67 95 if offset + end_col > cursor_pos:
68 96 # we found the cursor, stop reading
69 97 break
70 98
71 99 tokens.append(tok)
72 100 if tok.token == tokenize2.NEWLINE:
73 101 offset += len(tok.line)
74 102
75 103 if names:
76 104 return names[-1]
77 105 else:
78 106 return ''
79 107
80 108
General Comments 0
You need to be logged in to leave comments. Login now