Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #809 from minrk/osxkernel

use CFRunLoop directly in `ipython kernel --pylab osx`
  • Loading branch information...
commit 321d643f5e8ed3a089b04834a77dea61ae72e6c7 2 parents f09513e + 5175b0e
@minrk minrk authored
Showing with 73 additions and 2 deletions.
  1. +72 −1 IPython/zmq/ipkernel.py
  2. +1 −1  docs/source/interactive/qtconsole.txt
View
73 IPython/zmq/ipkernel.py
@@ -586,6 +586,77 @@ def start(self):
gtk_kernel.start()
+class OSXKernel(TkKernel):
+ """A Kernel subclass with Cocoa support via the matplotlib OSX backend."""
+
+ def start(self):
+ """Start the kernel, coordinating with the Cocoa CFRunLoop event loop
+ via the matplotlib MacOSX backend.
+ """
+ import matplotlib
+ if matplotlib.__version__ < '1.1.0':
+ self.log.warn(
+ "MacOSX backend in matplotlib %s doesn't have a Timer, "
+ "falling back on Tk for CFRunLoop integration. Note that "
+ "even this won't work if Tk is linked against X11 instead of "
+ "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, "
+ "you must use matplotlib >= 1.1.0, or a native libtk."
+ )
+ return TkKernel.start(self)
+
+ from matplotlib.backends.backend_macosx import TimerMac, show
+
+ # scale interval for sec->ms
+ poll_interval = int(1000*self._poll_interval)
+
+ real_excepthook = sys.excepthook
+ def handle_int(etype, value, tb):
+ """don't let KeyboardInterrupts look like crashes"""
+ if etype is KeyboardInterrupt:
+ io.raw_print("KeyboardInterrupt caught in CFRunLoop")
+ else:
+ real_excepthook(etype, value, tb)
+
+ # add doi() as a Timer to the CFRunLoop
+ def doi():
+ # restore excepthook during IPython code
+ sys.excepthook = real_excepthook
+ self.do_one_iteration()
+ # and back:
+ sys.excepthook = handle_int
+
+ t = TimerMac(poll_interval)
+ t.add_callback(doi)
+ t.start()
+
+ # but still need a Poller for when there are no active windows,
+ # during which time mainloop() returns immediately
+ poller = zmq.Poller()
+ poller.register(self.shell_socket, zmq.POLLIN)
+
+ while True:
+ try:
+ # double nested try/except, to properly catch KeyboardInterrupt
+ # due to pyzmq Issue #130
+ try:
+ # don't let interrupts during mainloop invoke crash_handler:
+ sys.excepthook = handle_int
+ show.mainloop()
+ sys.excepthook = real_excepthook
+ # use poller if mainloop returned (no windows)
+ # scale by extra factor of 10, since it's a real poll
+ poller.poll(10*poll_interval)
+ self.do_one_iteration()
+ except:
+ raise
+ except KeyboardInterrupt:
+ # Ctrl-C shouldn't crash the kernel
+ io.raw_print("KeyboardInterrupt caught in kernel")
+ finally:
+ # ensure excepthook is restored
+ sys.excepthook = real_excepthook
+
+
#-----------------------------------------------------------------------------
# Aliases and Flags for the IPKernelApp
#-----------------------------------------------------------------------------
@@ -639,7 +710,7 @@ def init_kernel(self):
'qt' : QtKernel,
'qt4': QtKernel,
'inline': Kernel,
- 'osx': TkKernel,
+ 'osx': OSXKernel,
'wx' : WxKernel,
'tk' : TkKernel,
'gtk': GTKKernel,
View
2  docs/source/interactive/qtconsole.txt
@@ -61,7 +61,7 @@ Pylab
=====
One of the most exciting features of the new console is embedded matplotlib
-figures. You can use any standard matplotlib GUI backend (Except native MacOSX)
+figures. You can use any standard matplotlib GUI backend
to draw the figures, and since there is now a two-process model, there is no
longer a conflict between user input and the drawing eventloop.
Please sign in to comment.
Something went wrong with that request. Please try again.