##// END OF EJS Templates
update zmq shell magics...
MinRK -
Show More
@@ -16,11 +16,9 b' machinery. This should thus be thought of as scaffolding.'
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib
18 # Stdlib
19 import inspect
20 import os
19 import os
21 import sys
20 import sys
22 import time
21 import time
23 from subprocess import Popen, PIPE
24
22
25 # System library imports
23 # System library imports
26 from zmq.eventloop import ioloop
24 from zmq.eventloop import ioloop
@@ -29,11 +27,11 b' from zmq.eventloop import ioloop'
29 from IPython.core.interactiveshell import (
27 from IPython.core.interactiveshell import (
30 InteractiveShell, InteractiveShellABC
28 InteractiveShell, InteractiveShellABC
31 )
29 )
32 from IPython.core import page, pylabtools
30 from IPython.core import page
33 from IPython.core.autocall import ZMQExitAutocall
31 from IPython.core.autocall import ZMQExitAutocall
34 from IPython.core.displaypub import DisplayPublisher
32 from IPython.core.displaypub import DisplayPublisher
35 from IPython.core.macro import Macro
33 from IPython.core.magics import MacroToEdit, CodeMagics
36 from IPython.core.magics import MacroToEdit
34 from IPython.core.magic import magics_class, line_magic, Magics
37 from IPython.core.payloadpage import install_payload_page
35 from IPython.core.payloadpage import install_payload_page
38 from IPython.lib.kernel import (
36 from IPython.lib.kernel import (
39 get_connection_file, get_connection_info, connect_qtconsole
37 get_connection_file, get_connection_info, connect_qtconsole
@@ -41,7 +39,6 b' from IPython.lib.kernel import ('
41 from IPython.testing.skipdoctest import skip_doctest
39 from IPython.testing.skipdoctest import skip_doctest
42 from IPython.utils import io
40 from IPython.utils import io
43 from IPython.utils.jsonutil import json_clean
41 from IPython.utils.jsonutil import json_clean
44 from IPython.utils.path import get_py_filename
45 from IPython.utils.process import arg_split
42 from IPython.utils.process import arg_split
46 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes
43 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes
47 from IPython.utils.warn import warn, error
44 from IPython.utils.warn import warn, error
@@ -99,106 +96,8 b' class ZMQDisplayPublisher(DisplayPublisher):'
99 parent=self.parent_header, ident=self.topic,
96 parent=self.parent_header, ident=self.topic,
100 )
97 )
101
98
102 class ZMQInteractiveShell(InteractiveShell):
99 @magics_class
103 """A subclass of InteractiveShell for ZMQ."""
100 class KernelMagics(Magics):
104
105 displayhook_class = Type(ZMQShellDisplayHook)
106 display_pub_class = Type(ZMQDisplayPublisher)
107
108 # Override the traitlet in the parent class, because there's no point using
109 # readline for the kernel. Can be removed when the readline code is moved
110 # to the terminal frontend.
111 colors_force = CBool(True)
112 readline_use = CBool(False)
113 # autoindent has no meaning in a zmqshell, and attempting to enable it
114 # will print a warning in the absence of readline.
115 autoindent = CBool(False)
116
117 exiter = Instance(ZMQExitAutocall)
118 def _exiter_default(self):
119 return ZMQExitAutocall(self)
120
121 def _exit_now_changed(self, name, old, new):
122 """stop eventloop when exit_now fires"""
123 if new:
124 loop = ioloop.IOLoop.instance()
125 loop.add_timeout(time.time()+0.1, loop.stop)
126
127 keepkernel_on_exit = None
128
129 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
130 # interactive input being read; we provide event loop support in ipkernel
131 from .eventloops import enable_gui
132 enable_gui = staticmethod(enable_gui)
133
134 def init_environment(self):
135 """Configure the user's environment.
136
137 """
138 env = os.environ
139 # These two ensure 'ls' produces nice coloring on BSD-derived systems
140 env['TERM'] = 'xterm-color'
141 env['CLICOLOR'] = '1'
142 # Since normal pagers don't work at all (over pexpect we don't have
143 # single-key control of the subprocess), try to disable paging in
144 # subprocesses as much as possible.
145 env['PAGER'] = 'cat'
146 env['GIT_PAGER'] = 'cat'
147
148 # And install the payload version of page.
149 install_payload_page()
150
151 def auto_rewrite_input(self, cmd):
152 """Called to show the auto-rewritten input for autocall and friends.
153
154 FIXME: this payload is currently not correctly processed by the
155 frontend.
156 """
157 new = self.prompt_manager.render('rewrite') + cmd
158 payload = dict(
159 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
160 transformed_input=new,
161 )
162 self.payload_manager.write_payload(payload)
163
164 def ask_exit(self):
165 """Engage the exit actions."""
166 self.exit_now = True
167 payload = dict(
168 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
169 exit=True,
170 keepkernel=self.keepkernel_on_exit,
171 )
172 self.payload_manager.write_payload(payload)
173
174 def _showtraceback(self, etype, evalue, stb):
175
176 exc_content = {
177 u'traceback' : stb,
178 u'ename' : unicode(etype.__name__),
179 u'evalue' : unicode(evalue)
180 }
181
182 dh = self.displayhook
183 # Send exception info over pub socket for other clients than the caller
184 # to pick up
185 topic = None
186 if dh.topic:
187 topic = dh.topic.replace(b'pyout', b'pyerr')
188
189 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header, ident=topic)
190
191 # FIXME - Hack: store exception info in shell object. Right now, the
192 # caller is reading this info after the fact, we need to fix this logic
193 # to remove this hack. Even uglier, we need to store the error status
194 # here, because in the main loop, the logic that sets it is being
195 # skipped because runlines swallows the exceptions.
196 exc_content[u'status'] = u'error'
197 self._reply_content = exc_content
198 # /FIXME
199
200 return exc_content
201
202 #------------------------------------------------------------------------
101 #------------------------------------------------------------------------
203 # Magic overrides
102 # Magic overrides
204 #------------------------------------------------------------------------
103 #------------------------------------------------------------------------
@@ -207,7 +106,8 b' class ZMQInteractiveShell(InteractiveShell):'
207 # the magics which this class needs to implement differently from the base
106 # the magics which this class needs to implement differently from the base
208 # class, or that are unique to it.
107 # class, or that are unique to it.
209
108
210 def magic_doctest_mode(self,parameter_s=''):
109 @line_magic
110 def doctest_mode(self, parameter_s=''):
211 """Toggle doctest mode on and off.
111 """Toggle doctest mode on and off.
212
112
213 This mode is intended to make IPython behave as much as possible like a
113 This mode is intended to make IPython behave as much as possible like a
@@ -253,12 +153,12 b' class ZMQInteractiveShell(InteractiveShell):'
253 # turn on
153 # turn on
254 ptformatter.pprint = False
154 ptformatter.pprint = False
255 disp_formatter.plain_text_only = True
155 disp_formatter.plain_text_only = True
256 shell.magic_xmode('Plain')
156 shell.magic('xmode Plain')
257 else:
157 else:
258 # turn off
158 # turn off
259 ptformatter.pprint = dstore.rc_pprint
159 ptformatter.pprint = dstore.rc_pprint
260 disp_formatter.plain_text_only = dstore.rc_plain_text_only
160 disp_formatter.plain_text_only = dstore.rc_plain_text_only
261 shell.magic_xmode(dstore.xmode)
161 shell.magic("xmode " + dstore.xmode)
262
162
263 # Store new mode and inform on console
163 # Store new mode and inform on console
264 dstore.mode = bool(1-int(mode))
164 dstore.mode = bool(1-int(mode))
@@ -267,12 +167,16 b' class ZMQInteractiveShell(InteractiveShell):'
267
167
268 # Send the payload back so that clients can modify their prompt display
168 # Send the payload back so that clients can modify their prompt display
269 payload = dict(
169 payload = dict(
270 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
170 source='IPython.zmq.zmqshell.ZMQInteractiveShell.doctest_mode',
271 mode=dstore.mode)
171 mode=dstore.mode)
272 self.payload_manager.write_payload(payload)
172 shell.payload_manager.write_payload(payload)
173
174
175 _find_edit_target = CodeMagics._find_edit_target
273
176
274 @skip_doctest
177 @skip_doctest
275 def magic_edit(self,parameter_s='',last_call=['','']):
178 @line_magic
179 def edit(self, parameter_s='', last_call=['','']):
276 """Bring up an editor and execute the resulting code.
180 """Bring up an editor and execute the resulting code.
277
181
278 Usage:
182 Usage:
@@ -404,7 +308,7 b' class ZMQInteractiveShell(InteractiveShell):'
404 opts,args = self.parse_options(parameter_s,'prn:')
308 opts,args = self.parse_options(parameter_s,'prn:')
405
309
406 try:
310 try:
407 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
311 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
408 except MacroToEdit as e:
312 except MacroToEdit as e:
409 # TODO: Implement macro editing over 2 processes.
313 # TODO: Implement macro editing over 2 processes.
410 print("Macro editing not yet implemented in 2-process model.")
314 print("Macro editing not yet implemented in 2-process model.")
@@ -419,12 +323,13 b' class ZMQInteractiveShell(InteractiveShell):'
419 'filename' : filename,
323 'filename' : filename,
420 'line_number' : lineno
324 'line_number' : lineno
421 }
325 }
422 self.payload_manager.write_payload(payload)
326 self.shell.payload_manager.write_payload(payload)
423
327
424 # A few magics that are adapted to the specifics of using pexpect and a
328 # A few magics that are adapted to the specifics of using pexpect and a
425 # remote terminal
329 # remote terminal
426
330
427 def magic_clear(self, arg_s):
331 @line_magic
332 def clear(self, arg_s):
428 """Clear the terminal."""
333 """Clear the terminal."""
429 if os.name == 'posix':
334 if os.name == 'posix':
430 self.shell.system("clear")
335 self.shell.system("clear")
@@ -433,11 +338,12 b' class ZMQInteractiveShell(InteractiveShell):'
433
338
434 if os.name == 'nt':
339 if os.name == 'nt':
435 # This is the usual name in windows
340 # This is the usual name in windows
436 magic_cls = magic_clear
341 cls = line_magic('cls')(clear)
437
342
438 # Terminal pagers won't work over pexpect, but we do have our own pager
343 # Terminal pagers won't work over pexpect, but we do have our own pager
439
344
440 def magic_less(self, arg_s):
345 @line_magic
346 def less(self, arg_s):
441 """Show a file through the pager.
347 """Show a file through the pager.
442
348
443 Files ending in .py are syntax-highlighted."""
349 Files ending in .py are syntax-highlighted."""
@@ -446,11 +352,12 b' class ZMQInteractiveShell(InteractiveShell):'
446 cont = self.shell.pycolorize(cont)
352 cont = self.shell.pycolorize(cont)
447 page.page(cont)
353 page.page(cont)
448
354
449 magic_more = magic_less
355 more = line_magic('more')(less)
450
356
451 # Man calls a pager, so we also need to redefine it
357 # Man calls a pager, so we also need to redefine it
452 if os.name == 'posix':
358 if os.name == 'posix':
453 def magic_man(self, arg_s):
359 @line_magic
360 def man(self, arg_s):
454 """Find the man page for the given command and display in pager."""
361 """Find the man page for the given command and display in pager."""
455 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
362 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
456 split=False))
363 split=False))
@@ -459,12 +366,15 b' class ZMQInteractiveShell(InteractiveShell):'
459 # magics at startup that are only for the gui. Once the gui app has proper
366 # magics at startup that are only for the gui. Once the gui app has proper
460 # profile and configuration management, we can have it initialize a kernel
367 # profile and configuration management, we can have it initialize a kernel
461 # with a special config file that provides these.
368 # with a special config file that provides these.
462 def magic_guiref(self, arg_s):
369
370 @line_magic
371 def guiref(self, arg_s):
463 """Show a basic reference about the GUI console."""
372 """Show a basic reference about the GUI console."""
464 from IPython.core.usage import gui_reference
373 from IPython.core.usage import gui_reference
465 page.page(gui_reference, auto_html=True)
374 page.page(gui_reference, auto_html=True)
466
375
467 def magic_connect_info(self, arg_s):
376 @line_magic
377 def connect_info(self, arg_s):
468 """Print information for connecting other clients to this kernel
378 """Print information for connecting other clients to this kernel
469
379
470 It will print the contents of this session's connection file, as well as
380 It will print the contents of this session's connection file, as well as
@@ -514,7 +424,8 b' class ZMQInteractiveShell(InteractiveShell):'
514 )
424 )
515 )
425 )
516
426
517 def magic_qtconsole(self, arg_s):
427 @line_magic
428 def qtconsole(self, arg_s):
518 """Open a qtconsole connected to this kernel.
429 """Open a qtconsole connected to this kernel.
519
430
520 Useful for connecting a qtconsole to running notebooks, for better
431 Useful for connecting a qtconsole to running notebooks, for better
@@ -526,6 +437,107 b' class ZMQInteractiveShell(InteractiveShell):'
526 error("Could not start qtconsole: %r" % e)
437 error("Could not start qtconsole: %r" % e)
527 return
438 return
528
439
440
441 class ZMQInteractiveShell(InteractiveShell):
442 """A subclass of InteractiveShell for ZMQ."""
443
444 displayhook_class = Type(ZMQShellDisplayHook)
445 display_pub_class = Type(ZMQDisplayPublisher)
446
447 # Override the traitlet in the parent class, because there's no point using
448 # readline for the kernel. Can be removed when the readline code is moved
449 # to the terminal frontend.
450 colors_force = CBool(True)
451 readline_use = CBool(False)
452 # autoindent has no meaning in a zmqshell, and attempting to enable it
453 # will print a warning in the absence of readline.
454 autoindent = CBool(False)
455
456 exiter = Instance(ZMQExitAutocall)
457 def _exiter_default(self):
458 return ZMQExitAutocall(self)
459
460 def _exit_now_changed(self, name, old, new):
461 """stop eventloop when exit_now fires"""
462 if new:
463 loop = ioloop.IOLoop.instance()
464 loop.add_timeout(time.time()+0.1, loop.stop)
465
466 keepkernel_on_exit = None
467
468 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
469 # interactive input being read; we provide event loop support in ipkernel
470 from .eventloops import enable_gui
471 enable_gui = staticmethod(enable_gui)
472
473 def init_environment(self):
474 """Configure the user's environment.
475
476 """
477 env = os.environ
478 # These two ensure 'ls' produces nice coloring on BSD-derived systems
479 env['TERM'] = 'xterm-color'
480 env['CLICOLOR'] = '1'
481 # Since normal pagers don't work at all (over pexpect we don't have
482 # single-key control of the subprocess), try to disable paging in
483 # subprocesses as much as possible.
484 env['PAGER'] = 'cat'
485 env['GIT_PAGER'] = 'cat'
486
487 # And install the payload version of page.
488 install_payload_page()
489
490 def auto_rewrite_input(self, cmd):
491 """Called to show the auto-rewritten input for autocall and friends.
492
493 FIXME: this payload is currently not correctly processed by the
494 frontend.
495 """
496 new = self.prompt_manager.render('rewrite') + cmd
497 payload = dict(
498 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
499 transformed_input=new,
500 )
501 self.payload_manager.write_payload(payload)
502
503 def ask_exit(self):
504 """Engage the exit actions."""
505 self.exit_now = True
506 payload = dict(
507 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
508 exit=True,
509 keepkernel=self.keepkernel_on_exit,
510 )
511 self.payload_manager.write_payload(payload)
512
513 def _showtraceback(self, etype, evalue, stb):
514
515 exc_content = {
516 u'traceback' : stb,
517 u'ename' : unicode(etype.__name__),
518 u'evalue' : unicode(evalue)
519 }
520
521 dh = self.displayhook
522 # Send exception info over pub socket for other clients than the caller
523 # to pick up
524 topic = None
525 if dh.topic:
526 topic = dh.topic.replace(b'pyout', b'pyerr')
527
528 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header, ident=topic)
529
530 # FIXME - Hack: store exception info in shell object. Right now, the
531 # caller is reading this info after the fact, we need to fix this logic
532 # to remove this hack. Even uglier, we need to store the error status
533 # here, because in the main loop, the logic that sets it is being
534 # skipped because runlines swallows the exceptions.
535 exc_content[u'status'] = u'error'
536 self._reply_content = exc_content
537 # /FIXME
538
539 return exc_content
540
529 def set_next_input(self, text):
541 def set_next_input(self, text):
530 """Send the specified text to the frontend to be presented at the next
542 """Send the specified text to the frontend to be presented at the next
531 input cell."""
543 input cell."""
@@ -534,6 +546,15 b' class ZMQInteractiveShell(InteractiveShell):'
534 text=text
546 text=text
535 )
547 )
536 self.payload_manager.write_payload(payload)
548 self.payload_manager.write_payload(payload)
549
550 #-------------------------------------------------------------------------
551 # Things related to magics
552 #-------------------------------------------------------------------------
553
554 def init_magics(self):
555 super(ZMQInteractiveShell, self).init_magics()
556 self.register_magics(KernelMagics)
557
537
558
538
559
539 InteractiveShellABC.register(ZMQInteractiveShell)
560 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now