Show More
@@ -0,0 +1,206 b'' | |||||
|
1 | # encoding: utf-8 | |||
|
2 | """Event loop integration for the ZeroMQ-based kernels. | |||
|
3 | """ | |||
|
4 | ||||
|
5 | #----------------------------------------------------------------------------- | |||
|
6 | # Copyright (C) 2011 The IPython Development Team | |||
|
7 | ||||
|
8 | # Distributed under the terms of the BSD License. The full license is in | |||
|
9 | # the file COPYING, distributed as part of this software. | |||
|
10 | #----------------------------------------------------------------------------- | |||
|
11 | ||||
|
12 | ||||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | # Imports | |||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | ||||
|
17 | import sys | |||
|
18 | ||||
|
19 | # System library imports. | |||
|
20 | import zmq | |||
|
21 | ||||
|
22 | # Local imports. | |||
|
23 | from IPython.utils import io | |||
|
24 | ||||
|
25 | #------------------------------------------------------------------------------ | |||
|
26 | # Eventloops for integrating the Kernel into different GUIs | |||
|
27 | #------------------------------------------------------------------------------ | |||
|
28 | ||||
|
29 | def loop_qt4(kernel): | |||
|
30 | """Start a kernel with PyQt4 event loop integration.""" | |||
|
31 | ||||
|
32 | from IPython.external.qt_for_kernel import QtCore | |||
|
33 | from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4 | |||
|
34 | ||||
|
35 | kernel.app = get_app_qt4([" "]) | |||
|
36 | kernel.app.setQuitOnLastWindowClosed(False) | |||
|
37 | kernel.timer = QtCore.QTimer() | |||
|
38 | kernel.timer.timeout.connect(kernel.do_one_iteration) | |||
|
39 | # Units for the timer are in milliseconds | |||
|
40 | kernel.timer.start(1000*kernel._poll_interval) | |||
|
41 | start_event_loop_qt4(kernel.app) | |||
|
42 | ||||
|
43 | ||||
|
44 | def loop_wx(kernel): | |||
|
45 | """Start a kernel with wx event loop support.""" | |||
|
46 | ||||
|
47 | import wx | |||
|
48 | from IPython.lib.guisupport import start_event_loop_wx | |||
|
49 | ||||
|
50 | doi = kernel.do_one_iteration | |||
|
51 | # Wx uses milliseconds | |||
|
52 | poll_interval = int(1000*kernel._poll_interval) | |||
|
53 | ||||
|
54 | # We have to put the wx.Timer in a wx.Frame for it to fire properly. | |||
|
55 | # We make the Frame hidden when we create it in the main app below. | |||
|
56 | class TimerFrame(wx.Frame): | |||
|
57 | def __init__(self, func): | |||
|
58 | wx.Frame.__init__(self, None, -1) | |||
|
59 | self.timer = wx.Timer(self) | |||
|
60 | # Units for the timer are in milliseconds | |||
|
61 | self.timer.Start(poll_interval) | |||
|
62 | self.Bind(wx.EVT_TIMER, self.on_timer) | |||
|
63 | self.func = func | |||
|
64 | ||||
|
65 | def on_timer(self, event): | |||
|
66 | self.func() | |||
|
67 | ||||
|
68 | # We need a custom wx.App to create our Frame subclass that has the | |||
|
69 | # wx.Timer to drive the ZMQ event loop. | |||
|
70 | class IPWxApp(wx.App): | |||
|
71 | def OnInit(self): | |||
|
72 | self.frame = TimerFrame(doi) | |||
|
73 | self.frame.Show(False) | |||
|
74 | return True | |||
|
75 | ||||
|
76 | # The redirect=False here makes sure that wx doesn't replace | |||
|
77 | # sys.stdout/stderr with its own classes. | |||
|
78 | kernel.app = IPWxApp(redirect=False) | |||
|
79 | start_event_loop_wx(kernel.app) | |||
|
80 | ||||
|
81 | ||||
|
82 | def loop_tk(kernel): | |||
|
83 | """Start a kernel with the Tk event loop.""" | |||
|
84 | ||||
|
85 | import Tkinter | |||
|
86 | doi = kernel.do_one_iteration | |||
|
87 | # Tk uses milliseconds | |||
|
88 | poll_interval = int(1000*kernel._poll_interval) | |||
|
89 | # For Tkinter, we create a Tk object and call its withdraw method. | |||
|
90 | class Timer(object): | |||
|
91 | def __init__(self, func): | |||
|
92 | self.app = Tkinter.Tk() | |||
|
93 | self.app.withdraw() | |||
|
94 | self.func = func | |||
|
95 | ||||
|
96 | def on_timer(self): | |||
|
97 | self.func() | |||
|
98 | self.app.after(poll_interval, self.on_timer) | |||
|
99 | ||||
|
100 | def start(self): | |||
|
101 | self.on_timer() # Call it once to get things going. | |||
|
102 | self.app.mainloop() | |||
|
103 | ||||
|
104 | kernel.timer = Timer(doi) | |||
|
105 | kernel.timer.start() | |||
|
106 | ||||
|
107 | ||||
|
108 | def loop_gtk(kernel): | |||
|
109 | """Start the kernel, coordinating with the GTK event loop""" | |||
|
110 | from .gui.gtkembed import GTKEmbed | |||
|
111 | ||||
|
112 | gtk_kernel = GTKEmbed(kernel) | |||
|
113 | gtk_kernel.start() | |||
|
114 | ||||
|
115 | ||||
|
116 | def loop_cocoa(kernel): | |||
|
117 | """Start the kernel, coordinating with the Cocoa CFRunLoop event loop | |||
|
118 | via the matplotlib MacOSX backend. | |||
|
119 | """ | |||
|
120 | import matplotlib | |||
|
121 | if matplotlib.__version__ < '1.1.0': | |||
|
122 | kernel.log.warn( | |||
|
123 | "MacOSX backend in matplotlib %s doesn't have a Timer, " | |||
|
124 | "falling back on Tk for CFRunLoop integration. Note that " | |||
|
125 | "even this won't work if Tk is linked against X11 instead of " | |||
|
126 | "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, " | |||
|
127 | "you must use matplotlib >= 1.1.0, or a native libtk." | |||
|
128 | ) | |||
|
129 | return loop_tk(kernel) | |||
|
130 | ||||
|
131 | from matplotlib.backends.backend_macosx import TimerMac, show | |||
|
132 | ||||
|
133 | # scale interval for sec->ms | |||
|
134 | poll_interval = int(1000*kernel._poll_interval) | |||
|
135 | ||||
|
136 | real_excepthook = sys.excepthook | |||
|
137 | def handle_int(etype, value, tb): | |||
|
138 | """don't let KeyboardInterrupts look like crashes""" | |||
|
139 | if etype is KeyboardInterrupt: | |||
|
140 | io.raw_print("KeyboardInterrupt caught in CFRunLoop") | |||
|
141 | else: | |||
|
142 | real_excepthook(etype, value, tb) | |||
|
143 | ||||
|
144 | # add doi() as a Timer to the CFRunLoop | |||
|
145 | def doi(): | |||
|
146 | # restore excepthook during IPython code | |||
|
147 | sys.excepthook = real_excepthook | |||
|
148 | kernel.do_one_iteration() | |||
|
149 | # and back: | |||
|
150 | sys.excepthook = handle_int | |||
|
151 | ||||
|
152 | t = TimerMac(poll_interval) | |||
|
153 | t.add_callback(doi) | |||
|
154 | t.start() | |||
|
155 | ||||
|
156 | # but still need a Poller for when there are no active windows, | |||
|
157 | # during which time mainloop() returns immediately | |||
|
158 | poller = zmq.Poller() | |||
|
159 | poller.register(kernel.shell_socket, zmq.POLLIN) | |||
|
160 | ||||
|
161 | while True: | |||
|
162 | try: | |||
|
163 | # double nested try/except, to properly catch KeyboardInterrupt | |||
|
164 | # due to pyzmq Issue #130 | |||
|
165 | try: | |||
|
166 | # don't let interrupts during mainloop invoke crash_handler: | |||
|
167 | sys.excepthook = handle_int | |||
|
168 | show.mainloop() | |||
|
169 | sys.excepthook = real_excepthook | |||
|
170 | # use poller if mainloop returned (no windows) | |||
|
171 | # scale by extra factor of 10, since it's a real poll | |||
|
172 | poller.poll(10*poll_interval) | |||
|
173 | kernel.do_one_iteration() | |||
|
174 | except: | |||
|
175 | raise | |||
|
176 | except KeyboardInterrupt: | |||
|
177 | # Ctrl-C shouldn't crash the kernel | |||
|
178 | io.raw_print("KeyboardInterrupt caught in kernel") | |||
|
179 | finally: | |||
|
180 | # ensure excepthook is restored | |||
|
181 | sys.excepthook = real_excepthook | |||
|
182 | ||||
|
183 | # mapping of keys to loop functions | |||
|
184 | loop_map = { | |||
|
185 | 'qt' : loop_qt4, | |||
|
186 | 'qt4': loop_qt4, | |||
|
187 | 'inline': None, | |||
|
188 | 'osx': loop_cocoa, | |||
|
189 | 'wx' : loop_wx, | |||
|
190 | 'tk' : loop_tk, | |||
|
191 | 'gtk': loop_gtk, | |||
|
192 | None : None, | |||
|
193 | } | |||
|
194 | ||||
|
195 | ||||
|
196 | def enable_gui(gui, kernel=None): | |||
|
197 | """Enable integration with a given GUI""" | |||
|
198 | if kernel is None: | |||
|
199 | from .ipkernel import IPKernelApp | |||
|
200 | kernel = IPKernelApp.instance().kernel | |||
|
201 | if gui not in loop_map: | |||
|
202 | raise ValueError("GUI %r not supported" % gui) | |||
|
203 | loop = loop_map[gui] | |||
|
204 | if kernel.eventloop is not None and kernel.eventloop is not loop: | |||
|
205 | raise RuntimeError("Cannot activate multiple GUI eventloops") | |||
|
206 | kernel.eventloop = loop |
@@ -62,6 +62,7 b' from IPython.core.payload import PayloadManager' | |||||
62 | from IPython.core.plugin import PluginManager |
|
62 | from IPython.core.plugin import PluginManager | |
63 | from IPython.core.prefilter import PrefilterManager, ESC_MAGIC |
|
63 | from IPython.core.prefilter import PrefilterManager, ESC_MAGIC | |
64 | from IPython.core.profiledir import ProfileDir |
|
64 | from IPython.core.profiledir import ProfileDir | |
|
65 | from IPython.core.pylabtools import pylab_activate | |||
65 | from IPython.external.Itpl import ItplNS |
|
66 | from IPython.external.Itpl import ItplNS | |
66 | from IPython.utils import PyColorize |
|
67 | from IPython.utils import PyColorize | |
67 | from IPython.utils import io |
|
68 | from IPython.utils import io | |
@@ -2531,8 +2532,46 b' class InteractiveShell(SingletonConfigurable, Magic):' | |||||
2531 | # Things related to GUI support and pylab |
|
2532 | # Things related to GUI support and pylab | |
2532 | #------------------------------------------------------------------------- |
|
2533 | #------------------------------------------------------------------------- | |
2533 |
|
2534 | |||
|
2535 | def enable_gui(self, gui=None): | |||
|
2536 | raise NotImplementedError('Implement enable_gui in a subclass') | |||
|
2537 | ||||
2534 | def enable_pylab(self, gui=None, import_all=True): |
|
2538 | def enable_pylab(self, gui=None, import_all=True): | |
2535 | raise NotImplementedError('Implement enable_pylab in a subclass') |
|
2539 | """Activate pylab support at runtime. | |
|
2540 | ||||
|
2541 | This turns on support for matplotlib, preloads into the interactive | |||
|
2542 | namespace all of numpy and pylab, and configures IPython to correctly | |||
|
2543 | interact with the GUI event loop. The GUI backend to be used can be | |||
|
2544 | optionally selected with the optional :param:`gui` argument. | |||
|
2545 | ||||
|
2546 | Parameters | |||
|
2547 | ---------- | |||
|
2548 | gui : optional, string | |||
|
2549 | ||||
|
2550 | If given, dictates the choice of matplotlib GUI backend to use | |||
|
2551 | (should be one of IPython's supported backends, 'qt', 'osx', 'tk', | |||
|
2552 | 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by | |||
|
2553 | matplotlib (as dictated by the matplotlib build-time options plus the | |||
|
2554 | user's matplotlibrc configuration file). Note that not all backends | |||
|
2555 | make sense in all contexts, for example a terminal ipython can't | |||
|
2556 | display figures inline. | |||
|
2557 | """ | |||
|
2558 | ||||
|
2559 | # We want to prevent the loading of pylab to pollute the user's | |||
|
2560 | # namespace as shown by the %who* magics, so we execute the activation | |||
|
2561 | # code in an empty namespace, and we update *both* user_ns and | |||
|
2562 | # user_ns_hidden with this information. | |||
|
2563 | ns = {} | |||
|
2564 | try: | |||
|
2565 | gui = pylab_activate(ns, gui, import_all, self) | |||
|
2566 | except KeyError: | |||
|
2567 | error("Backend %r not supported" % gui) | |||
|
2568 | return | |||
|
2569 | self.user_ns.update(ns) | |||
|
2570 | self.user_ns_hidden.update(ns) | |||
|
2571 | # Now we must activate the gui pylab wants to use, and fix %run to take | |||
|
2572 | # plot updates into account | |||
|
2573 | self.enable_gui(gui) | |||
|
2574 | self.magic_run = self._pylab_magic_run | |||
2536 |
|
2575 | |||
2537 | #------------------------------------------------------------------------- |
|
2576 | #------------------------------------------------------------------------- | |
2538 | # Utilities |
|
2577 | # Utilities |
@@ -50,7 +50,7 b' from IPython.core.profiledir import ProfileDir' | |||||
50 | from IPython.core.macro import Macro |
|
50 | from IPython.core.macro import Macro | |
51 | from IPython.core import magic_arguments, page |
|
51 | from IPython.core import magic_arguments, page | |
52 | from IPython.core.prefilter import ESC_MAGIC |
|
52 | from IPython.core.prefilter import ESC_MAGIC | |
53 |
from IPython. |
|
53 | from IPython.core.pylabtools import mpl_runner | |
54 | from IPython.testing.skipdoctest import skip_doctest |
|
54 | from IPython.testing.skipdoctest import skip_doctest | |
55 | from IPython.utils import py3compat |
|
55 | from IPython.utils import py3compat | |
56 | from IPython.utils.io import file_read, nlprint |
|
56 | from IPython.utils.io import file_read, nlprint | |
@@ -3305,24 +3305,30 b' Defaulting color scheme to \'NoColor\'"""' | |||||
3305 |
|
3305 | |||
3306 | This magic replaces IPython's threaded shells that were activated |
|
3306 | This magic replaces IPython's threaded shells that were activated | |
3307 | using the (pylab/wthread/etc.) command line flags. GUI toolkits |
|
3307 | using the (pylab/wthread/etc.) command line flags. GUI toolkits | |
3308 |
can now be enabled |
|
3308 | can now be enabled at runtime and keyboard | |
3309 | interrupts should work without any problems. The following toolkits |
|
3309 | interrupts should work without any problems. The following toolkits | |
3310 |
are supported: wxPython, PyQt4, PyGTK, |
|
3310 | are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX):: | |
3311 |
|
3311 | |||
3312 | %gui wx # enable wxPython event loop integration |
|
3312 | %gui wx # enable wxPython event loop integration | |
3313 | %gui qt4|qt # enable PyQt4 event loop integration |
|
3313 | %gui qt4|qt # enable PyQt4 event loop integration | |
3314 | %gui gtk # enable PyGTK event loop integration |
|
3314 | %gui gtk # enable PyGTK event loop integration | |
3315 | %gui tk # enable Tk event loop integration |
|
3315 | %gui tk # enable Tk event loop integration | |
|
3316 | %gui OSX # enable Cocoa event loop integration | |||
|
3317 | # (requires %matplotlib 1.1) | |||
3316 | %gui # disable all event loop integration |
|
3318 | %gui # disable all event loop integration | |
3317 |
|
3319 | |||
3318 | WARNING: after any of these has been called you can simply create |
|
3320 | WARNING: after any of these has been called you can simply create | |
3319 | an application object, but DO NOT start the event loop yourself, as |
|
3321 | an application object, but DO NOT start the event loop yourself, as | |
3320 | we have already handled that. |
|
3322 | we have already handled that. | |
3321 | """ |
|
3323 | """ | |
3322 | from IPython.lib.inputhook import enable_gui |
|
|||
3323 | opts, arg = self.parse_options(parameter_s, '') |
|
3324 | opts, arg = self.parse_options(parameter_s, '') | |
3324 | if arg=='': arg = None |
|
3325 | if arg=='': arg = None | |
3325 | return enable_gui(arg) |
|
3326 | try: | |
|
3327 | return self.enable_gui(arg) | |||
|
3328 | except Exception as e: | |||
|
3329 | # print simple error message, rather than traceback if we can't | |||
|
3330 | # hook up the GUI | |||
|
3331 | error(str(e)) | |||
3326 |
|
3332 | |||
3327 | def magic_load_ext(self, module_str): |
|
3333 | def magic_load_ext(self, module_str): | |
3328 | """Load an IPython extension by its module name.""" |
|
3334 | """Load an IPython extension by its module name.""" | |
@@ -3416,9 +3422,9 b' Defaulting color scheme to \'NoColor\'"""' | |||||
3416 | Parameters |
|
3422 | Parameters | |
3417 | ---------- |
|
3423 | ---------- | |
3418 | guiname : optional |
|
3424 | guiname : optional | |
3419 |
One of the valid arguments to the %gui magic ('qt', 'wx', 'gtk', |
|
3425 | One of the valid arguments to the %gui magic ('qt', 'wx', 'gtk', | |
3420 |
'tk'). If given, the corresponding Matplotlib backend is |
|
3426 | 'osx' or 'tk'). If given, the corresponding Matplotlib backend is | |
3421 | otherwise matplotlib's default (which you can override in your |
|
3427 | used, otherwise matplotlib's default (which you can override in your | |
3422 | matplotlib config file) is used. |
|
3428 | matplotlib config file) is used. | |
3423 |
|
3429 | |||
3424 | Examples |
|
3430 | Examples | |
@@ -3449,7 +3455,7 b' Defaulting color scheme to \'NoColor\'"""' | |||||
3449 | else: |
|
3455 | else: | |
3450 | import_all_status = True |
|
3456 | import_all_status = True | |
3451 |
|
3457 | |||
3452 | self.shell.enable_pylab(s,import_all=import_all_status) |
|
3458 | self.shell.enable_pylab(s, import_all=import_all_status) | |
3453 |
|
3459 | |||
3454 | def magic_tb(self, s): |
|
3460 | def magic_tb(self, s): | |
3455 | """Print the last traceback with the currently active exception mode. |
|
3461 | """Print the last traceback with the currently active exception mode. |
@@ -232,7 +232,8 b' def activate_matplotlib(backend):' | |||||
232 | # For this, we wrap it into a decorator which adds a 'called' flag. |
|
232 | # For this, we wrap it into a decorator which adds a 'called' flag. | |
233 | pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive) |
|
233 | pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive) | |
234 |
|
234 | |||
235 | def import_pylab(user_ns, backend, import_all=True, shell=None): |
|
235 | ||
|
236 | def import_pylab(user_ns, import_all=True): | |||
236 | """Import the standard pylab symbols into user_ns.""" |
|
237 | """Import the standard pylab symbols into user_ns.""" | |
237 |
|
238 | |||
238 | # Import numpy as np/pyplot as plt are conventions we're trying to |
|
239 | # Import numpy as np/pyplot as plt are conventions we're trying to | |
@@ -246,48 +247,62 b' def import_pylab(user_ns, backend, import_all=True, shell=None):' | |||||
246 | ) |
|
247 | ) | |
247 | exec s in user_ns |
|
248 | exec s in user_ns | |
248 |
|
249 | |||
249 | if shell is not None: |
|
|||
250 | exec s in shell.user_ns_hidden |
|
|||
251 | # If using our svg payload backend, register the post-execution |
|
|||
252 | # function that will pick up the results for display. This can only be |
|
|||
253 | # done with access to the real shell object. |
|
|||
254 | # |
|
|||
255 | from IPython.zmq.pylab.backend_inline import InlineBackend |
|
|||
256 |
|
||||
257 | cfg = InlineBackend.instance(config=shell.config) |
|
|||
258 | cfg.shell = shell |
|
|||
259 | if cfg not in shell.configurables: |
|
|||
260 | shell.configurables.append(cfg) |
|
|||
261 |
|
||||
262 | if backend == backends['inline']: |
|
|||
263 | from IPython.zmq.pylab.backend_inline import flush_figures |
|
|||
264 | from matplotlib import pyplot |
|
|||
265 | shell.register_post_execute(flush_figures) |
|
|||
266 | # load inline_rc |
|
|||
267 | pyplot.rcParams.update(cfg.rc) |
|
|||
268 |
|
||||
269 | # Add 'figsize' to pyplot and to the user's namespace |
|
|||
270 | user_ns['figsize'] = pyplot.figsize = figsize |
|
|||
271 | shell.user_ns_hidden['figsize'] = figsize |
|
|||
272 |
|
||||
273 | # Setup the default figure format |
|
|||
274 | fmt = cfg.figure_format |
|
|||
275 | select_figure_format(shell, fmt) |
|
|||
276 |
|
||||
277 | # The old pastefig function has been replaced by display |
|
|||
278 | from IPython.core.display import display |
|
|||
279 | # Add display and display_png to the user's namespace |
|
|||
280 | user_ns['display'] = display |
|
|||
281 | shell.user_ns_hidden['display'] = display |
|
|||
282 | user_ns['getfigs'] = getfigs |
|
|||
283 | shell.user_ns_hidden['getfigs'] = getfigs |
|
|||
284 |
|
||||
285 | if import_all: |
|
250 | if import_all: | |
286 | s = ("from matplotlib.pylab import *\n" |
|
251 | s = ("from matplotlib.pylab import *\n" | |
287 | "from numpy import *\n") |
|
252 | "from numpy import *\n") | |
288 | exec s in user_ns |
|
253 | exec s in user_ns | |
289 | if shell is not None: |
|
254 | ||
290 | exec s in shell.user_ns_hidden |
|
255 | ||
|
256 | def configure_inline_support(shell, backend, user_ns=None): | |||
|
257 | """Configure an IPython shell object for matplotlib use. | |||
|
258 | ||||
|
259 | Parameters | |||
|
260 | ---------- | |||
|
261 | shell : InteractiveShell instance | |||
|
262 | ||||
|
263 | backend : matplotlib backend | |||
|
264 | ||||
|
265 | user_ns : dict | |||
|
266 | A namespace where all configured variables will be placed. If not given, | |||
|
267 | the `user_ns` attribute of the shell object is used. | |||
|
268 | """ | |||
|
269 | # If using our svg payload backend, register the post-execution | |||
|
270 | # function that will pick up the results for display. This can only be | |||
|
271 | # done with access to the real shell object. | |||
|
272 | ||||
|
273 | # Note: if we can't load the inline backend, then there's no point | |||
|
274 | # continuing (such as in terminal-only shells in environments without | |||
|
275 | # zeromq available). | |||
|
276 | try: | |||
|
277 | from IPython.zmq.pylab.backend_inline import InlineBackend | |||
|
278 | except ImportError: | |||
|
279 | return | |||
|
280 | ||||
|
281 | user_ns = shell.user_ns if user_ns is None else user_ns | |||
|
282 | ||||
|
283 | cfg = InlineBackend.instance(config=shell.config) | |||
|
284 | cfg.shell = shell | |||
|
285 | if cfg not in shell.configurables: | |||
|
286 | shell.configurables.append(cfg) | |||
|
287 | ||||
|
288 | if backend == backends['inline']: | |||
|
289 | from IPython.zmq.pylab.backend_inline import flush_figures | |||
|
290 | from matplotlib import pyplot | |||
|
291 | shell.register_post_execute(flush_figures) | |||
|
292 | # load inline_rc | |||
|
293 | pyplot.rcParams.update(cfg.rc) | |||
|
294 | # Add 'figsize' to pyplot and to the user's namespace | |||
|
295 | user_ns['figsize'] = pyplot.figsize = figsize | |||
|
296 | ||||
|
297 | # Setup the default figure format | |||
|
298 | fmt = cfg.figure_format | |||
|
299 | select_figure_format(shell, fmt) | |||
|
300 | ||||
|
301 | # The old pastefig function has been replaced by display | |||
|
302 | from IPython.core.display import display | |||
|
303 | # Add display and getfigs to the user's namespace | |||
|
304 | user_ns['display'] = display | |||
|
305 | user_ns['getfigs'] = getfigs | |||
291 |
|
306 | |||
292 |
|
307 | |||
293 | def pylab_activate(user_ns, gui=None, import_all=True, shell=None): |
|
308 | def pylab_activate(user_ns, gui=None, import_all=True, shell=None): | |
@@ -313,8 +328,10 b' def pylab_activate(user_ns, gui=None, import_all=True, shell=None):' | |||||
313 | """ |
|
328 | """ | |
314 | gui, backend = find_gui_and_backend(gui) |
|
329 | gui, backend = find_gui_and_backend(gui) | |
315 | activate_matplotlib(backend) |
|
330 | activate_matplotlib(backend) | |
316 |
import_pylab(user_ns, |
|
331 | import_pylab(user_ns, import_all) | |
317 |
|
332 | if shell is not None: | ||
|
333 | configure_inline_support(shell, backend, user_ns) | |||
|
334 | ||||
318 | print """ |
|
335 | print """ | |
319 | Welcome to pylab, a matplotlib-based Python environment [backend: %s]. |
|
336 | Welcome to pylab, a matplotlib-based Python environment [backend: %s]. | |
320 | For more information, type 'help(pylab)'.""" % backend |
|
337 | For more information, type 'help(pylab)'.""" % backend |
@@ -20,6 +20,7 b" import matplotlib; matplotlib.use('Agg')" | |||||
20 | import nose.tools as nt |
|
20 | import nose.tools as nt | |
21 |
|
21 | |||
22 | from matplotlib import pyplot as plt |
|
22 | from matplotlib import pyplot as plt | |
|
23 | import numpy as np | |||
23 |
|
24 | |||
24 | # Our own imports |
|
25 | # Our own imports | |
25 | from IPython.testing import decorators as dec |
|
26 | from IPython.testing import decorators as dec | |
@@ -52,3 +53,11 b' def test_figure_to_svg():' | |||||
52 | plt.draw() |
|
53 | plt.draw() | |
53 | svg = pt.print_figure(fig, 'svg')[:100].lower() |
|
54 | svg = pt.print_figure(fig, 'svg')[:100].lower() | |
54 | yield nt.assert_true('doctype svg' in svg) |
|
55 | yield nt.assert_true('doctype svg' in svg) | |
|
56 | ||||
|
57 | ||||
|
58 | def test_import_pylab(): | |||
|
59 | ip = get_ipython() | |||
|
60 | ns = {} | |||
|
61 | pt.import_pylab(ns, import_all=False) | |||
|
62 | nt.assert_true('plt' in ns) | |||
|
63 | nt.assert_equal(ns['np'], np) |
@@ -29,8 +29,7 b' except:' | |||||
29 | from IPython.core.error import TryNext |
|
29 | from IPython.core.error import TryNext | |
30 | from IPython.core.usage import interactive_usage, default_banner |
|
30 | from IPython.core.usage import interactive_usage, default_banner | |
31 | from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC |
|
31 | from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC | |
32 |
from IPython. |
|
32 | from IPython.core.pylabtools import pylab_activate | |
33 | from IPython.lib.pylabtools import pylab_activate |
|
|||
34 | from IPython.testing.skipdoctest import skip_doctest |
|
33 | from IPython.testing.skipdoctest import skip_doctest | |
35 | from IPython.utils import py3compat |
|
34 | from IPython.utils import py3compat | |
36 | from IPython.utils.terminal import toggle_set_term_title, set_term_title |
|
35 | from IPython.utils.terminal import toggle_set_term_title, set_term_title | |
@@ -171,10 +170,13 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
171 | help="Enable auto setting the terminal title." |
|
170 | help="Enable auto setting the terminal title." | |
172 | ) |
|
171 | ) | |
173 |
|
172 | |||
174 | def __init__(self, config=None, ipython_dir=None, profile_dir=None, user_ns=None, |
|
173 | # In the terminal, GUI control is done via PyOS_InputHook | |
175 | user_module=None, custom_exceptions=((),None), |
|
174 | from IPython.lib.inputhook import enable_gui | |
176 | usage=None, banner1=None, banner2=None, |
|
175 | enable_gui = staticmethod(enable_gui) | |
177 | display_banner=None): |
|
176 | ||
|
177 | def __init__(self, config=None, ipython_dir=None, profile_dir=None, | |||
|
178 | user_ns=None, user_module=None, custom_exceptions=((),None), | |||
|
179 | usage=None, banner1=None, banner2=None, display_banner=None): | |||
178 |
|
180 | |||
179 | super(TerminalInteractiveShell, self).__init__( |
|
181 | super(TerminalInteractiveShell, self).__init__( | |
180 | config=config, profile_dir=profile_dir, user_ns=user_ns, |
|
182 | config=config, profile_dir=profile_dir, user_ns=user_ns, | |
@@ -517,45 +519,6 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
517 | return True |
|
519 | return True | |
518 |
|
520 | |||
519 | #------------------------------------------------------------------------- |
|
521 | #------------------------------------------------------------------------- | |
520 | # Things related to GUI support and pylab |
|
|||
521 | #------------------------------------------------------------------------- |
|
|||
522 |
|
||||
523 | def enable_pylab(self, gui=None, import_all=True): |
|
|||
524 | """Activate pylab support at runtime. |
|
|||
525 |
|
||||
526 | This turns on support for matplotlib, preloads into the interactive |
|
|||
527 | namespace all of numpy and pylab, and configures IPython to correcdtly |
|
|||
528 | interact with the GUI event loop. The GUI backend to be used can be |
|
|||
529 | optionally selected with the optional :param:`gui` argument. |
|
|||
530 |
|
||||
531 | Parameters |
|
|||
532 | ---------- |
|
|||
533 | gui : optional, string |
|
|||
534 |
|
||||
535 | If given, dictates the choice of matplotlib GUI backend to use |
|
|||
536 | (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or |
|
|||
537 | 'gtk'), otherwise we use the default chosen by matplotlib (as |
|
|||
538 | dictated by the matplotlib build-time options plus the user's |
|
|||
539 | matplotlibrc configuration file). |
|
|||
540 | """ |
|
|||
541 | # We want to prevent the loading of pylab to pollute the user's |
|
|||
542 | # namespace as shown by the %who* magics, so we execute the activation |
|
|||
543 | # code in an empty namespace, and we update *both* user_ns and |
|
|||
544 | # user_ns_hidden with this information. |
|
|||
545 | ns = {} |
|
|||
546 | try: |
|
|||
547 | gui = pylab_activate(ns, gui, import_all) |
|
|||
548 | except KeyError: |
|
|||
549 | error("Backend %r not supported" % gui) |
|
|||
550 | return |
|
|||
551 | self.user_ns.update(ns) |
|
|||
552 | self.user_ns_hidden.update(ns) |
|
|||
553 | # Now we must activate the gui pylab wants to use, and fix %run to take |
|
|||
554 | # plot updates into account |
|
|||
555 | enable_gui(gui) |
|
|||
556 | self.magic_run = self._pylab_magic_run |
|
|||
557 |
|
||||
558 | #------------------------------------------------------------------------- |
|
|||
559 | # Things related to exiting |
|
522 | # Things related to exiting | |
560 | #------------------------------------------------------------------------- |
|
523 | #------------------------------------------------------------------------- | |
561 |
|
524 |
@@ -238,8 +238,8 b' def make_exclude():' | |||||
238 | exclusions.append(ipjoin('parallel', 'tests', 'test_mongodb')) |
|
238 | exclusions.append(ipjoin('parallel', 'tests', 'test_mongodb')) | |
239 |
|
239 | |||
240 | if not have['matplotlib']: |
|
240 | if not have['matplotlib']: | |
241 |
exclusions.extend([ipjoin(' |
|
241 | exclusions.extend([ipjoin('core', 'pylabtools'), | |
242 |
ipjoin(' |
|
242 | ipjoin('core', 'tests', 'test_pylabtools')]) | |
243 |
|
243 | |||
244 | if not have['tornado']: |
|
244 | if not have['tornado']: | |
245 | exclusions.append(ipjoin('frontend', 'html')) |
|
245 | exclusions.append(ipjoin('frontend', 'html')) |
@@ -39,12 +39,11 b' from IPython.utils import py3compat' | |||||
39 | from IPython.utils.jsonutil import json_clean |
|
39 | from IPython.utils.jsonutil import json_clean | |
40 | from IPython.lib import pylabtools |
|
40 | from IPython.lib import pylabtools | |
41 | from IPython.utils.traitlets import ( |
|
41 | from IPython.utils.traitlets import ( | |
42 |
Any |
|
42 | Any, Instance, Float, Dict, CaselessStrEnum | |
43 | ) |
|
43 | ) | |
44 |
|
44 | |||
45 | from entry_point import base_launch_kernel |
|
45 | from entry_point import base_launch_kernel | |
46 | from kernelapp import KernelApp, kernel_flags, kernel_aliases |
|
46 | from kernelapp import KernelApp, kernel_flags, kernel_aliases | |
47 | from iostream import OutStream |
|
|||
48 | from session import Session, Message |
|
47 | from session import Session, Message | |
49 | from zmqshell import ZMQInteractiveShell |
|
48 | from zmqshell import ZMQInteractiveShell | |
50 |
|
49 | |||
@@ -212,16 +211,16 b' class Kernel(Configurable):' | |||||
212 | def _publish_pyin(self, code, parent): |
|
211 | def _publish_pyin(self, code, parent): | |
213 | """Publish the code request on the pyin stream.""" |
|
212 | """Publish the code request on the pyin stream.""" | |
214 |
|
213 | |||
215 |
|
|
214 | self.session.send(self.iopub_socket, u'pyin', {u'code':code}, | |
|
215 | parent=parent) | |||
216 |
|
216 | |||
217 | def execute_request(self, ident, parent): |
|
217 | def execute_request(self, ident, parent): | |
218 |
|
218 | |||
219 |
|
|
219 | self.session.send(self.iopub_socket, | |
220 | u'status', |
|
220 | u'status', | |
221 | {u'execution_state':u'busy'}, |
|
221 | {u'execution_state':u'busy'}, | |
222 | parent=parent |
|
222 | parent=parent ) | |
223 |
|
|
223 | ||
224 |
|
||||
225 | try: |
|
224 | try: | |
226 | content = parent[u'content'] |
|
225 | content = parent[u'content'] | |
227 | code = content[u'code'] |
|
226 | code = content[u'code'] | |
@@ -331,11 +330,10 b' class Kernel(Configurable):' | |||||
331 | if reply_msg['content']['status'] == u'error': |
|
330 | if reply_msg['content']['status'] == u'error': | |
332 | self._abort_queue() |
|
331 | self._abort_queue() | |
333 |
|
332 | |||
334 |
|
|
333 | self.session.send(self.iopub_socket, | |
335 | u'status', |
|
334 | u'status', | |
336 | {u'execution_state':u'idle'}, |
|
335 | {u'execution_state':u'idle'}, | |
337 | parent=parent |
|
336 | parent=parent ) | |
338 | ) |
|
|||
339 |
|
337 | |||
340 | def complete_request(self, ident, parent): |
|
338 | def complete_request(self, ident, parent): | |
341 | txt, matches = self._complete(parent) |
|
339 | txt, matches = self._complete(parent) | |
@@ -375,7 +373,8 b' class Kernel(Configurable):' | |||||
375 |
|
373 | |||
376 | elif hist_access_type == 'search': |
|
374 | elif hist_access_type == 'search': | |
377 | pattern = parent['content']['pattern'] |
|
375 | pattern = parent['content']['pattern'] | |
378 |
hist = self.shell.history_manager.search(pattern, raw=raw, |
|
376 | hist = self.shell.history_manager.search(pattern, raw=raw, | |
|
377 | output=output) | |||
379 |
|
378 | |||
380 | else: |
|
379 | else: | |
381 | hist = [] |
|
380 | hist = [] | |
@@ -396,7 +395,8 b' class Kernel(Configurable):' | |||||
396 |
|
395 | |||
397 | def shutdown_request(self, ident, parent): |
|
396 | def shutdown_request(self, ident, parent): | |
398 | self.shell.exit_now = True |
|
397 | self.shell.exit_now = True | |
399 |
self._shutdown_message = self.session.msg(u'shutdown_reply', |
|
398 | self._shutdown_message = self.session.msg(u'shutdown_reply', | |
|
399 | parent['content'], parent) | |||
400 | sys.exit(0) |
|
400 | sys.exit(0) | |
401 |
|
401 | |||
402 | #--------------------------------------------------------------------------- |
|
402 | #--------------------------------------------------------------------------- | |
@@ -427,8 +427,10 b' class Kernel(Configurable):' | |||||
427 | time.sleep(0.1) |
|
427 | time.sleep(0.1) | |
428 |
|
428 | |||
429 | def _no_raw_input(self): |
|
429 | def _no_raw_input(self): | |
430 |
"""Raise StdinNotImplentedError if active frontend doesn't support |
|
430 | """Raise StdinNotImplentedError if active frontend doesn't support | |
431 | raise StdinNotImplementedError("raw_input was called, but this frontend does not support stdin.") |
|
431 | stdin.""" | |
|
432 | raise StdinNotImplementedError("raw_input was called, but this " | |||
|
433 | "frontend does not support stdin.") | |||
432 |
|
434 | |||
433 | def _raw_input(self, prompt, ident, parent): |
|
435 | def _raw_input(self, prompt, ident, parent): | |
434 | # Flush output before making the request. |
|
436 | # Flush output before making the request. | |
@@ -437,7 +439,8 b' class Kernel(Configurable):' | |||||
437 |
|
439 | |||
438 | # Send the input request. |
|
440 | # Send the input request. | |
439 | content = json_clean(dict(prompt=prompt)) |
|
441 | content = json_clean(dict(prompt=prompt)) | |
440 |
|
|
442 | self.session.send(self.stdin_socket, u'input_request', content, parent, | |
|
443 | ident=ident) | |||
441 |
|
444 | |||
442 | # Await a response. |
|
445 | # Await a response. | |
443 | while True: |
|
446 | while True: | |
@@ -510,189 +513,6 b' class Kernel(Configurable):' | |||||
510 | # before Python truly shuts down. |
|
513 | # before Python truly shuts down. | |
511 | time.sleep(0.01) |
|
514 | time.sleep(0.01) | |
512 |
|
515 | |||
513 |
|
||||
514 | #------------------------------------------------------------------------------ |
|
|||
515 | # Eventloops for integrating the Kernel into different GUIs |
|
|||
516 | #------------------------------------------------------------------------------ |
|
|||
517 |
|
||||
518 |
|
||||
519 | def loop_qt4(kernel): |
|
|||
520 | """Start a kernel with PyQt4 event loop integration.""" |
|
|||
521 |
|
||||
522 | from IPython.external.qt_for_kernel import QtCore |
|
|||
523 | from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4 |
|
|||
524 |
|
||||
525 | kernel.app = get_app_qt4([" "]) |
|
|||
526 | kernel.app.setQuitOnLastWindowClosed(False) |
|
|||
527 | kernel.timer = QtCore.QTimer() |
|
|||
528 | kernel.timer.timeout.connect(kernel.do_one_iteration) |
|
|||
529 | # Units for the timer are in milliseconds |
|
|||
530 | kernel.timer.start(1000*kernel._poll_interval) |
|
|||
531 | start_event_loop_qt4(kernel.app) |
|
|||
532 |
|
||||
533 |
|
||||
534 | def loop_wx(kernel): |
|
|||
535 | """Start a kernel with wx event loop support.""" |
|
|||
536 |
|
||||
537 | import wx |
|
|||
538 | from IPython.lib.guisupport import start_event_loop_wx |
|
|||
539 |
|
||||
540 | doi = kernel.do_one_iteration |
|
|||
541 | # Wx uses milliseconds |
|
|||
542 | poll_interval = int(1000*kernel._poll_interval) |
|
|||
543 |
|
||||
544 | # We have to put the wx.Timer in a wx.Frame for it to fire properly. |
|
|||
545 | # We make the Frame hidden when we create it in the main app below. |
|
|||
546 | class TimerFrame(wx.Frame): |
|
|||
547 | def __init__(self, func): |
|
|||
548 | wx.Frame.__init__(self, None, -1) |
|
|||
549 | self.timer = wx.Timer(self) |
|
|||
550 | # Units for the timer are in milliseconds |
|
|||
551 | self.timer.Start(poll_interval) |
|
|||
552 | self.Bind(wx.EVT_TIMER, self.on_timer) |
|
|||
553 | self.func = func |
|
|||
554 |
|
||||
555 | def on_timer(self, event): |
|
|||
556 | self.func() |
|
|||
557 |
|
||||
558 | # We need a custom wx.App to create our Frame subclass that has the |
|
|||
559 | # wx.Timer to drive the ZMQ event loop. |
|
|||
560 | class IPWxApp(wx.App): |
|
|||
561 | def OnInit(self): |
|
|||
562 | self.frame = TimerFrame(doi) |
|
|||
563 | self.frame.Show(False) |
|
|||
564 | return True |
|
|||
565 |
|
||||
566 | # The redirect=False here makes sure that wx doesn't replace |
|
|||
567 | # sys.stdout/stderr with its own classes. |
|
|||
568 | kernel.app = IPWxApp(redirect=False) |
|
|||
569 | start_event_loop_wx(kernel.app) |
|
|||
570 |
|
||||
571 |
|
||||
572 | def loop_tk(kernel): |
|
|||
573 | """Start a kernel with the Tk event loop.""" |
|
|||
574 |
|
||||
575 | import Tkinter |
|
|||
576 | doi = kernel.do_one_iteration |
|
|||
577 | # Tk uses milliseconds |
|
|||
578 | poll_interval = int(1000*kernel._poll_interval) |
|
|||
579 | # For Tkinter, we create a Tk object and call its withdraw method. |
|
|||
580 | class Timer(object): |
|
|||
581 | def __init__(self, func): |
|
|||
582 | self.app = Tkinter.Tk() |
|
|||
583 | self.app.withdraw() |
|
|||
584 | self.func = func |
|
|||
585 |
|
||||
586 | def on_timer(self): |
|
|||
587 | self.func() |
|
|||
588 | self.app.after(poll_interval, self.on_timer) |
|
|||
589 |
|
||||
590 | def start(self): |
|
|||
591 | self.on_timer() # Call it once to get things going. |
|
|||
592 | self.app.mainloop() |
|
|||
593 |
|
||||
594 | kernel.timer = Timer(doi) |
|
|||
595 | kernel.timer.start() |
|
|||
596 |
|
||||
597 |
|
||||
598 | def loop_gtk(kernel): |
|
|||
599 | """Start the kernel, coordinating with the GTK event loop""" |
|
|||
600 | from .gui.gtkembed import GTKEmbed |
|
|||
601 |
|
||||
602 | gtk_kernel = GTKEmbed(kernel) |
|
|||
603 | gtk_kernel.start() |
|
|||
604 |
|
||||
605 |
|
||||
606 | def loop_cocoa(kernel): |
|
|||
607 | """Start the kernel, coordinating with the Cocoa CFRunLoop event loop |
|
|||
608 | via the matplotlib MacOSX backend. |
|
|||
609 | """ |
|
|||
610 | import matplotlib |
|
|||
611 | if matplotlib.__version__ < '1.1.0': |
|
|||
612 | kernel.log.warn( |
|
|||
613 | "MacOSX backend in matplotlib %s doesn't have a Timer, " |
|
|||
614 | "falling back on Tk for CFRunLoop integration. Note that " |
|
|||
615 | "even this won't work if Tk is linked against X11 instead of " |
|
|||
616 | "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, " |
|
|||
617 | "you must use matplotlib >= 1.1.0, or a native libtk." |
|
|||
618 | ) |
|
|||
619 | return loop_tk(kernel) |
|
|||
620 |
|
||||
621 | from matplotlib.backends.backend_macosx import TimerMac, show |
|
|||
622 |
|
||||
623 | # scale interval for sec->ms |
|
|||
624 | poll_interval = int(1000*kernel._poll_interval) |
|
|||
625 |
|
||||
626 | real_excepthook = sys.excepthook |
|
|||
627 | def handle_int(etype, value, tb): |
|
|||
628 | """don't let KeyboardInterrupts look like crashes""" |
|
|||
629 | if etype is KeyboardInterrupt: |
|
|||
630 | io.raw_print("KeyboardInterrupt caught in CFRunLoop") |
|
|||
631 | else: |
|
|||
632 | real_excepthook(etype, value, tb) |
|
|||
633 |
|
||||
634 | # add doi() as a Timer to the CFRunLoop |
|
|||
635 | def doi(): |
|
|||
636 | # restore excepthook during IPython code |
|
|||
637 | sys.excepthook = real_excepthook |
|
|||
638 | kernel.do_one_iteration() |
|
|||
639 | # and back: |
|
|||
640 | sys.excepthook = handle_int |
|
|||
641 |
|
||||
642 | t = TimerMac(poll_interval) |
|
|||
643 | t.add_callback(doi) |
|
|||
644 | t.start() |
|
|||
645 |
|
||||
646 | # but still need a Poller for when there are no active windows, |
|
|||
647 | # during which time mainloop() returns immediately |
|
|||
648 | poller = zmq.Poller() |
|
|||
649 | poller.register(kernel.shell_socket, zmq.POLLIN) |
|
|||
650 |
|
||||
651 | while True: |
|
|||
652 | try: |
|
|||
653 | # double nested try/except, to properly catch KeyboardInterrupt |
|
|||
654 | # due to pyzmq Issue #130 |
|
|||
655 | try: |
|
|||
656 | # don't let interrupts during mainloop invoke crash_handler: |
|
|||
657 | sys.excepthook = handle_int |
|
|||
658 | show.mainloop() |
|
|||
659 | sys.excepthook = real_excepthook |
|
|||
660 | # use poller if mainloop returned (no windows) |
|
|||
661 | # scale by extra factor of 10, since it's a real poll |
|
|||
662 | poller.poll(10*poll_interval) |
|
|||
663 | kernel.do_one_iteration() |
|
|||
664 | except: |
|
|||
665 | raise |
|
|||
666 | except KeyboardInterrupt: |
|
|||
667 | # Ctrl-C shouldn't crash the kernel |
|
|||
668 | io.raw_print("KeyboardInterrupt caught in kernel") |
|
|||
669 | finally: |
|
|||
670 | # ensure excepthook is restored |
|
|||
671 | sys.excepthook = real_excepthook |
|
|||
672 |
|
||||
673 | # mapping of keys to loop functions |
|
|||
674 | loop_map = { |
|
|||
675 | 'qt' : loop_qt4, |
|
|||
676 | 'qt4': loop_qt4, |
|
|||
677 | 'inline': None, |
|
|||
678 | 'osx': loop_cocoa, |
|
|||
679 | 'wx' : loop_wx, |
|
|||
680 | 'tk' : loop_tk, |
|
|||
681 | 'gtk': loop_gtk, |
|
|||
682 | } |
|
|||
683 |
|
||||
684 | def enable_gui(gui, kernel=None): |
|
|||
685 | """Enable integration with a give GUI""" |
|
|||
686 | if kernel is None: |
|
|||
687 | kernel = IPKernelApp.instance().kernel |
|
|||
688 | if gui not in loop_map: |
|
|||
689 | raise ValueError("GUI %r not supported" % gui) |
|
|||
690 | loop = loop_map[gui] |
|
|||
691 | if kernel.eventloop is not None and kernel.eventloop is not loop: |
|
|||
692 | raise RuntimeError("Cannot activate multiple GUI eventloops") |
|
|||
693 | kernel.eventloop = loop |
|
|||
694 |
|
||||
695 |
|
||||
696 | #----------------------------------------------------------------------------- |
|
516 | #----------------------------------------------------------------------------- | |
697 | # Aliases and Flags for the IPKernelApp |
|
517 | # Aliases and Flags for the IPKernelApp | |
698 | #----------------------------------------------------------------------------- |
|
518 | #----------------------------------------------------------------------------- | |
@@ -767,7 +587,8 b' class IPKernelApp(KernelApp, InteractiveShellApp):' | |||||
767 | # replace pyerr-sending traceback with stdout |
|
587 | # replace pyerr-sending traceback with stdout | |
768 | _showtraceback = shell._showtraceback |
|
588 | _showtraceback = shell._showtraceback | |
769 | def print_tb(etype, evalue, stb): |
|
589 | def print_tb(etype, evalue, stb): | |
770 |
print ("Error initializing pylab, pylab mode will not |
|
590 | print ("Error initializing pylab, pylab mode will not " | |
|
591 | "be active", file=io.stderr) | |||
771 | print (shell.InteractiveTB.stb2text(stb), file=io.stdout) |
|
592 | print (shell.InteractiveTB.stb2text(stb), file=io.stdout) | |
772 | shell._showtraceback = print_tb |
|
593 | shell._showtraceback = print_tb | |
773 |
|
594 | |||
@@ -790,8 +611,8 b' class IPKernelApp(KernelApp, InteractiveShellApp):' | |||||
790 | def launch_kernel(*args, **kwargs): |
|
611 | def launch_kernel(*args, **kwargs): | |
791 | """Launches a localhost IPython kernel, binding to the specified ports. |
|
612 | """Launches a localhost IPython kernel, binding to the specified ports. | |
792 |
|
613 | |||
793 |
This function simply calls entry_point.base_launch_kernel with the right |
|
614 | This function simply calls entry_point.base_launch_kernel with the right | |
794 | command to start an ipkernel. See base_launch_kernel for arguments. |
|
615 | first command to start an ipkernel. See base_launch_kernel for arguments. | |
795 |
|
616 | |||
796 | Returns |
|
617 | Returns | |
797 | ------- |
|
618 | ------- |
@@ -16,7 +16,7 b' from matplotlib._pylab_helpers import Gcf' | |||||
16 | # Local imports. |
|
16 | # Local imports. | |
17 | from IPython.config.configurable import SingletonConfigurable |
|
17 | from IPython.config.configurable import SingletonConfigurable | |
18 | from IPython.core.displaypub import publish_display_data |
|
18 | from IPython.core.displaypub import publish_display_data | |
19 |
from IPython. |
|
19 | from IPython.core.pylabtools import print_figure, select_figure_format | |
20 | from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, CBool |
|
20 | from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, CBool | |
21 | from IPython.utils.warn import warn |
|
21 | from IPython.utils.warn import warn | |
22 |
|
22 |
@@ -109,6 +109,11 b' class ZMQInteractiveShell(InteractiveShell):' | |||||
109 |
|
109 | |||
110 | keepkernel_on_exit = None |
|
110 | keepkernel_on_exit = None | |
111 |
|
111 | |||
|
112 | # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no | |||
|
113 | # interactive input being read; we provide event loop support in ipkernel | |||
|
114 | from .eventloops import enable_gui | |||
|
115 | enable_gui = staticmethod(enable_gui) | |||
|
116 | ||||
112 | def init_environment(self): |
|
117 | def init_environment(self): | |
113 | """Configure the user's environment. |
|
118 | """Configure the user's environment. | |
114 |
|
119 | |||
@@ -390,79 +395,6 b' class ZMQInteractiveShell(InteractiveShell):' | |||||
390 | } |
|
395 | } | |
391 | self.payload_manager.write_payload(payload) |
|
396 | self.payload_manager.write_payload(payload) | |
392 |
|
397 | |||
393 | def magic_gui(self, parameter_s=''): |
|
|||
394 | """Enable or disable IPython GUI event loop integration. |
|
|||
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 | try: |
|
|||
418 | enable_gui(arg) |
|
|||
419 | except Exception as e: |
|
|||
420 | # print simple error message, rather than traceback if we can't |
|
|||
421 | # hook up the GUI |
|
|||
422 | error(str(e)) |
|
|||
423 |
|
||||
424 | def enable_pylab(self, gui=None, import_all=True): |
|
|||
425 | """Activate pylab support at runtime. |
|
|||
426 |
|
||||
427 | This turns on support for matplotlib, preloads into the interactive |
|
|||
428 | namespace all of numpy and pylab, and configures IPython to correcdtly |
|
|||
429 | interact with the GUI event loop. The GUI backend to be used can be |
|
|||
430 | optionally selected with the optional :param:`gui` argument. |
|
|||
431 |
|
||||
432 | Parameters |
|
|||
433 | ---------- |
|
|||
434 | gui : optional, string [default: inline] |
|
|||
435 |
|
||||
436 | If given, dictates the choice of matplotlib GUI backend to use |
|
|||
437 | (should be one of IPython's supported backends, 'inline', 'qt', 'osx', |
|
|||
438 | 'tk', or 'gtk'), otherwise we use the default chosen by matplotlib |
|
|||
439 | (as dictated by the matplotlib build-time options plus the user's |
|
|||
440 | matplotlibrc configuration file). |
|
|||
441 | """ |
|
|||
442 | from IPython.zmq.ipkernel import enable_gui |
|
|||
443 | # We want to prevent the loading of pylab to pollute the user's |
|
|||
444 | # namespace as shown by the %who* magics, so we execute the activation |
|
|||
445 | # code in an empty namespace, and we update *both* user_ns and |
|
|||
446 | # user_ns_hidden with this information. |
|
|||
447 | ns = {} |
|
|||
448 | try: |
|
|||
449 | gui = pylabtools.pylab_activate(ns, gui, import_all, self) |
|
|||
450 | except KeyError: |
|
|||
451 | error("Backend %r not supported" % gui) |
|
|||
452 | return |
|
|||
453 | self.user_ns.update(ns) |
|
|||
454 | self.user_ns_hidden.update(ns) |
|
|||
455 | # Now we must activate the gui pylab wants to use, and fix %run to take |
|
|||
456 | # plot updates into account |
|
|||
457 | try: |
|
|||
458 | enable_gui(gui) |
|
|||
459 | except Exception as e: |
|
|||
460 | # print simple error message, rather than traceback if we can't |
|
|||
461 | # hook up the GUI |
|
|||
462 | error(str(e)) |
|
|||
463 | self.magic_run = self._pylab_magic_run |
|
|||
464 |
|
||||
465 |
|
||||
466 | # A few magics that are adapted to the specifics of using pexpect and a |
|
398 | # A few magics that are adapted to the specifics of using pexpect and a | |
467 | # remote terminal |
|
399 | # remote terminal | |
468 |
|
400 | |||
@@ -567,7 +499,6 b' class ZMQInteractiveShell(InteractiveShell):' | |||||
567 | except Exception as e: |
|
499 | except Exception as e: | |
568 | error("Could not start qtconsole: %r" % e) |
|
500 | error("Could not start qtconsole: %r" % e) | |
569 | return |
|
501 | return | |
570 |
|
||||
571 |
|
502 | |||
572 | def set_next_input(self, text): |
|
503 | def set_next_input(self, text): | |
573 | """Send the specified text to the frontend to be presented at the next |
|
504 | """Send the specified text to the frontend to be presented at the next | |
@@ -578,4 +509,5 b' class ZMQInteractiveShell(InteractiveShell):' | |||||
578 | ) |
|
509 | ) | |
579 | self.payload_manager.write_payload(payload) |
|
510 | self.payload_manager.write_payload(payload) | |
580 |
|
511 | |||
|
512 | ||||
581 | InteractiveShellABC.register(ZMQInteractiveShell) |
|
513 | InteractiveShellABC.register(ZMQInteractiveShell) |
General Comments 0
You need to be logged in to leave comments.
Login now