##// END OF EJS Templates
update %connect_info magic to cover non-default cases...
MinRK -
Show More
@@ -1,561 +1,581 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 34 from IPython.lib import pylabtools
35 35 from IPython.lib.kernel import (
36 36 get_connection_file, get_connection_info, connect_qtconsole
37 37 )
38 38 from IPython.utils import io
39 39 from IPython.utils.jsonutil import json_clean
40 40 from IPython.utils.path import get_py_filename
41 41 from IPython.utils.process import arg_split
42 42 from IPython.utils.traitlets import Instance, Type, Dict, CBool
43 43 from IPython.utils.warn import warn, error
44 44 from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary
45 45 from IPython.zmq.session import extract_header
46 46 from session import Session
47 47
48 48 #-----------------------------------------------------------------------------
49 49 # Globals and side-effects
50 50 #-----------------------------------------------------------------------------
51 51
52 52 # Install the payload version of page.
53 53 install_payload_page()
54 54
55 55 #-----------------------------------------------------------------------------
56 56 # Functions and classes
57 57 #-----------------------------------------------------------------------------
58 58
59 59 class ZMQDisplayPublisher(DisplayPublisher):
60 60 """A display publisher that publishes data using a ZeroMQ PUB socket."""
61 61
62 62 session = Instance(Session)
63 63 pub_socket = Instance('zmq.Socket')
64 64 parent_header = Dict({})
65 65
66 66 def set_parent(self, parent):
67 67 """Set the parent for outbound messages."""
68 68 self.parent_header = extract_header(parent)
69 69
70 70 def publish(self, source, data, metadata=None):
71 71 if metadata is None:
72 72 metadata = {}
73 73 self._validate_data(source, data, metadata)
74 74 content = {}
75 75 content['source'] = source
76 76 _encode_binary(data)
77 77 content['data'] = data
78 78 content['metadata'] = metadata
79 79 self.session.send(
80 80 self.pub_socket, u'display_data', json_clean(content),
81 81 parent=self.parent_header
82 82 )
83 83
84 84 def clear_output(self, stdout=True, stderr=True, other=True):
85 85 content = dict(stdout=stdout, stderr=stderr, other=other)
86 86 self.session.send(
87 87 self.pub_socket, u'clear_output', content,
88 88 parent=self.parent_header
89 89 )
90 90
91 91 class ZMQInteractiveShell(InteractiveShell):
92 92 """A subclass of InteractiveShell for ZMQ."""
93 93
94 94 displayhook_class = Type(ZMQShellDisplayHook)
95 95 display_pub_class = Type(ZMQDisplayPublisher)
96 96
97 97 # Override the traitlet in the parent class, because there's no point using
98 98 # readline for the kernel. Can be removed when the readline code is moved
99 99 # to the terminal frontend.
100 100 colors_force = CBool(True)
101 101 readline_use = CBool(False)
102 102 # autoindent has no meaning in a zmqshell, and attempting to enable it
103 103 # will print a warning in the absence of readline.
104 104 autoindent = CBool(False)
105 105
106 106 exiter = Instance(ZMQExitAutocall)
107 107 def _exiter_default(self):
108 108 return ZMQExitAutocall(self)
109 109
110 110 keepkernel_on_exit = None
111 111
112 112 def init_environment(self):
113 113 """Configure the user's environment.
114 114
115 115 """
116 116 env = os.environ
117 117 # These two ensure 'ls' produces nice coloring on BSD-derived systems
118 118 env['TERM'] = 'xterm-color'
119 119 env['CLICOLOR'] = '1'
120 120 # Since normal pagers don't work at all (over pexpect we don't have
121 121 # single-key control of the subprocess), try to disable paging in
122 122 # subprocesses as much as possible.
123 123 env['PAGER'] = 'cat'
124 124 env['GIT_PAGER'] = 'cat'
125 125
126 126 def auto_rewrite_input(self, cmd):
127 127 """Called to show the auto-rewritten input for autocall and friends.
128 128
129 129 FIXME: this payload is currently not correctly processed by the
130 130 frontend.
131 131 """
132 132 new = self.displayhook.prompt1.auto_rewrite() + cmd
133 133 payload = dict(
134 134 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
135 135 transformed_input=new,
136 136 )
137 137 self.payload_manager.write_payload(payload)
138 138
139 139 def ask_exit(self):
140 140 """Engage the exit actions."""
141 141 payload = dict(
142 142 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
143 143 exit=True,
144 144 keepkernel=self.keepkernel_on_exit,
145 145 )
146 146 self.payload_manager.write_payload(payload)
147 147
148 148 def _showtraceback(self, etype, evalue, stb):
149 149
150 150 exc_content = {
151 151 u'traceback' : stb,
152 152 u'ename' : unicode(etype.__name__),
153 153 u'evalue' : unicode(evalue)
154 154 }
155 155
156 156 dh = self.displayhook
157 157 # Send exception info over pub socket for other clients than the caller
158 158 # to pick up
159 159 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header)
160 160
161 161 # FIXME - Hack: store exception info in shell object. Right now, the
162 162 # caller is reading this info after the fact, we need to fix this logic
163 163 # to remove this hack. Even uglier, we need to store the error status
164 164 # here, because in the main loop, the logic that sets it is being
165 165 # skipped because runlines swallows the exceptions.
166 166 exc_content[u'status'] = u'error'
167 167 self._reply_content = exc_content
168 168 # /FIXME
169 169
170 170 return exc_content
171 171
172 172 #------------------------------------------------------------------------
173 173 # Magic overrides
174 174 #------------------------------------------------------------------------
175 175 # Once the base class stops inheriting from magic, this code needs to be
176 176 # moved into a separate machinery as well. For now, at least isolate here
177 177 # the magics which this class needs to implement differently from the base
178 178 # class, or that are unique to it.
179 179
180 180 def magic_doctest_mode(self,parameter_s=''):
181 181 """Toggle doctest mode on and off.
182 182
183 183 This mode is intended to make IPython behave as much as possible like a
184 184 plain Python shell, from the perspective of how its prompts, exceptions
185 185 and output look. This makes it easy to copy and paste parts of a
186 186 session into doctests. It does so by:
187 187
188 188 - Changing the prompts to the classic ``>>>`` ones.
189 189 - Changing the exception reporting mode to 'Plain'.
190 190 - Disabling pretty-printing of output.
191 191
192 192 Note that IPython also supports the pasting of code snippets that have
193 193 leading '>>>' and '...' prompts in them. This means that you can paste
194 194 doctests from files or docstrings (even if they have leading
195 195 whitespace), and the code will execute correctly. You can then use
196 196 '%history -t' to see the translated history; this will give you the
197 197 input after removal of all the leading prompts and whitespace, which
198 198 can be pasted back into an editor.
199 199
200 200 With these features, you can switch into this mode easily whenever you
201 201 need to do testing and changes to doctests, without having to leave
202 202 your existing IPython session.
203 203 """
204 204
205 205 from IPython.utils.ipstruct import Struct
206 206
207 207 # Shorthands
208 208 shell = self.shell
209 209 disp_formatter = self.shell.display_formatter
210 210 ptformatter = disp_formatter.formatters['text/plain']
211 211 # dstore is a data store kept in the instance metadata bag to track any
212 212 # changes we make, so we can undo them later.
213 213 dstore = shell.meta.setdefault('doctest_mode', Struct())
214 214 save_dstore = dstore.setdefault
215 215
216 216 # save a few values we'll need to recover later
217 217 mode = save_dstore('mode', False)
218 218 save_dstore('rc_pprint', ptformatter.pprint)
219 219 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
220 220 save_dstore('xmode', shell.InteractiveTB.mode)
221 221
222 222 if mode == False:
223 223 # turn on
224 224 ptformatter.pprint = False
225 225 disp_formatter.plain_text_only = True
226 226 shell.magic_xmode('Plain')
227 227 else:
228 228 # turn off
229 229 ptformatter.pprint = dstore.rc_pprint
230 230 disp_formatter.plain_text_only = dstore.rc_plain_text_only
231 231 shell.magic_xmode(dstore.xmode)
232 232
233 233 # Store new mode and inform on console
234 234 dstore.mode = bool(1-int(mode))
235 235 mode_label = ['OFF','ON'][dstore.mode]
236 236 print('Doctest mode is:', mode_label)
237 237
238 238 # Send the payload back so that clients can modify their prompt display
239 239 payload = dict(
240 240 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
241 241 mode=dstore.mode)
242 242 self.payload_manager.write_payload(payload)
243 243
244 244 def magic_edit(self,parameter_s='',last_call=['','']):
245 245 """Bring up an editor and execute the resulting code.
246 246
247 247 Usage:
248 248 %edit [options] [args]
249 249
250 250 %edit runs an external text editor. You will need to set the command for
251 251 this editor via the ``TerminalInteractiveShell.editor`` option in your
252 252 configuration file before it will work.
253 253
254 254 This command allows you to conveniently edit multi-line code right in
255 255 your IPython session.
256 256
257 257 If called without arguments, %edit opens up an empty editor with a
258 258 temporary file and will execute the contents of this file when you
259 259 close it (don't forget to save it!).
260 260
261 261
262 262 Options:
263 263
264 264 -n <number>: open the editor at a specified line number. By default,
265 265 the IPython editor hook uses the unix syntax 'editor +N filename', but
266 266 you can configure this by providing your own modified hook if your
267 267 favorite editor supports line-number specifications with a different
268 268 syntax.
269 269
270 270 -p: this will call the editor with the same data as the previous time
271 271 it was used, regardless of how long ago (in your current session) it
272 272 was.
273 273
274 274 -r: use 'raw' input. This option only applies to input taken from the
275 275 user's history. By default, the 'processed' history is used, so that
276 276 magics are loaded in their transformed version to valid Python. If
277 277 this option is given, the raw input as typed as the command line is
278 278 used instead. When you exit the editor, it will be executed by
279 279 IPython's own processor.
280 280
281 281 -x: do not execute the edited code immediately upon exit. This is
282 282 mainly useful if you are editing programs which need to be called with
283 283 command line arguments, which you can then do using %run.
284 284
285 285
286 286 Arguments:
287 287
288 288 If arguments are given, the following possibilites exist:
289 289
290 290 - The arguments are numbers or pairs of colon-separated numbers (like
291 291 1 4:8 9). These are interpreted as lines of previous input to be
292 292 loaded into the editor. The syntax is the same of the %macro command.
293 293
294 294 - If the argument doesn't start with a number, it is evaluated as a
295 295 variable and its contents loaded into the editor. You can thus edit
296 296 any string which contains python code (including the result of
297 297 previous edits).
298 298
299 299 - If the argument is the name of an object (other than a string),
300 300 IPython will try to locate the file where it was defined and open the
301 301 editor at the point where it is defined. You can use `%edit function`
302 302 to load an editor exactly at the point where 'function' is defined,
303 303 edit it and have the file be executed automatically.
304 304
305 305 If the object is a macro (see %macro for details), this opens up your
306 306 specified editor with a temporary file containing the macro's data.
307 307 Upon exit, the macro is reloaded with the contents of the file.
308 308
309 309 Note: opening at an exact line is only supported under Unix, and some
310 310 editors (like kedit and gedit up to Gnome 2.8) do not understand the
311 311 '+NUMBER' parameter necessary for this feature. Good editors like
312 312 (X)Emacs, vi, jed, pico and joe all do.
313 313
314 314 - If the argument is not found as a variable, IPython will look for a
315 315 file with that name (adding .py if necessary) and load it into the
316 316 editor. It will execute its contents with execfile() when you exit,
317 317 loading any code in the file into your interactive namespace.
318 318
319 319 After executing your code, %edit will return as output the code you
320 320 typed in the editor (except when it was an existing file). This way
321 321 you can reload the code in further invocations of %edit as a variable,
322 322 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
323 323 the output.
324 324
325 325 Note that %edit is also available through the alias %ed.
326 326
327 327 This is an example of creating a simple function inside the editor and
328 328 then modifying it. First, start up the editor:
329 329
330 330 In [1]: ed
331 331 Editing... done. Executing edited code...
332 332 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
333 333
334 334 We can then call the function foo():
335 335
336 336 In [2]: foo()
337 337 foo() was defined in an editing session
338 338
339 339 Now we edit foo. IPython automatically loads the editor with the
340 340 (temporary) file where foo() was previously defined:
341 341
342 342 In [3]: ed foo
343 343 Editing... done. Executing edited code...
344 344
345 345 And if we call foo() again we get the modified version:
346 346
347 347 In [4]: foo()
348 348 foo() has now been changed!
349 349
350 350 Here is an example of how to edit a code snippet successive
351 351 times. First we call the editor:
352 352
353 353 In [5]: ed
354 354 Editing... done. Executing edited code...
355 355 hello
356 356 Out[5]: "print 'hello'n"
357 357
358 358 Now we call it again with the previous output (stored in _):
359 359
360 360 In [6]: ed _
361 361 Editing... done. Executing edited code...
362 362 hello world
363 363 Out[6]: "print 'hello world'n"
364 364
365 365 Now we call it with the output #8 (stored in _8, also as Out[8]):
366 366
367 367 In [7]: ed _8
368 368 Editing... done. Executing edited code...
369 369 hello again
370 370 Out[7]: "print 'hello again'n"
371 371 """
372 372
373 373 opts,args = self.parse_options(parameter_s,'prn:')
374 374
375 375 try:
376 376 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
377 377 except MacroToEdit as e:
378 378 # TODO: Implement macro editing over 2 processes.
379 379 print("Macro editing not yet implemented in 2-process model.")
380 380 return
381 381
382 382 # Make sure we send to the client an absolute path, in case the working
383 383 # directory of client and kernel don't match
384 384 filename = os.path.abspath(filename)
385 385
386 386 payload = {
387 387 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
388 388 'filename' : filename,
389 389 'line_number' : lineno
390 390 }
391 391 self.payload_manager.write_payload(payload)
392 392
393 393 def magic_gui(self, parameter_s=''):
394 394 """Enable or disable IPython GUI event loop integration.
395 395
396 396 %gui [GUINAME]
397 397
398 398 This magic replaces IPython's threaded shells that were activated
399 399 using the (pylab/wthread/etc.) command line flags. GUI toolkits
400 400 can now be enabled at runtime and keyboard
401 401 interrupts should work without any problems. The following toolkits
402 402 are supported: wxPython, PyQt4, PyGTK, Cocoa, and Tk::
403 403
404 404 %gui wx # enable wxPython event loop integration
405 405 %gui qt4|qt # enable PyQt4 event loop integration
406 406 %gui gtk # enable PyGTK event loop integration
407 407 %gui OSX # enable Cocoa event loop integration (requires matplotlib 1.1)
408 408 %gui tk # enable Tk event loop integration
409 409
410 410 WARNING: after any of these has been called you can simply create
411 411 an application object, but DO NOT start the event loop yourself, as
412 412 we have already handled that.
413 413 """
414 414 from IPython.zmq.ipkernel import enable_gui
415 415 opts, arg = self.parse_options(parameter_s, '')
416 416 if arg=='': arg = None
417 417 try:
418 418 enable_gui(arg)
419 419 except Exception as e:
420 420 # print simple error message, rather than traceback if we can't
421 421 # hook up the GUI
422 422 error(str(e))
423 423
424 424 def enable_pylab(self, gui=None, import_all=True):
425 425 """Activate pylab support at runtime.
426 426
427 427 This turns on support for matplotlib, preloads into the interactive
428 428 namespace all of numpy and pylab, and configures IPython to correcdtly
429 429 interact with the GUI event loop. The GUI backend to be used can be
430 430 optionally selected with the optional :param:`gui` argument.
431 431
432 432 Parameters
433 433 ----------
434 434 gui : optional, string [default: inline]
435 435
436 436 If given, dictates the choice of matplotlib GUI backend to use
437 437 (should be one of IPython's supported backends, 'inline', 'qt', 'osx',
438 438 'tk', or 'gtk'), otherwise we use the default chosen by matplotlib
439 439 (as dictated by the matplotlib build-time options plus the user's
440 440 matplotlibrc configuration file).
441 441 """
442 442 from IPython.zmq.ipkernel import enable_gui
443 443 # We want to prevent the loading of pylab to pollute the user's
444 444 # namespace as shown by the %who* magics, so we execute the activation
445 445 # code in an empty namespace, and we update *both* user_ns and
446 446 # user_ns_hidden with this information.
447 447 ns = {}
448 448 try:
449 449 gui = pylabtools.pylab_activate(ns, gui, import_all, self)
450 450 except KeyError:
451 451 error("Backend %r not supported" % gui)
452 452 return
453 453 self.user_ns.update(ns)
454 454 self.user_ns_hidden.update(ns)
455 455 # Now we must activate the gui pylab wants to use, and fix %run to take
456 456 # plot updates into account
457 457 try:
458 458 enable_gui(gui)
459 459 except Exception as e:
460 460 # print simple error message, rather than traceback if we can't
461 461 # hook up the GUI
462 462 error(str(e))
463 463 self.magic_run = self._pylab_magic_run
464 464
465 465
466 466 # A few magics that are adapted to the specifics of using pexpect and a
467 467 # remote terminal
468 468
469 469 def magic_clear(self, arg_s):
470 470 """Clear the terminal."""
471 471 if os.name == 'posix':
472 472 self.shell.system("clear")
473 473 else:
474 474 self.shell.system("cls")
475 475
476 476 if os.name == 'nt':
477 477 # This is the usual name in windows
478 478 magic_cls = magic_clear
479 479
480 480 # Terminal pagers won't work over pexpect, but we do have our own pager
481 481
482 482 def magic_less(self, arg_s):
483 483 """Show a file through the pager.
484 484
485 485 Files ending in .py are syntax-highlighted."""
486 486 cont = open(arg_s).read()
487 487 if arg_s.endswith('.py'):
488 488 cont = self.shell.pycolorize(cont)
489 489 page.page(cont)
490 490
491 491 magic_more = magic_less
492 492
493 493 # Man calls a pager, so we also need to redefine it
494 494 if os.name == 'posix':
495 495 def magic_man(self, arg_s):
496 496 """Find the man page for the given command and display in pager."""
497 497 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
498 498 split=False))
499 499
500 500 # FIXME: this is specific to the GUI, so we should let the gui app load
501 501 # magics at startup that are only for the gui. Once the gui app has proper
502 502 # profile and configuration management, we can have it initialize a kernel
503 503 # with a special config file that provides these.
504 504 def magic_guiref(self, arg_s):
505 505 """Show a basic reference about the GUI console."""
506 506 from IPython.core.usage import gui_reference
507 507 page.page(gui_reference, auto_html=True)
508 508
509 509 def magic_connect_info(self, arg_s):
510 510 """Print information for connecting other clients to this kernel
511 511
512 512 It will print the contents of this session's connection file, as well as
513 513 shortcuts for local clients.
514 514
515 515 In the simplest case, when called from the most recently launched kernel,
516 516 secondary clients can be connected, simply with:
517 517
518 518 $> ipython <app> --existing
519 519
520 520 """
521
522 from IPython.core.application import BaseIPythonApplication as BaseIPApp
523
524 if BaseIPApp.initialized():
525 app = BaseIPApp.instance()
526 security_dir = app.profile_dir.security_dir
527 profile = app.profile
528 else:
529 profile = 'default'
530 security_dir = ''
531
521 532 try:
522 533 connection_file = get_connection_file()
523 534 info = get_connection_info(unpack=False)
524 535 except Exception as e:
525 536 error("Could not get connection info: %r" % e)
526 537 return
527
538
539 # add profile flag for non-default profile
540 profile_flag = "--profile %s" % profile if profile != 'default' else ""
541
542 # if it's in the security dir, truncate to basename
543 if security_dir == os.path.dirname(connection_file):
544 connection_file = os.path.basename(connection_file)
545
546
528 547 print (info + '\n')
529 548 print ("Paste the above JSON into a file, and connect with:\n"
530 549 " $> ipython <app> --existing <file>\n"
531 550 "or, if you are local, you can connect with just:\n"
532 " $> ipython <app> --existing %s\n"
551 " $> ipython <app> --existing {0} {1}\n"
533 552 "or even just:\n"
534 " $> ipython <app> --existing\n"
535 "if this is the most recent IPython session you have started."
536 % os.path.basename(connection_file)
553 " $> ipython <app> --existing {1}\n"
554 "if this is the most recent IPython session you have started.".format(
555 connection_file, profile_flag
556 )
537 557 )
538 558
539 559 def magic_qtconsole(self, arg_s):
540 560 """Open a qtconsole connected to this kernel.
541 561
542 562 Useful for connecting a qtconsole to running notebooks, for better
543 563 debugging.
544 564 """
545 565 try:
546 566 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
547 567 except Exception as e:
548 568 error("Could not start qtconsole: %r" % e)
549 569 return
550 570
551 571
552 572 def set_next_input(self, text):
553 573 """Send the specified text to the frontend to be presented at the next
554 574 input cell."""
555 575 payload = dict(
556 576 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
557 577 text=text
558 578 )
559 579 self.payload_manager.write_payload(payload)
560 580
561 581 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now