##// END OF EJS Templates
add IPython.lib.kernel...
MinRK -
Show More
@@ -0,0 +1,99 b''
1 """Utilities for connecting to kernels
2
3 Authors:
4
5 * Min Ragan-Kelley
6
7 """
8
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2011 The IPython Development Team
11 #
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
15
16 #-----------------------------------------------------------------------------
17 # Imports
18 #-----------------------------------------------------------------------------
19
20 import json
21 import sys
22 from subprocess import Popen, PIPE
23
24 from IPython.utils.path import filefind
25 from IPython.utils.py3compat import str_to_bytes
26
27
28 #-----------------------------------------------------------------------------
29 # Functions
30 #-----------------------------------------------------------------------------
31
32 def get_connection_file(app=None):
33 """Return the path to the connection file of an app
34
35 Parameters
36 ----------
37 app : KernelApp instance [optional]
38 If unspecified, the currently running app will be used
39 """
40 if app is None:
41 from IPython.zmq.kernelapp import KernelApp
42 if not KernelApp.initialized():
43 raise RuntimeError("app not specified, and not in a running Kernel")
44
45 app = KernelApp.instance()
46 return filefind(app.connection_file, ['.', app.profile_dir.security_dir])
47
48 def get_connection_info(unpack=False):
49 """Return the connection information for the current Kernel.
50
51 Parameters
52 ----------
53 unpack : bool [default: False]
54 if True, return the unpacked dict, otherwise just the string contents
55 of the file.
56
57 Returns
58 -------
59 The connection dictionary of the current kernel, as string or dict,
60 depending on `unpack`.
61 """
62 cf = get_connection_file()
63 with open(cf) as f:
64 info = f.read()
65
66 if unpack:
67 info = json.loads(info)
68 # ensure key is bytes:
69 info['key'] = str_to_bytes(info.get('key', ''))
70 return info
71
72 def connect_qtconsole(argv=None):
73 """Connect a qtconsole to the current kernel.
74
75 This is useful for connecting a second qtconsole to a kernel, or to a
76 local notebook.
77
78 Parameters
79 ----------
80 argv : list [optional]
81 Any extra args to be passed to the console.
82
83 Returns
84 -------
85 subprocess.Popen instance running the qtconsole frontend
86 """
87 argv = [] if argv is None else argv
88
89 # get connection file from current kernel
90 cf = get_connection_file()
91
92 cmd = ';'.join([
93 "from IPython.frontend.qt.console import qtconsoleapp",
94 "qtconsoleapp.main()"
95 ])
96
97 return Popen([sys.executable, '-c', cmd, '--existing', cf] + argv, stdout=PIPE, stderr=PIPE)
98
99
@@ -1,497 +1,489 b''
1 1 """A ZMQ-based subclass of InteractiveShell.
2 2
3 3 This code is meant to ease the refactoring of the base InteractiveShell into
4 4 something with a cleaner architecture for 2-process use, without actually
5 5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 6 we subclass and override what we want to fix. Once this is working well, we
7 7 can go back to the base class and refactor the code for a cleaner inheritance
8 8 implementation that doesn't rely on so much monkeypatching.
9 9
10 10 But this lets us maintain a fully working IPython as we develop the new
11 11 machinery. This should thus be thought of as scaffolding.
12 12 """
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # Stdlib
19 19 import inspect
20 20 import os
21 21 import sys
22 22 from subprocess import Popen, PIPE
23 23
24 24 # Our own
25 25 from IPython.core.interactiveshell import (
26 26 InteractiveShell, InteractiveShellABC
27 27 )
28 28 from IPython.core import page
29 29 from IPython.core.autocall import ZMQExitAutocall
30 30 from IPython.core.displaypub import DisplayPublisher
31 31 from IPython.core.macro import Macro
32 32 from IPython.core.magic import MacroToEdit
33 33 from IPython.core.payloadpage import install_payload_page
34 from IPython.lib.kernel import (
35 get_connection_file, get_connection_info, connect_qtconsole
36 )
34 37 from IPython.utils import io
35 38 from IPython.utils.jsonutil import json_clean
36 39 from IPython.utils.path import get_py_filename
40 from IPython.utils.process import arg_split
37 41 from IPython.utils.traitlets import Instance, Type, Dict, CBool
38 42 from IPython.utils.warn import warn, error
39 43 from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary
40 44 from IPython.zmq.session import extract_header
41 45 from session import Session
42 46
43 47 #-----------------------------------------------------------------------------
44 48 # Globals and side-effects
45 49 #-----------------------------------------------------------------------------
46 50
47 51 # Install the payload version of page.
48 52 install_payload_page()
49 53
50 54 #-----------------------------------------------------------------------------
51 55 # Functions and classes
52 56 #-----------------------------------------------------------------------------
53 57
54 58 class ZMQDisplayPublisher(DisplayPublisher):
55 59 """A display publisher that publishes data using a ZeroMQ PUB socket."""
56 60
57 61 session = Instance(Session)
58 62 pub_socket = Instance('zmq.Socket')
59 63 parent_header = Dict({})
60 64
61 65 def set_parent(self, parent):
62 66 """Set the parent for outbound messages."""
63 67 self.parent_header = extract_header(parent)
64 68
65 69 def publish(self, source, data, metadata=None):
66 70 if metadata is None:
67 71 metadata = {}
68 72 self._validate_data(source, data, metadata)
69 73 content = {}
70 74 content['source'] = source
71 75 _encode_binary(data)
72 76 content['data'] = data
73 77 content['metadata'] = metadata
74 78 self.session.send(
75 79 self.pub_socket, u'display_data', json_clean(content),
76 80 parent=self.parent_header
77 81 )
78 82
79 83
80 84 class ZMQInteractiveShell(InteractiveShell):
81 85 """A subclass of InteractiveShell for ZMQ."""
82 86
83 87 displayhook_class = Type(ZMQShellDisplayHook)
84 88 display_pub_class = Type(ZMQDisplayPublisher)
85 89
86 90 # Override the traitlet in the parent class, because there's no point using
87 91 # readline for the kernel. Can be removed when the readline code is moved
88 92 # to the terminal frontend.
89 93 colors_force = CBool(True)
90 94 readline_use = CBool(False)
91 95 # autoindent has no meaning in a zmqshell, and attempting to enable it
92 96 # will print a warning in the absence of readline.
93 97 autoindent = CBool(False)
94 98
95 99 exiter = Instance(ZMQExitAutocall)
96 100 def _exiter_default(self):
97 101 return ZMQExitAutocall(self)
98 102
99 103 keepkernel_on_exit = None
100 104
101 105 def init_environment(self):
102 106 """Configure the user's environment.
103 107
104 108 """
105 109 env = os.environ
106 110 # These two ensure 'ls' produces nice coloring on BSD-derived systems
107 111 env['TERM'] = 'xterm-color'
108 112 env['CLICOLOR'] = '1'
109 113 # Since normal pagers don't work at all (over pexpect we don't have
110 114 # single-key control of the subprocess), try to disable paging in
111 115 # subprocesses as much as possible.
112 116 env['PAGER'] = 'cat'
113 117 env['GIT_PAGER'] = 'cat'
114 118
115 119 def auto_rewrite_input(self, cmd):
116 120 """Called to show the auto-rewritten input for autocall and friends.
117 121
118 122 FIXME: this payload is currently not correctly processed by the
119 123 frontend.
120 124 """
121 125 new = self.displayhook.prompt1.auto_rewrite() + cmd
122 126 payload = dict(
123 127 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
124 128 transformed_input=new,
125 129 )
126 130 self.payload_manager.write_payload(payload)
127 131
128 132 def ask_exit(self):
129 133 """Engage the exit actions."""
130 134 payload = dict(
131 135 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
132 136 exit=True,
133 137 keepkernel=self.keepkernel_on_exit,
134 138 )
135 139 self.payload_manager.write_payload(payload)
136 140
137 141 def _showtraceback(self, etype, evalue, stb):
138 142
139 143 exc_content = {
140 144 u'traceback' : stb,
141 145 u'ename' : unicode(etype.__name__),
142 146 u'evalue' : unicode(evalue)
143 147 }
144 148
145 149 dh = self.displayhook
146 150 # Send exception info over pub socket for other clients than the caller
147 151 # to pick up
148 152 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header)
149 153
150 154 # FIXME - Hack: store exception info in shell object. Right now, the
151 155 # caller is reading this info after the fact, we need to fix this logic
152 156 # to remove this hack. Even uglier, we need to store the error status
153 157 # here, because in the main loop, the logic that sets it is being
154 158 # skipped because runlines swallows the exceptions.
155 159 exc_content[u'status'] = u'error'
156 160 self._reply_content = exc_content
157 161 # /FIXME
158 162
159 163 return exc_content
160 164
161 165 #------------------------------------------------------------------------
162 166 # Magic overrides
163 167 #------------------------------------------------------------------------
164 168 # Once the base class stops inheriting from magic, this code needs to be
165 169 # moved into a separate machinery as well. For now, at least isolate here
166 170 # the magics which this class needs to implement differently from the base
167 171 # class, or that are unique to it.
168 172
169 173 def magic_doctest_mode(self,parameter_s=''):
170 174 """Toggle doctest mode on and off.
171 175
172 176 This mode is intended to make IPython behave as much as possible like a
173 177 plain Python shell, from the perspective of how its prompts, exceptions
174 178 and output look. This makes it easy to copy and paste parts of a
175 179 session into doctests. It does so by:
176 180
177 181 - Changing the prompts to the classic ``>>>`` ones.
178 182 - Changing the exception reporting mode to 'Plain'.
179 183 - Disabling pretty-printing of output.
180 184
181 185 Note that IPython also supports the pasting of code snippets that have
182 186 leading '>>>' and '...' prompts in them. This means that you can paste
183 187 doctests from files or docstrings (even if they have leading
184 188 whitespace), and the code will execute correctly. You can then use
185 189 '%history -t' to see the translated history; this will give you the
186 190 input after removal of all the leading prompts and whitespace, which
187 191 can be pasted back into an editor.
188 192
189 193 With these features, you can switch into this mode easily whenever you
190 194 need to do testing and changes to doctests, without having to leave
191 195 your existing IPython session.
192 196 """
193 197
194 198 from IPython.utils.ipstruct import Struct
195 199
196 200 # Shorthands
197 201 shell = self.shell
198 202 disp_formatter = self.shell.display_formatter
199 203 ptformatter = disp_formatter.formatters['text/plain']
200 204 # dstore is a data store kept in the instance metadata bag to track any
201 205 # changes we make, so we can undo them later.
202 206 dstore = shell.meta.setdefault('doctest_mode', Struct())
203 207 save_dstore = dstore.setdefault
204 208
205 209 # save a few values we'll need to recover later
206 210 mode = save_dstore('mode', False)
207 211 save_dstore('rc_pprint', ptformatter.pprint)
208 212 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
209 213 save_dstore('xmode', shell.InteractiveTB.mode)
210 214
211 215 if mode == False:
212 216 # turn on
213 217 ptformatter.pprint = False
214 218 disp_formatter.plain_text_only = True
215 219 shell.magic_xmode('Plain')
216 220 else:
217 221 # turn off
218 222 ptformatter.pprint = dstore.rc_pprint
219 223 disp_formatter.plain_text_only = dstore.rc_plain_text_only
220 224 shell.magic_xmode(dstore.xmode)
221 225
222 226 # Store new mode and inform on console
223 227 dstore.mode = bool(1-int(mode))
224 228 mode_label = ['OFF','ON'][dstore.mode]
225 229 print('Doctest mode is:', mode_label)
226 230
227 231 # Send the payload back so that clients can modify their prompt display
228 232 payload = dict(
229 233 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
230 234 mode=dstore.mode)
231 235 self.payload_manager.write_payload(payload)
232 236
233 237 def magic_edit(self,parameter_s='',last_call=['','']):
234 238 """Bring up an editor and execute the resulting code.
235 239
236 240 Usage:
237 241 %edit [options] [args]
238 242
239 243 %edit runs an external text editor. You will need to set the command for
240 244 this editor via the ``TerminalInteractiveShell.editor`` option in your
241 245 configuration file before it will work.
242 246
243 247 This command allows you to conveniently edit multi-line code right in
244 248 your IPython session.
245 249
246 250 If called without arguments, %edit opens up an empty editor with a
247 251 temporary file and will execute the contents of this file when you
248 252 close it (don't forget to save it!).
249 253
250 254
251 255 Options:
252 256
253 257 -n <number>: open the editor at a specified line number. By default,
254 258 the IPython editor hook uses the unix syntax 'editor +N filename', but
255 259 you can configure this by providing your own modified hook if your
256 260 favorite editor supports line-number specifications with a different
257 261 syntax.
258 262
259 263 -p: this will call the editor with the same data as the previous time
260 264 it was used, regardless of how long ago (in your current session) it
261 265 was.
262 266
263 267 -r: use 'raw' input. This option only applies to input taken from the
264 268 user's history. By default, the 'processed' history is used, so that
265 269 magics are loaded in their transformed version to valid Python. If
266 270 this option is given, the raw input as typed as the command line is
267 271 used instead. When you exit the editor, it will be executed by
268 272 IPython's own processor.
269 273
270 274 -x: do not execute the edited code immediately upon exit. This is
271 275 mainly useful if you are editing programs which need to be called with
272 276 command line arguments, which you can then do using %run.
273 277
274 278
275 279 Arguments:
276 280
277 281 If arguments are given, the following possibilites exist:
278 282
279 283 - The arguments are numbers or pairs of colon-separated numbers (like
280 284 1 4:8 9). These are interpreted as lines of previous input to be
281 285 loaded into the editor. The syntax is the same of the %macro command.
282 286
283 287 - If the argument doesn't start with a number, it is evaluated as a
284 288 variable and its contents loaded into the editor. You can thus edit
285 289 any string which contains python code (including the result of
286 290 previous edits).
287 291
288 292 - If the argument is the name of an object (other than a string),
289 293 IPython will try to locate the file where it was defined and open the
290 294 editor at the point where it is defined. You can use `%edit function`
291 295 to load an editor exactly at the point where 'function' is defined,
292 296 edit it and have the file be executed automatically.
293 297
294 298 If the object is a macro (see %macro for details), this opens up your
295 299 specified editor with a temporary file containing the macro's data.
296 300 Upon exit, the macro is reloaded with the contents of the file.
297 301
298 302 Note: opening at an exact line is only supported under Unix, and some
299 303 editors (like kedit and gedit up to Gnome 2.8) do not understand the
300 304 '+NUMBER' parameter necessary for this feature. Good editors like
301 305 (X)Emacs, vi, jed, pico and joe all do.
302 306
303 307 - If the argument is not found as a variable, IPython will look for a
304 308 file with that name (adding .py if necessary) and load it into the
305 309 editor. It will execute its contents with execfile() when you exit,
306 310 loading any code in the file into your interactive namespace.
307 311
308 312 After executing your code, %edit will return as output the code you
309 313 typed in the editor (except when it was an existing file). This way
310 314 you can reload the code in further invocations of %edit as a variable,
311 315 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
312 316 the output.
313 317
314 318 Note that %edit is also available through the alias %ed.
315 319
316 320 This is an example of creating a simple function inside the editor and
317 321 then modifying it. First, start up the editor:
318 322
319 323 In [1]: ed
320 324 Editing... done. Executing edited code...
321 325 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
322 326
323 327 We can then call the function foo():
324 328
325 329 In [2]: foo()
326 330 foo() was defined in an editing session
327 331
328 332 Now we edit foo. IPython automatically loads the editor with the
329 333 (temporary) file where foo() was previously defined:
330 334
331 335 In [3]: ed foo
332 336 Editing... done. Executing edited code...
333 337
334 338 And if we call foo() again we get the modified version:
335 339
336 340 In [4]: foo()
337 341 foo() has now been changed!
338 342
339 343 Here is an example of how to edit a code snippet successive
340 344 times. First we call the editor:
341 345
342 346 In [5]: ed
343 347 Editing... done. Executing edited code...
344 348 hello
345 349 Out[5]: "print 'hello'n"
346 350
347 351 Now we call it again with the previous output (stored in _):
348 352
349 353 In [6]: ed _
350 354 Editing... done. Executing edited code...
351 355 hello world
352 356 Out[6]: "print 'hello world'n"
353 357
354 358 Now we call it with the output #8 (stored in _8, also as Out[8]):
355 359
356 360 In [7]: ed _8
357 361 Editing... done. Executing edited code...
358 362 hello again
359 363 Out[7]: "print 'hello again'n"
360 364 """
361 365
362 366 opts,args = self.parse_options(parameter_s,'prn:')
363 367
364 368 try:
365 369 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
366 370 except MacroToEdit as e:
367 371 # TODO: Implement macro editing over 2 processes.
368 372 print("Macro editing not yet implemented in 2-process model.")
369 373 return
370 374
371 375 # Make sure we send to the client an absolute path, in case the working
372 376 # directory of client and kernel don't match
373 377 filename = os.path.abspath(filename)
374 378
375 379 payload = {
376 380 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
377 381 'filename' : filename,
378 382 'line_number' : lineno
379 383 }
380 384 self.payload_manager.write_payload(payload)
381 385
382 386 def magic_gui(self, *args, **kwargs):
383 387 raise NotImplementedError(
384 388 'Kernel GUI support is not implemented yet, except for --pylab.')
385 389
386 390 def magic_pylab(self, *args, **kwargs):
387 391 raise NotImplementedError(
388 392 'pylab support must be enabled in command line options.')
389 393
390 394 # A few magics that are adapted to the specifics of using pexpect and a
391 395 # remote terminal
392 396
393 397 def magic_clear(self, arg_s):
394 398 """Clear the terminal."""
395 399 if os.name == 'posix':
396 400 self.shell.system("clear")
397 401 else:
398 402 self.shell.system("cls")
399 403
400 404 if os.name == 'nt':
401 405 # This is the usual name in windows
402 406 magic_cls = magic_clear
403 407
404 408 # Terminal pagers won't work over pexpect, but we do have our own pager
405 409
406 410 def magic_less(self, arg_s):
407 411 """Show a file through the pager.
408 412
409 413 Files ending in .py are syntax-highlighted."""
410 414 cont = open(arg_s).read()
411 415 if arg_s.endswith('.py'):
412 416 cont = self.shell.pycolorize(cont)
413 417 page.page(cont)
414 418
415 419 magic_more = magic_less
416 420
417 421 # Man calls a pager, so we also need to redefine it
418 422 if os.name == 'posix':
419 423 def magic_man(self, arg_s):
420 424 """Find the man page for the given command and display in pager."""
421 425 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
422 426 split=False))
423 427
424 428 # FIXME: this is specific to the GUI, so we should let the gui app load
425 429 # magics at startup that are only for the gui. Once the gui app has proper
426 430 # profile and configuration management, we can have it initialize a kernel
427 431 # with a special config file that provides these.
428 432 def magic_guiref(self, arg_s):
429 433 """Show a basic reference about the GUI console."""
430 434 from IPython.core.usage import gui_reference
431 435 page.page(gui_reference, auto_html=True)
432 436
433 437 def magic_connect_info(self, arg_s):
434 438 """Print information for connecting other clients to this kernel
435 439
436 440 It will print the contents of this session's connection file, as well as
437 441 shortcuts for local clients.
438 442
439 443 In the simplest case, when called from the most recently launched kernel,
440 444 secondary clients can be connected, simply with:
441 445
442 446 $> ipython <app> --existing
443 447
444 448 """
445 from IPython.zmq.kernelapp import KernelApp
446 if not KernelApp.initialized():
447 error("KernelApp is not initialized. I cannot find the connection info")
448 return
449 app = KernelApp.instance()
450 449 try:
451 with open(app.connection_file) as f:
452 s = f.read()
450 connection_file = get_connection_file()
451 info = get_connection_info(unpack=False)
453 452 except Exception as e:
454 error("Could not read connection file: %s" % e)
453 error("Could not get connection info: %r" % e)
455 454 return
456 print (s + '\n')
455
456 print (info + '\n')
457 457 print ("Paste the above JSON into a file, and connect with:\n"
458 458 " $> ipython <app> --existing <file>\n"
459 459 "or, if you are local, you can connect with just:\n"
460 460 " $> ipython <app> --existing %s\n"
461 461 "or even just:\n"
462 462 " $> ipython <app> --existing\n"
463 463 "if this is the most recent IPython session you have started."
464 % os.path.basename((app.connection_file))
464 % os.path.basename(connection_file)
465 465 )
466 466
467 467 def magic_qtconsole(self, arg_s):
468 468 """Open a qtconsole connected to this kernel.
469 469
470 470 Useful for connecting a qtconsole to running notebooks, for better
471 471 debugging.
472 472 """
473 from IPython.zmq.kernelapp import KernelApp
474
475 if not KernelApp.initialized():
476 error("KernelApp is not initialized. %qtconsole magic must be run from a Kernel")
473 try:
474 p = connect_qtconsole(arg_split(arg_s, os.name=='posix'))
475 except Exception as e:
476 error("Could not start qtconsole: %r" % e)
477 477 return
478 app = KernelApp.instance()
479
480 cmd = ';'.join([
481 "from IPython.frontend.qt.console import qtconsoleapp",
482 "qtconsoleapp.main()"
483 ])
484 478
485 return Popen([sys.executable, '-c', cmd, '--existing', app.connection_file],
486 stdout=PIPE,stderr=PIPE)
487 479
488 480 def set_next_input(self, text):
489 481 """Send the specified text to the frontend to be presented at the next
490 482 input cell."""
491 483 payload = dict(
492 484 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
493 485 text=text
494 486 )
495 487 self.payload_manager.write_payload(payload)
496 488
497 489 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now