##// END OF EJS Templates
enable %gui/%pylab magics in the Kernel...
MinRK -
Show More
@@ -289,7 +289,7 b' def import_pylab(user_ns, backend, import_all=True, shell=None):'
289 exec s in shell.user_ns_hidden
289 exec s in shell.user_ns_hidden
290
290
291
291
292 def pylab_activate(user_ns, gui=None, import_all=True):
292 def pylab_activate(user_ns, gui=None, import_all=True, shell=None):
293 """Activate pylab mode in the user's namespace.
293 """Activate pylab mode in the user's namespace.
294
294
295 Loads and initializes numpy, matplotlib and friends for interactive use.
295 Loads and initializes numpy, matplotlib and friends for interactive use.
@@ -312,7 +312,7 b' def pylab_activate(user_ns, gui=None, import_all=True):'
312 """
312 """
313 gui, backend = find_gui_and_backend(gui)
313 gui, backend = find_gui_and_backend(gui)
314 activate_matplotlib(backend)
314 activate_matplotlib(backend)
315 import_pylab(user_ns, backend, import_all)
315 import_pylab(user_ns, backend, import_all, shell)
316
316
317 print """
317 print """
318 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
318 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
@@ -22,6 +22,7 b' import sys'
22 import time
22 import time
23 import traceback
23 import traceback
24 import logging
24 import logging
25
25 # System library imports.
26 # System library imports.
26 import zmq
27 import zmq
27
28
@@ -38,7 +39,7 b' from IPython.utils import py3compat'
38 from IPython.utils.jsonutil import json_clean
39 from IPython.utils.jsonutil import json_clean
39 from IPython.lib import pylabtools
40 from IPython.lib import pylabtools
40 from IPython.utils.traitlets import (
41 from IPython.utils.traitlets import (
41 List, Instance, Float, Dict, Bool, Int, Unicode, CaselessStrEnum
42 Any, List, Instance, Float, Dict, Bool, Int, Unicode, CaselessStrEnum
42 )
43 )
43
44
44 from entry_point import base_launch_kernel
45 from entry_point import base_launch_kernel
@@ -58,6 +59,9 b' class Kernel(Configurable):'
58 # Kernel interface
59 # Kernel interface
59 #---------------------------------------------------------------------------
60 #---------------------------------------------------------------------------
60
61
62 # attribute to override with a GUI
63 eventloop = Any(None)
64
61 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
65 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
62 session = Instance(Session)
66 session = Instance(Session)
63 shell_socket = Instance('zmq.Socket')
67 shell_socket = Instance('zmq.Socket')
@@ -164,7 +168,8 b' class Kernel(Configurable):'
164 """
168 """
165 poller = zmq.Poller()
169 poller = zmq.Poller()
166 poller.register(self.shell_socket, zmq.POLLIN)
170 poller.register(self.shell_socket, zmq.POLLIN)
167 while True:
171 # loop while self.eventloop has not been overridden
172 while self.eventloop is None:
168 try:
173 try:
169 # scale by extra factor of 10, because there is no
174 # scale by extra factor of 10, because there is no
170 # reason for this to be anything less than ~ 0.1s
175 # reason for this to be anything less than ~ 0.1s
@@ -181,6 +186,13 b' class Kernel(Configurable):'
181 except KeyboardInterrupt:
186 except KeyboardInterrupt:
182 # Ctrl-C shouldn't crash the kernel
187 # Ctrl-C shouldn't crash the kernel
183 io.raw_print("KeyboardInterrupt caught in kernel")
188 io.raw_print("KeyboardInterrupt caught in kernel")
189 if self.eventloop is not None:
190 try:
191 self.eventloop(self)
192 except KeyboardInterrupt:
193 # Ctrl-C shouldn't crash the kernel
194 io.raw_print("KeyboardInterrupt caught in kernel")
195
184
196
185 def record_ports(self, ports):
197 def record_ports(self, ports):
186 """Record the ports that this kernel is using.
198 """Record the ports that this kernel is using.
@@ -496,36 +508,35 b' class Kernel(Configurable):'
496 time.sleep(0.01)
508 time.sleep(0.01)
497
509
498
510
499 class QtKernel(Kernel):
511 #------------------------------------------------------------------------------
500 """A Kernel subclass with Qt support."""
512 # Eventloops for integrating the Kernel into different GUIs
513 #------------------------------------------------------------------------------
501
514
502 def start(self):
515
503 """Start a kernel with QtPy4 event loop integration."""
516 def loop_qt4(kernel):
517 """Start a kernel with PyQt4 event loop integration."""
504
518
505 from IPython.external.qt_for_kernel import QtCore
519 from IPython.external.qt_for_kernel import QtCore
506 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
520 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
507
521
508 self.app = get_app_qt4([" "])
522 kernel.app = get_app_qt4([" "])
509 self.app.setQuitOnLastWindowClosed(False)
523 kernel.app.setQuitOnLastWindowClosed(False)
510 self.timer = QtCore.QTimer()
524 kernel.timer = QtCore.QTimer()
511 self.timer.timeout.connect(self.do_one_iteration)
525 kernel.timer.timeout.connect(kernel.do_one_iteration)
512 # Units for the timer are in milliseconds
526 # Units for the timer are in milliseconds
513 self.timer.start(1000*self._poll_interval)
527 kernel.timer.start(1000*kernel._poll_interval)
514 start_event_loop_qt4(self.app)
528 start_event_loop_qt4(kernel.app)
515
529
516
530
517 class WxKernel(Kernel):
531 def loop_wx(kernel):
518 """A Kernel subclass with Wx support."""
519
520 def start(self):
521 """Start a kernel with wx event loop support."""
532 """Start a kernel with wx event loop support."""
522
533
523 import wx
534 import wx
524 from IPython.lib.guisupport import start_event_loop_wx
535 from IPython.lib.guisupport import start_event_loop_wx
525
536
526 doi = self.do_one_iteration
537 doi = kernel.do_one_iteration
527 # Wx uses milliseconds
538 # Wx uses milliseconds
528 poll_interval = int(1000*self._poll_interval)
539 poll_interval = int(1000*kernel._poll_interval)
529
540
530 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
541 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
531 # We make the Frame hidden when we create it in the main app below.
542 # We make the Frame hidden when we create it in the main app below.
@@ -551,20 +562,17 b' class WxKernel(Kernel):'
551
562
552 # The redirect=False here makes sure that wx doesn't replace
563 # The redirect=False here makes sure that wx doesn't replace
553 # sys.stdout/stderr with its own classes.
564 # sys.stdout/stderr with its own classes.
554 self.app = IPWxApp(redirect=False)
565 kernel.app = IPWxApp(redirect=False)
555 start_event_loop_wx(self.app)
566 start_event_loop_wx(kernel.app)
556
557
567
558 class TkKernel(Kernel):
559 """A Kernel subclass with Tk support."""
560
568
561 def start(self):
569 def loop_tk(kernel):
562 """Start a Tk enabled event loop."""
570 """Start a kernel with the Tk event loop."""
563
571
564 import Tkinter
572 import Tkinter
565 doi = self.do_one_iteration
573 doi = kernel.do_one_iteration
566 # Tk uses milliseconds
574 # Tk uses milliseconds
567 poll_interval = int(1000*self._poll_interval)
575 poll_interval = int(1000*kernel._poll_interval)
568 # For Tkinter, we create a Tk object and call its withdraw method.
576 # For Tkinter, we create a Tk object and call its withdraw method.
569 class Timer(object):
577 class Timer(object):
570 def __init__(self, func):
578 def __init__(self, func):
@@ -580,43 +588,37 b' class TkKernel(Kernel):'
580 self.on_timer() # Call it once to get things going.
588 self.on_timer() # Call it once to get things going.
581 self.app.mainloop()
589 self.app.mainloop()
582
590
583 self.timer = Timer(doi)
591 kernel.timer = Timer(doi)
584 self.timer.start()
592 kernel.timer.start()
585
586
593
587 class GTKKernel(Kernel):
588 """A Kernel subclass with GTK support."""
589
594
590 def start(self):
595 def loop_gtk(kernel):
591 """Start the kernel, coordinating with the GTK event loop"""
596 """Start the kernel, coordinating with the GTK event loop"""
592 from .gui.gtkembed import GTKEmbed
597 from .gui.gtkembed import GTKEmbed
593
598
594 gtk_kernel = GTKEmbed(self)
599 gtk_kernel = GTKEmbed(kernel)
595 gtk_kernel.start()
600 gtk_kernel.start()
596
601
597
602
598 class OSXKernel(TkKernel):
603 def loop_cocoa(kernel):
599 """A Kernel subclass with Cocoa support via the matplotlib OSX backend."""
600
601 def start(self):
602 """Start the kernel, coordinating with the Cocoa CFRunLoop event loop
604 """Start the kernel, coordinating with the Cocoa CFRunLoop event loop
603 via the matplotlib MacOSX backend.
605 via the matplotlib MacOSX backend.
604 """
606 """
605 import matplotlib
607 import matplotlib
606 if matplotlib.__version__ < '1.1.0':
608 if matplotlib.__version__ < '1.1.0':
607 self.log.warn(
609 kernel.log.warn(
608 "MacOSX backend in matplotlib %s doesn't have a Timer, "
610 "MacOSX backend in matplotlib %s doesn't have a Timer, "
609 "falling back on Tk for CFRunLoop integration. Note that "
611 "falling back on Tk for CFRunLoop integration. Note that "
610 "even this won't work if Tk is linked against X11 instead of "
612 "even this won't work if Tk is linked against X11 instead of "
611 "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, "
613 "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, "
612 "you must use matplotlib >= 1.1.0, or a native libtk."
614 "you must use matplotlib >= 1.1.0, or a native libtk."
613 )
615 )
614 return TkKernel.start(self)
616 return loop_tk(kernel)
615
617
616 from matplotlib.backends.backend_macosx import TimerMac, show
618 from matplotlib.backends.backend_macosx import TimerMac, show
617
619
618 # scale interval for sec->ms
620 # scale interval for sec->ms
619 poll_interval = int(1000*self._poll_interval)
621 poll_interval = int(1000*kernel._poll_interval)
620
622
621 real_excepthook = sys.excepthook
623 real_excepthook = sys.excepthook
622 def handle_int(etype, value, tb):
624 def handle_int(etype, value, tb):
@@ -630,7 +632,7 b' class OSXKernel(TkKernel):'
630 def doi():
632 def doi():
631 # restore excepthook during IPython code
633 # restore excepthook during IPython code
632 sys.excepthook = real_excepthook
634 sys.excepthook = real_excepthook
633 self.do_one_iteration()
635 kernel.do_one_iteration()
634 # and back:
636 # and back:
635 sys.excepthook = handle_int
637 sys.excepthook = handle_int
636
638
@@ -641,7 +643,7 b' class OSXKernel(TkKernel):'
641 # but still need a Poller for when there are no active windows,
643 # but still need a Poller for when there are no active windows,
642 # during which time mainloop() returns immediately
644 # during which time mainloop() returns immediately
643 poller = zmq.Poller()
645 poller = zmq.Poller()
644 poller.register(self.shell_socket, zmq.POLLIN)
646 poller.register(kernel.shell_socket, zmq.POLLIN)
645
647
646 while True:
648 while True:
647 try:
649 try:
@@ -655,7 +657,7 b' class OSXKernel(TkKernel):'
655 # use poller if mainloop returned (no windows)
657 # use poller if mainloop returned (no windows)
656 # scale by extra factor of 10, since it's a real poll
658 # scale by extra factor of 10, since it's a real poll
657 poller.poll(10*poll_interval)
659 poller.poll(10*poll_interval)
658 self.do_one_iteration()
660 kernel.do_one_iteration()
659 except:
661 except:
660 raise
662 raise
661 except KeyboardInterrupt:
663 except KeyboardInterrupt:
@@ -665,6 +667,28 b' class OSXKernel(TkKernel):'
665 # ensure excepthook is restored
667 # ensure excepthook is restored
666 sys.excepthook = real_excepthook
668 sys.excepthook = real_excepthook
667
669
670 # mapping of keys to loop functions
671 loop_map = {
672 'qt' : loop_qt4,
673 'qt4': loop_qt4,
674 'inline': None,
675 'osx': loop_cocoa,
676 'wx' : loop_wx,
677 'tk' : loop_tk,
678 'gtk': loop_gtk,
679 }
680
681 def enable_gui(gui, kernel=None):
682 """Enable integration with a give GUI"""
683 if kernel is None:
684 kernel = IPKernelApp.instance().kernel
685 if gui not in loop_map:
686 raise ValueError("GUI %r not supported" % gui)
687 loop = loop_map[gui]
688 if kernel.eventloop is not None and kernel.eventloop is not loop:
689 raise RuntimeError("Cannot activate multiple GUI eventloops")
690 kernel.eventloop = loop
691
668
692
669 #-----------------------------------------------------------------------------
693 #-----------------------------------------------------------------------------
670 # Aliases and Flags for the IPKernelApp
694 # Aliases and Flags for the IPKernelApp
@@ -715,37 +739,21 b' class IPKernelApp(KernelApp, InteractiveShellApp):'
715 def init_kernel(self):
739 def init_kernel(self):
716 kernel_factory = Kernel
740 kernel_factory = Kernel
717
741
718 kernel_map = {
719 'qt' : QtKernel,
720 'qt4': QtKernel,
721 'inline': Kernel,
722 'osx': OSXKernel,
723 'wx' : WxKernel,
724 'tk' : TkKernel,
725 'gtk': GTKKernel,
726 }
727
728 if self.pylab:
742 if self.pylab:
729 key = None if self.pylab == 'auto' else self.pylab
743 key = None if self.pylab == 'auto' else self.pylab
730 gui, backend = pylabtools.find_gui_and_backend(key)
744 gui, backend = pylabtools.find_gui_and_backend(key)
731 kernel_factory = kernel_map.get(gui)
732 if kernel_factory is None:
733 raise ValueError('GUI is not supported: %r' % gui)
734 pylabtools.activate_matplotlib(backend)
735
745
736 kernel = kernel_factory(config=self.config, session=self.session,
746 kernel = kernel_factory(config=self.config, session=self.session,
737 shell_socket=self.shell_socket,
747 shell_socket=self.shell_socket,
738 iopub_socket=self.iopub_socket,
748 iopub_socket=self.iopub_socket,
739 stdin_socket=self.stdin_socket,
749 stdin_socket=self.stdin_socket,
740 log=self.log
750 log=self.log,
741 )
751 )
742 self.kernel = kernel
752 self.kernel = kernel
743 kernel.record_ports(self.ports)
753 kernel.record_ports(self.ports)
744
754
745 if self.pylab:
755 if self.pylab:
746 import_all = self.pylab_import_all
756 kernel.shell.enable_pylab(gui, import_all=self.pylab_import_all)
747 pylabtools.import_pylab(kernel.shell.user_ns, backend, import_all,
748 shell=kernel.shell)
749
757
750 def init_shell(self):
758 def init_shell(self):
751 self.shell = self.kernel.shell
759 self.shell = self.kernel.shell
@@ -31,6 +31,7 b' from IPython.core.displaypub import DisplayPublisher'
31 from IPython.core.macro import Macro
31 from IPython.core.macro import Macro
32 from IPython.core.magic import MacroToEdit
32 from IPython.core.magic import MacroToEdit
33 from IPython.core.payloadpage import install_payload_page
33 from IPython.core.payloadpage import install_payload_page
34 from IPython.lib import pylabtools
34 from IPython.lib.kernel import (
35 from IPython.lib.kernel import (
35 get_connection_file, get_connection_info, connect_qtconsole
36 get_connection_file, get_connection_info, connect_qtconsole
36 )
37 )
@@ -389,13 +390,65 b' class ZMQInteractiveShell(InteractiveShell):'
389 }
390 }
390 self.payload_manager.write_payload(payload)
391 self.payload_manager.write_payload(payload)
391
392
392 def magic_gui(self, *args, **kwargs):
393 def magic_gui(self, parameter_s=''):
393 raise NotImplementedError(
394 """Enable or disable IPython GUI event loop integration.
394 'Kernel GUI support is not implemented yet, except for --pylab.')
395
396 %gui [GUINAME]
397
398 This magic replaces IPython's threaded shells that were activated
399 using the (pylab/wthread/etc.) command line flags. GUI toolkits
400 can now be enabled at runtime and keyboard
401 interrupts should work without any problems. The following toolkits
402 are supported: wxPython, PyQt4, PyGTK, Cocoa, and Tk::
403
404 %gui wx # enable wxPython event loop integration
405 %gui qt4|qt # enable PyQt4 event loop integration
406 %gui gtk # enable PyGTK event loop integration
407 %gui OSX # enable Cocoa event loop integration (requires matplotlib 1.1)
408 %gui tk # enable Tk event loop integration
409
410 WARNING: after any of these has been called you can simply create
411 an application object, but DO NOT start the event loop yourself, as
412 we have already handled that.
413 """
414 from IPython.zmq.ipkernel import enable_gui
415 opts, arg = self.parse_options(parameter_s, '')
416 if arg=='': arg = None
417 return enable_gui(arg)
418
419 def enable_pylab(self, gui=None, import_all=True):
420 """Activate pylab support at runtime.
421
422 This turns on support for matplotlib, preloads into the interactive
423 namespace all of numpy and pylab, and configures IPython to correcdtly
424 interact with the GUI event loop. The GUI backend to be used can be
425 optionally selected with the optional :param:`gui` argument.
426
427 Parameters
428 ----------
429 gui : optional, string [default: inline]
430
431 If given, dictates the choice of matplotlib GUI backend to use
432 (should be one of IPython's supported backends, 'inline', 'qt', 'osx',
433 'tk', or 'gtk'), otherwise we use the default chosen by matplotlib
434 (as dictated by the matplotlib build-time options plus the user's
435 matplotlibrc configuration file).
436 """
437 from IPython.zmq.ipkernel import enable_gui
438 # We want to prevent the loading of pylab to pollute the user's
439 # namespace as shown by the %who* magics, so we execute the activation
440 # code in an empty namespace, and we update *both* user_ns and
441 # user_ns_hidden with this information.
442 ns = {}
443 # override default to inline, from auto-detect
444 gui = pylabtools.pylab_activate(ns, gui or 'inline', import_all, self)
445 self.user_ns.update(ns)
446 self.user_ns_hidden.update(ns)
447 # Now we must activate the gui pylab wants to use, and fix %run to take
448 # plot updates into account
449 enable_gui(gui)
450 self.magic_run = self._pylab_magic_run
395
451
396 def magic_pylab(self, *args, **kwargs):
397 raise NotImplementedError(
398 'pylab support must be enabled in command line options.')
399
452
400 # A few magics that are adapted to the specifics of using pexpect and a
453 # A few magics that are adapted to the specifics of using pexpect and a
401 # remote terminal
454 # remote terminal
General Comments 0
You need to be logged in to leave comments. Login now