##// END OF EJS Templates
Fix for ticket 237073 thanks to Nathaniel Smith...
Brian Granger -
Show More
@@ -1,1244 +1,1246 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Shell classes.
2 """IPython Shell classes.
3
3
4 All the matplotlib support code was co-developed with John Hunter,
4 All the matplotlib support code was co-developed with John Hunter,
5 matplotlib's author.
5 matplotlib's author.
6 """
6 """
7
7
8 #*****************************************************************************
8 #*****************************************************************************
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #*****************************************************************************
13 #*****************************************************************************
14
14
15 # Code begins
15 # Code begins
16 # Stdlib imports
16 # Stdlib imports
17 import __builtin__
17 import __builtin__
18 import __main__
18 import __main__
19 import Queue
19 import Queue
20 import inspect
20 import inspect
21 import os
21 import os
22 import sys
22 import sys
23 import thread
23 import thread
24 import threading
24 import threading
25 import time
25 import time
26
26
27 from signal import signal, SIGINT
27 from signal import signal, SIGINT
28
28
29 try:
29 try:
30 import ctypes
30 import ctypes
31 HAS_CTYPES = True
31 HAS_CTYPES = True
32 except ImportError:
32 except ImportError:
33 HAS_CTYPES = False
33 HAS_CTYPES = False
34
34
35 # IPython imports
35 # IPython imports
36 import IPython
36 import IPython
37 from IPython import ultraTB, ipapi
37 from IPython import ultraTB, ipapi
38 from IPython.Magic import Magic
38 from IPython.Magic import Magic
39 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
39 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
40 from IPython.iplib import InteractiveShell
40 from IPython.iplib import InteractiveShell
41 from IPython.ipmaker import make_IPython
41 from IPython.ipmaker import make_IPython
42 from IPython.ipstruct import Struct
42 from IPython.ipstruct import Struct
43 from IPython.testing import decorators as testdec
43 from IPython.testing import decorators as testdec
44
44
45 # Globals
45 # Globals
46 # global flag to pass around information about Ctrl-C without exceptions
46 # global flag to pass around information about Ctrl-C without exceptions
47 KBINT = False
47 KBINT = False
48
48
49 # global flag to turn on/off Tk support.
49 # global flag to turn on/off Tk support.
50 USE_TK = False
50 USE_TK = False
51
51
52 # ID for the main thread, used for cross-thread exceptions
52 # ID for the main thread, used for cross-thread exceptions
53 MAIN_THREAD_ID = thread.get_ident()
53 MAIN_THREAD_ID = thread.get_ident()
54
54
55 # Tag when runcode() is active, for exception handling
55 # Tag when runcode() is active, for exception handling
56 CODE_RUN = None
56 CODE_RUN = None
57
57
58 # Default timeout for waiting for multithreaded shells (in seconds)
58 # Default timeout for waiting for multithreaded shells (in seconds)
59 GUI_TIMEOUT = 10
59 GUI_TIMEOUT = 10
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # This class is trivial now, but I want to have it in to publish a clean
62 # This class is trivial now, but I want to have it in to publish a clean
63 # interface. Later when the internals are reorganized, code that uses this
63 # interface. Later when the internals are reorganized, code that uses this
64 # shouldn't have to change.
64 # shouldn't have to change.
65
65
66 class IPShell:
66 class IPShell:
67 """Create an IPython instance."""
67 """Create an IPython instance."""
68
68
69 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
69 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
70 debug=1,shell_class=InteractiveShell):
70 debug=1,shell_class=InteractiveShell):
71 self.IP = make_IPython(argv,user_ns=user_ns,
71 self.IP = make_IPython(argv,user_ns=user_ns,
72 user_global_ns=user_global_ns,
72 user_global_ns=user_global_ns,
73 debug=debug,shell_class=shell_class)
73 debug=debug,shell_class=shell_class)
74
74
75 def mainloop(self,sys_exit=0,banner=None):
75 def mainloop(self,sys_exit=0,banner=None):
76 self.IP.mainloop(banner)
76 self.IP.mainloop(banner)
77 if sys_exit:
77 if sys_exit:
78 sys.exit()
78 sys.exit()
79
79
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81 def kill_embedded(self,parameter_s=''):
81 def kill_embedded(self,parameter_s=''):
82 """%kill_embedded : deactivate for good the current embedded IPython.
82 """%kill_embedded : deactivate for good the current embedded IPython.
83
83
84 This function (after asking for confirmation) sets an internal flag so that
84 This function (after asking for confirmation) sets an internal flag so that
85 an embedded IPython will never activate again. This is useful to
85 an embedded IPython will never activate again. This is useful to
86 permanently disable a shell that is being called inside a loop: once you've
86 permanently disable a shell that is being called inside a loop: once you've
87 figured out what you needed from it, you may then kill it and the program
87 figured out what you needed from it, you may then kill it and the program
88 will then continue to run without the interactive shell interfering again.
88 will then continue to run without the interactive shell interfering again.
89 """
89 """
90
90
91 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
91 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
92 "(y/n)? [y/N] ",'n')
92 "(y/n)? [y/N] ",'n')
93 if kill:
93 if kill:
94 self.shell.embedded_active = False
94 self.shell.embedded_active = False
95 print "This embedded IPython will not reactivate anymore once you exit."
95 print "This embedded IPython will not reactivate anymore once you exit."
96
96
97 class IPShellEmbed:
97 class IPShellEmbed:
98 """Allow embedding an IPython shell into a running program.
98 """Allow embedding an IPython shell into a running program.
99
99
100 Instances of this class are callable, with the __call__ method being an
100 Instances of this class are callable, with the __call__ method being an
101 alias to the embed() method of an InteractiveShell instance.
101 alias to the embed() method of an InteractiveShell instance.
102
102
103 Usage (see also the example-embed.py file for a running example):
103 Usage (see also the example-embed.py file for a running example):
104
104
105 ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
105 ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
106
106
107 - argv: list containing valid command-line options for IPython, as they
107 - argv: list containing valid command-line options for IPython, as they
108 would appear in sys.argv[1:].
108 would appear in sys.argv[1:].
109
109
110 For example, the following command-line options:
110 For example, the following command-line options:
111
111
112 $ ipython -prompt_in1 'Input <\\#>' -colors LightBG
112 $ ipython -prompt_in1 'Input <\\#>' -colors LightBG
113
113
114 would be passed in the argv list as:
114 would be passed in the argv list as:
115
115
116 ['-prompt_in1','Input <\\#>','-colors','LightBG']
116 ['-prompt_in1','Input <\\#>','-colors','LightBG']
117
117
118 - banner: string which gets printed every time the interpreter starts.
118 - banner: string which gets printed every time the interpreter starts.
119
119
120 - exit_msg: string which gets printed every time the interpreter exits.
120 - exit_msg: string which gets printed every time the interpreter exits.
121
121
122 - rc_override: a dict or Struct of configuration options such as those
122 - rc_override: a dict or Struct of configuration options such as those
123 used by IPython. These options are read from your ~/.ipython/ipythonrc
123 used by IPython. These options are read from your ~/.ipython/ipythonrc
124 file when the Shell object is created. Passing an explicit rc_override
124 file when the Shell object is created. Passing an explicit rc_override
125 dict with any options you want allows you to override those values at
125 dict with any options you want allows you to override those values at
126 creation time without having to modify the file. This way you can create
126 creation time without having to modify the file. This way you can create
127 embeddable instances configured in any way you want without editing any
127 embeddable instances configured in any way you want without editing any
128 global files (thus keeping your interactive IPython configuration
128 global files (thus keeping your interactive IPython configuration
129 unchanged).
129 unchanged).
130
130
131 Then the ipshell instance can be called anywhere inside your code:
131 Then the ipshell instance can be called anywhere inside your code:
132
132
133 ipshell(header='') -> Opens up an IPython shell.
133 ipshell(header='') -> Opens up an IPython shell.
134
134
135 - header: string printed by the IPython shell upon startup. This can let
135 - header: string printed by the IPython shell upon startup. This can let
136 you know where in your code you are when dropping into the shell. Note
136 you know where in your code you are when dropping into the shell. Note
137 that 'banner' gets prepended to all calls, so header is used for
137 that 'banner' gets prepended to all calls, so header is used for
138 location-specific information.
138 location-specific information.
139
139
140 For more details, see the __call__ method below.
140 For more details, see the __call__ method below.
141
141
142 When the IPython shell is exited with Ctrl-D, normal program execution
142 When the IPython shell is exited with Ctrl-D, normal program execution
143 resumes.
143 resumes.
144
144
145 This functionality was inspired by a posting on comp.lang.python by cmkl
145 This functionality was inspired by a posting on comp.lang.python by cmkl
146 <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
146 <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
147 by the IDL stop/continue commands."""
147 by the IDL stop/continue commands."""
148
148
149 def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None,
149 def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None,
150 user_ns=None):
150 user_ns=None):
151 """Note that argv here is a string, NOT a list."""
151 """Note that argv here is a string, NOT a list."""
152 self.set_banner(banner)
152 self.set_banner(banner)
153 self.set_exit_msg(exit_msg)
153 self.set_exit_msg(exit_msg)
154 self.set_dummy_mode(0)
154 self.set_dummy_mode(0)
155
155
156 # sys.displayhook is a global, we need to save the user's original
156 # sys.displayhook is a global, we need to save the user's original
157 # Don't rely on __displayhook__, as the user may have changed that.
157 # Don't rely on __displayhook__, as the user may have changed that.
158 self.sys_displayhook_ori = sys.displayhook
158 self.sys_displayhook_ori = sys.displayhook
159
159
160 # save readline completer status
160 # save readline completer status
161 try:
161 try:
162 #print 'Save completer',sys.ipcompleter # dbg
162 #print 'Save completer',sys.ipcompleter # dbg
163 self.sys_ipcompleter_ori = sys.ipcompleter
163 self.sys_ipcompleter_ori = sys.ipcompleter
164 except:
164 except:
165 pass # not nested with IPython
165 pass # not nested with IPython
166
166
167 self.IP = make_IPython(argv,rc_override=rc_override,
167 self.IP = make_IPython(argv,rc_override=rc_override,
168 embedded=True,
168 embedded=True,
169 user_ns=user_ns)
169 user_ns=user_ns)
170
170
171 ip = ipapi.IPApi(self.IP)
171 ip = ipapi.IPApi(self.IP)
172 ip.expose_magic("kill_embedded",kill_embedded)
172 ip.expose_magic("kill_embedded",kill_embedded)
173
173
174 # copy our own displayhook also
174 # copy our own displayhook also
175 self.sys_displayhook_embed = sys.displayhook
175 self.sys_displayhook_embed = sys.displayhook
176 # and leave the system's display hook clean
176 # and leave the system's display hook clean
177 sys.displayhook = self.sys_displayhook_ori
177 sys.displayhook = self.sys_displayhook_ori
178 # don't use the ipython crash handler so that user exceptions aren't
178 # don't use the ipython crash handler so that user exceptions aren't
179 # trapped
179 # trapped
180 sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
180 sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
181 mode = self.IP.rc.xmode,
181 mode = self.IP.rc.xmode,
182 call_pdb = self.IP.rc.pdb)
182 call_pdb = self.IP.rc.pdb)
183 self.restore_system_completer()
183 self.restore_system_completer()
184
184
185 def restore_system_completer(self):
185 def restore_system_completer(self):
186 """Restores the readline completer which was in place.
186 """Restores the readline completer which was in place.
187
187
188 This allows embedded IPython within IPython not to disrupt the
188 This allows embedded IPython within IPython not to disrupt the
189 parent's completion.
189 parent's completion.
190 """
190 """
191
191
192 try:
192 try:
193 self.IP.readline.set_completer(self.sys_ipcompleter_ori)
193 self.IP.readline.set_completer(self.sys_ipcompleter_ori)
194 sys.ipcompleter = self.sys_ipcompleter_ori
194 sys.ipcompleter = self.sys_ipcompleter_ori
195 except:
195 except:
196 pass
196 pass
197
197
198 def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
198 def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
199 """Activate the interactive interpreter.
199 """Activate the interactive interpreter.
200
200
201 __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
201 __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
202 the interpreter shell with the given local and global namespaces, and
202 the interpreter shell with the given local and global namespaces, and
203 optionally print a header string at startup.
203 optionally print a header string at startup.
204
204
205 The shell can be globally activated/deactivated using the
205 The shell can be globally activated/deactivated using the
206 set/get_dummy_mode methods. This allows you to turn off a shell used
206 set/get_dummy_mode methods. This allows you to turn off a shell used
207 for debugging globally.
207 for debugging globally.
208
208
209 However, *each* time you call the shell you can override the current
209 However, *each* time you call the shell you can override the current
210 state of dummy_mode with the optional keyword parameter 'dummy'. For
210 state of dummy_mode with the optional keyword parameter 'dummy'. For
211 example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
211 example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
212 can still have a specific call work by making it as IPShell(dummy=0).
212 can still have a specific call work by making it as IPShell(dummy=0).
213
213
214 The optional keyword parameter dummy controls whether the call
214 The optional keyword parameter dummy controls whether the call
215 actually does anything. """
215 actually does anything. """
216
216
217 # If the user has turned it off, go away
217 # If the user has turned it off, go away
218 if not self.IP.embedded_active:
218 if not self.IP.embedded_active:
219 return
219 return
220
220
221 # Normal exits from interactive mode set this flag, so the shell can't
221 # Normal exits from interactive mode set this flag, so the shell can't
222 # re-enter (it checks this variable at the start of interactive mode).
222 # re-enter (it checks this variable at the start of interactive mode).
223 self.IP.exit_now = False
223 self.IP.exit_now = False
224
224
225 # Allow the dummy parameter to override the global __dummy_mode
225 # Allow the dummy parameter to override the global __dummy_mode
226 if dummy or (dummy != 0 and self.__dummy_mode):
226 if dummy or (dummy != 0 and self.__dummy_mode):
227 return
227 return
228
228
229 # Set global subsystems (display,completions) to our values
229 # Set global subsystems (display,completions) to our values
230 sys.displayhook = self.sys_displayhook_embed
230 sys.displayhook = self.sys_displayhook_embed
231 if self.IP.has_readline:
231 if self.IP.has_readline:
232 self.IP.set_completer()
232 self.IP.set_completer()
233
233
234 if self.banner and header:
234 if self.banner and header:
235 format = '%s\n%s\n'
235 format = '%s\n%s\n'
236 else:
236 else:
237 format = '%s%s\n'
237 format = '%s%s\n'
238 banner = format % (self.banner,header)
238 banner = format % (self.banner,header)
239
239
240 # Call the embedding code with a stack depth of 1 so it can skip over
240 # Call the embedding code with a stack depth of 1 so it can skip over
241 # our call and get the original caller's namespaces.
241 # our call and get the original caller's namespaces.
242 self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
242 self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
243
243
244 if self.exit_msg:
244 if self.exit_msg:
245 print self.exit_msg
245 print self.exit_msg
246
246
247 # Restore global systems (display, completion)
247 # Restore global systems (display, completion)
248 sys.displayhook = self.sys_displayhook_ori
248 sys.displayhook = self.sys_displayhook_ori
249 self.restore_system_completer()
249 self.restore_system_completer()
250
250
251 def set_dummy_mode(self,dummy):
251 def set_dummy_mode(self,dummy):
252 """Sets the embeddable shell's dummy mode parameter.
252 """Sets the embeddable shell's dummy mode parameter.
253
253
254 set_dummy_mode(dummy): dummy = 0 or 1.
254 set_dummy_mode(dummy): dummy = 0 or 1.
255
255
256 This parameter is persistent and makes calls to the embeddable shell
256 This parameter is persistent and makes calls to the embeddable shell
257 silently return without performing any action. This allows you to
257 silently return without performing any action. This allows you to
258 globally activate or deactivate a shell you're using with a single call.
258 globally activate or deactivate a shell you're using with a single call.
259
259
260 If you need to manually"""
260 If you need to manually"""
261
261
262 if dummy not in [0,1,False,True]:
262 if dummy not in [0,1,False,True]:
263 raise ValueError,'dummy parameter must be boolean'
263 raise ValueError,'dummy parameter must be boolean'
264 self.__dummy_mode = dummy
264 self.__dummy_mode = dummy
265
265
266 def get_dummy_mode(self):
266 def get_dummy_mode(self):
267 """Return the current value of the dummy mode parameter.
267 """Return the current value of the dummy mode parameter.
268 """
268 """
269 return self.__dummy_mode
269 return self.__dummy_mode
270
270
271 def set_banner(self,banner):
271 def set_banner(self,banner):
272 """Sets the global banner.
272 """Sets the global banner.
273
273
274 This banner gets prepended to every header printed when the shell
274 This banner gets prepended to every header printed when the shell
275 instance is called."""
275 instance is called."""
276
276
277 self.banner = banner
277 self.banner = banner
278
278
279 def set_exit_msg(self,exit_msg):
279 def set_exit_msg(self,exit_msg):
280 """Sets the global exit_msg.
280 """Sets the global exit_msg.
281
281
282 This exit message gets printed upon exiting every time the embedded
282 This exit message gets printed upon exiting every time the embedded
283 shell is called. It is None by default. """
283 shell is called. It is None by default. """
284
284
285 self.exit_msg = exit_msg
285 self.exit_msg = exit_msg
286
286
287 #-----------------------------------------------------------------------------
287 #-----------------------------------------------------------------------------
288 if HAS_CTYPES:
288 if HAS_CTYPES:
289 # Add async exception support. Trick taken from:
289 # Add async exception support. Trick taken from:
290 # http://sebulba.wikispaces.com/recipe+thread2
290 # http://sebulba.wikispaces.com/recipe+thread2
291 def _async_raise(tid, exctype):
291 def _async_raise(tid, exctype):
292 """raises the exception, performs cleanup if needed"""
292 """raises the exception, performs cleanup if needed"""
293 if not inspect.isclass(exctype):
293 if not inspect.isclass(exctype):
294 raise TypeError("Only types can be raised (not instances)")
294 raise TypeError("Only types can be raised (not instances)")
295 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
295 # Explicit cast to c_long is necessary for 64-bit support:
296 # See https://bugs.launchpad.net/ipython/+bug/237073
297 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid),
296 ctypes.py_object(exctype))
298 ctypes.py_object(exctype))
297 if res == 0:
299 if res == 0:
298 raise ValueError("invalid thread id")
300 raise ValueError("invalid thread id")
299 elif res != 1:
301 elif res != 1:
300 # """if it returns a number greater than one, you're in trouble,
302 # """if it returns a number greater than one, you're in trouble,
301 # and you should call it again with exc=NULL to revert the effect"""
303 # and you should call it again with exc=NULL to revert the effect"""
302 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
304 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
303 raise SystemError("PyThreadState_SetAsyncExc failed")
305 raise SystemError("PyThreadState_SetAsyncExc failed")
304
306
305 def sigint_handler (signum,stack_frame):
307 def sigint_handler (signum,stack_frame):
306 """Sigint handler for threaded apps.
308 """Sigint handler for threaded apps.
307
309
308 This is a horrible hack to pass information about SIGINT _without_
310 This is a horrible hack to pass information about SIGINT _without_
309 using exceptions, since I haven't been able to properly manage
311 using exceptions, since I haven't been able to properly manage
310 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
312 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
311 done (or at least that's my understanding from a c.l.py thread where
313 done (or at least that's my understanding from a c.l.py thread where
312 this was discussed)."""
314 this was discussed)."""
313
315
314 global KBINT
316 global KBINT
315
317
316 if CODE_RUN:
318 if CODE_RUN:
317 _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
319 _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
318 else:
320 else:
319 KBINT = True
321 KBINT = True
320 print '\nKeyboardInterrupt - Press <Enter> to continue.',
322 print '\nKeyboardInterrupt - Press <Enter> to continue.',
321 Term.cout.flush()
323 Term.cout.flush()
322
324
323 else:
325 else:
324 def sigint_handler (signum,stack_frame):
326 def sigint_handler (signum,stack_frame):
325 """Sigint handler for threaded apps.
327 """Sigint handler for threaded apps.
326
328
327 This is a horrible hack to pass information about SIGINT _without_
329 This is a horrible hack to pass information about SIGINT _without_
328 using exceptions, since I haven't been able to properly manage
330 using exceptions, since I haven't been able to properly manage
329 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
331 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
330 done (or at least that's my understanding from a c.l.py thread where
332 done (or at least that's my understanding from a c.l.py thread where
331 this was discussed)."""
333 this was discussed)."""
332
334
333 global KBINT
335 global KBINT
334
336
335 print '\nKeyboardInterrupt - Press <Enter> to continue.',
337 print '\nKeyboardInterrupt - Press <Enter> to continue.',
336 Term.cout.flush()
338 Term.cout.flush()
337 # Set global flag so that runsource can know that Ctrl-C was hit
339 # Set global flag so that runsource can know that Ctrl-C was hit
338 KBINT = True
340 KBINT = True
339
341
340
342
341 class MTInteractiveShell(InteractiveShell):
343 class MTInteractiveShell(InteractiveShell):
342 """Simple multi-threaded shell."""
344 """Simple multi-threaded shell."""
343
345
344 # Threading strategy taken from:
346 # Threading strategy taken from:
345 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
347 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
346 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
348 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
347 # from the pygtk mailing list, to avoid lockups with system calls.
349 # from the pygtk mailing list, to avoid lockups with system calls.
348
350
349 # class attribute to indicate whether the class supports threads or not.
351 # class attribute to indicate whether the class supports threads or not.
350 # Subclasses with thread support should override this as needed.
352 # Subclasses with thread support should override this as needed.
351 isthreaded = True
353 isthreaded = True
352
354
353 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
355 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
354 user_ns=None,user_global_ns=None,banner2='',
356 user_ns=None,user_global_ns=None,banner2='',
355 gui_timeout=GUI_TIMEOUT,**kw):
357 gui_timeout=GUI_TIMEOUT,**kw):
356 """Similar to the normal InteractiveShell, but with threading control"""
358 """Similar to the normal InteractiveShell, but with threading control"""
357
359
358 InteractiveShell.__init__(self,name,usage,rc,user_ns,
360 InteractiveShell.__init__(self,name,usage,rc,user_ns,
359 user_global_ns,banner2)
361 user_global_ns,banner2)
360
362
361 # Timeout we wait for GUI thread
363 # Timeout we wait for GUI thread
362 self.gui_timeout = gui_timeout
364 self.gui_timeout = gui_timeout
363
365
364 # A queue to hold the code to be executed.
366 # A queue to hold the code to be executed.
365 self.code_queue = Queue.Queue()
367 self.code_queue = Queue.Queue()
366
368
367 # Stuff to do at closing time
369 # Stuff to do at closing time
368 self._kill = None
370 self._kill = None
369 on_kill = kw.get('on_kill', [])
371 on_kill = kw.get('on_kill', [])
370 # Check that all things to kill are callable:
372 # Check that all things to kill are callable:
371 for t in on_kill:
373 for t in on_kill:
372 if not callable(t):
374 if not callable(t):
373 raise TypeError,'on_kill must be a list of callables'
375 raise TypeError,'on_kill must be a list of callables'
374 self.on_kill = on_kill
376 self.on_kill = on_kill
375 # thread identity of the "worker thread" (that may execute code directly)
377 # thread identity of the "worker thread" (that may execute code directly)
376 self.worker_ident = None
378 self.worker_ident = None
377
379
378 def runsource(self, source, filename="<input>", symbol="single"):
380 def runsource(self, source, filename="<input>", symbol="single"):
379 """Compile and run some source in the interpreter.
381 """Compile and run some source in the interpreter.
380
382
381 Modified version of code.py's runsource(), to handle threading issues.
383 Modified version of code.py's runsource(), to handle threading issues.
382 See the original for full docstring details."""
384 See the original for full docstring details."""
383
385
384 global KBINT
386 global KBINT
385
387
386 # If Ctrl-C was typed, we reset the flag and return right away
388 # If Ctrl-C was typed, we reset the flag and return right away
387 if KBINT:
389 if KBINT:
388 KBINT = False
390 KBINT = False
389 return False
391 return False
390
392
391 if self._kill:
393 if self._kill:
392 # can't queue new code if we are being killed
394 # can't queue new code if we are being killed
393 return True
395 return True
394
396
395 try:
397 try:
396 code = self.compile(source, filename, symbol)
398 code = self.compile(source, filename, symbol)
397 except (OverflowError, SyntaxError, ValueError):
399 except (OverflowError, SyntaxError, ValueError):
398 # Case 1
400 # Case 1
399 self.showsyntaxerror(filename)
401 self.showsyntaxerror(filename)
400 return False
402 return False
401
403
402 if code is None:
404 if code is None:
403 # Case 2
405 # Case 2
404 return True
406 return True
405
407
406 # shortcut - if we are in worker thread, or the worker thread is not
408 # shortcut - if we are in worker thread, or the worker thread is not
407 # running, execute directly (to allow recursion and prevent deadlock if
409 # running, execute directly (to allow recursion and prevent deadlock if
408 # code is run early in IPython construction)
410 # code is run early in IPython construction)
409
411
410 if (self.worker_ident is None
412 if (self.worker_ident is None
411 or self.worker_ident == thread.get_ident() ):
413 or self.worker_ident == thread.get_ident() ):
412 InteractiveShell.runcode(self,code)
414 InteractiveShell.runcode(self,code)
413 return False
415 return False
414
416
415 # Case 3
417 # Case 3
416 # Store code in queue, so the execution thread can handle it.
418 # Store code in queue, so the execution thread can handle it.
417
419
418 completed_ev, received_ev = threading.Event(), threading.Event()
420 completed_ev, received_ev = threading.Event(), threading.Event()
419
421
420 self.code_queue.put((code,completed_ev, received_ev))
422 self.code_queue.put((code,completed_ev, received_ev))
421 # first make sure the message was received, with timeout
423 # first make sure the message was received, with timeout
422 received_ev.wait(self.gui_timeout)
424 received_ev.wait(self.gui_timeout)
423 if not received_ev.isSet():
425 if not received_ev.isSet():
424 # the mainloop is dead, start executing code directly
426 # the mainloop is dead, start executing code directly
425 print "Warning: Timeout for mainloop thread exceeded"
427 print "Warning: Timeout for mainloop thread exceeded"
426 print "switching to nonthreaded mode (until mainloop wakes up again)"
428 print "switching to nonthreaded mode (until mainloop wakes up again)"
427 self.worker_ident = None
429 self.worker_ident = None
428 else:
430 else:
429 completed_ev.wait()
431 completed_ev.wait()
430 return False
432 return False
431
433
432 def runcode(self):
434 def runcode(self):
433 """Execute a code object.
435 """Execute a code object.
434
436
435 Multithreaded wrapper around IPython's runcode()."""
437 Multithreaded wrapper around IPython's runcode()."""
436
438
437 global CODE_RUN
439 global CODE_RUN
438
440
439 # we are in worker thread, stash out the id for runsource()
441 # we are in worker thread, stash out the id for runsource()
440 self.worker_ident = thread.get_ident()
442 self.worker_ident = thread.get_ident()
441
443
442 if self._kill:
444 if self._kill:
443 print >>Term.cout, 'Closing threads...',
445 print >>Term.cout, 'Closing threads...',
444 Term.cout.flush()
446 Term.cout.flush()
445 for tokill in self.on_kill:
447 for tokill in self.on_kill:
446 tokill()
448 tokill()
447 print >>Term.cout, 'Done.'
449 print >>Term.cout, 'Done.'
448 # allow kill() to return
450 # allow kill() to return
449 self._kill.set()
451 self._kill.set()
450 return True
452 return True
451
453
452 # Install sigint handler. We do it every time to ensure that if user
454 # Install sigint handler. We do it every time to ensure that if user
453 # code modifies it, we restore our own handling.
455 # code modifies it, we restore our own handling.
454 try:
456 try:
455 signal(SIGINT,sigint_handler)
457 signal(SIGINT,sigint_handler)
456 except SystemError:
458 except SystemError:
457 # This happens under Windows, which seems to have all sorts
459 # This happens under Windows, which seems to have all sorts
458 # of problems with signal handling. Oh well...
460 # of problems with signal handling. Oh well...
459 pass
461 pass
460
462
461 # Flush queue of pending code by calling the run methood of the parent
463 # Flush queue of pending code by calling the run methood of the parent
462 # class with all items which may be in the queue.
464 # class with all items which may be in the queue.
463 code_to_run = None
465 code_to_run = None
464 while 1:
466 while 1:
465 try:
467 try:
466 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
468 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
467 except Queue.Empty:
469 except Queue.Empty:
468 break
470 break
469 received_ev.set()
471 received_ev.set()
470
472
471 # Exceptions need to be raised differently depending on which
473 # Exceptions need to be raised differently depending on which
472 # thread is active. This convoluted try/except is only there to
474 # thread is active. This convoluted try/except is only there to
473 # protect against asynchronous exceptions, to ensure that a KBINT
475 # protect against asynchronous exceptions, to ensure that a KBINT
474 # at the wrong time doesn't deadlock everything. The global
476 # at the wrong time doesn't deadlock everything. The global
475 # CODE_TO_RUN is set to true/false as close as possible to the
477 # CODE_TO_RUN is set to true/false as close as possible to the
476 # runcode() call, so that the KBINT handler is correctly informed.
478 # runcode() call, so that the KBINT handler is correctly informed.
477 try:
479 try:
478 try:
480 try:
479 CODE_RUN = True
481 CODE_RUN = True
480 InteractiveShell.runcode(self,code_to_run)
482 InteractiveShell.runcode(self,code_to_run)
481 except KeyboardInterrupt:
483 except KeyboardInterrupt:
482 print "Keyboard interrupted in mainloop"
484 print "Keyboard interrupted in mainloop"
483 while not self.code_queue.empty():
485 while not self.code_queue.empty():
484 code, ev1,ev2 = self.code_queue.get_nowait()
486 code, ev1,ev2 = self.code_queue.get_nowait()
485 ev1.set()
487 ev1.set()
486 ev2.set()
488 ev2.set()
487 break
489 break
488 finally:
490 finally:
489 CODE_RUN = False
491 CODE_RUN = False
490 # allow runsource() return from wait
492 # allow runsource() return from wait
491 completed_ev.set()
493 completed_ev.set()
492
494
493
495
494 # This MUST return true for gtk threading to work
496 # This MUST return true for gtk threading to work
495 return True
497 return True
496
498
497 def kill(self):
499 def kill(self):
498 """Kill the thread, returning when it has been shut down."""
500 """Kill the thread, returning when it has been shut down."""
499 self._kill = threading.Event()
501 self._kill = threading.Event()
500 self._kill.wait()
502 self._kill.wait()
501
503
502 class MatplotlibShellBase:
504 class MatplotlibShellBase:
503 """Mixin class to provide the necessary modifications to regular IPython
505 """Mixin class to provide the necessary modifications to regular IPython
504 shell classes for matplotlib support.
506 shell classes for matplotlib support.
505
507
506 Given Python's MRO, this should be used as the FIRST class in the
508 Given Python's MRO, this should be used as the FIRST class in the
507 inheritance hierarchy, so that it overrides the relevant methods."""
509 inheritance hierarchy, so that it overrides the relevant methods."""
508
510
509 def _matplotlib_config(self,name,user_ns,user_global_ns=None):
511 def _matplotlib_config(self,name,user_ns,user_global_ns=None):
510 """Return items needed to setup the user's shell with matplotlib"""
512 """Return items needed to setup the user's shell with matplotlib"""
511
513
512 # Initialize matplotlib to interactive mode always
514 # Initialize matplotlib to interactive mode always
513 import matplotlib
515 import matplotlib
514 from matplotlib import backends
516 from matplotlib import backends
515 matplotlib.interactive(True)
517 matplotlib.interactive(True)
516
518
517 def use(arg):
519 def use(arg):
518 """IPython wrapper for matplotlib's backend switcher.
520 """IPython wrapper for matplotlib's backend switcher.
519
521
520 In interactive use, we can not allow switching to a different
522 In interactive use, we can not allow switching to a different
521 interactive backend, since thread conflicts will most likely crash
523 interactive backend, since thread conflicts will most likely crash
522 the python interpreter. This routine does a safety check first,
524 the python interpreter. This routine does a safety check first,
523 and refuses to perform a dangerous switch. It still allows
525 and refuses to perform a dangerous switch. It still allows
524 switching to non-interactive backends."""
526 switching to non-interactive backends."""
525
527
526 if arg in backends.interactive_bk and arg != self.mpl_backend:
528 if arg in backends.interactive_bk and arg != self.mpl_backend:
527 m=('invalid matplotlib backend switch.\n'
529 m=('invalid matplotlib backend switch.\n'
528 'This script attempted to switch to the interactive '
530 'This script attempted to switch to the interactive '
529 'backend: `%s`\n'
531 'backend: `%s`\n'
530 'Your current choice of interactive backend is: `%s`\n\n'
532 'Your current choice of interactive backend is: `%s`\n\n'
531 'Switching interactive matplotlib backends at runtime\n'
533 'Switching interactive matplotlib backends at runtime\n'
532 'would crash the python interpreter, '
534 'would crash the python interpreter, '
533 'and IPython has blocked it.\n\n'
535 'and IPython has blocked it.\n\n'
534 'You need to either change your choice of matplotlib backend\n'
536 'You need to either change your choice of matplotlib backend\n'
535 'by editing your .matplotlibrc file, or run this script as a \n'
537 'by editing your .matplotlibrc file, or run this script as a \n'
536 'standalone file from the command line, not using IPython.\n' %
538 'standalone file from the command line, not using IPython.\n' %
537 (arg,self.mpl_backend) )
539 (arg,self.mpl_backend) )
538 raise RuntimeError, m
540 raise RuntimeError, m
539 else:
541 else:
540 self.mpl_use(arg)
542 self.mpl_use(arg)
541 self.mpl_use._called = True
543 self.mpl_use._called = True
542
544
543 self.matplotlib = matplotlib
545 self.matplotlib = matplotlib
544 self.mpl_backend = matplotlib.rcParams['backend']
546 self.mpl_backend = matplotlib.rcParams['backend']
545
547
546 # we also need to block switching of interactive backends by use()
548 # we also need to block switching of interactive backends by use()
547 self.mpl_use = matplotlib.use
549 self.mpl_use = matplotlib.use
548 self.mpl_use._called = False
550 self.mpl_use._called = False
549 # overwrite the original matplotlib.use with our wrapper
551 # overwrite the original matplotlib.use with our wrapper
550 matplotlib.use = use
552 matplotlib.use = use
551
553
552 # This must be imported last in the matplotlib series, after
554 # This must be imported last in the matplotlib series, after
553 # backend/interactivity choices have been made
555 # backend/interactivity choices have been made
554 import matplotlib.pylab as pylab
556 import matplotlib.pylab as pylab
555 self.pylab = pylab
557 self.pylab = pylab
556
558
557 self.pylab.show._needmain = False
559 self.pylab.show._needmain = False
558 # We need to detect at runtime whether show() is called by the user.
560 # We need to detect at runtime whether show() is called by the user.
559 # For this, we wrap it into a decorator which adds a 'called' flag.
561 # For this, we wrap it into a decorator which adds a 'called' flag.
560 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
562 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
561
563
562 # Build a user namespace initialized with matplotlib/matlab features.
564 # Build a user namespace initialized with matplotlib/matlab features.
563 user_ns, user_global_ns = IPython.ipapi.make_user_namespaces(user_ns,
565 user_ns, user_global_ns = IPython.ipapi.make_user_namespaces(user_ns,
564 user_global_ns)
566 user_global_ns)
565
567
566 # Import numpy as np/pyplot as plt are conventions we're trying to
568 # Import numpy as np/pyplot as plt are conventions we're trying to
567 # somewhat standardize on. Making them available to users by default
569 # somewhat standardize on. Making them available to users by default
568 # will greatly help this.
570 # will greatly help this.
569 exec ("import numpy\n"
571 exec ("import numpy\n"
570 "import numpy as np\n"
572 "import numpy as np\n"
571 "import matplotlib\n"
573 "import matplotlib\n"
572 "import matplotlib.pylab as pylab\n"
574 "import matplotlib.pylab as pylab\n"
573 "try:\n"
575 "try:\n"
574 " import matplotlib.pyplot as plt\n"
576 " import matplotlib.pyplot as plt\n"
575 "except ImportError:\n"
577 "except ImportError:\n"
576 " pass\n"
578 " pass\n"
577 ) in user_ns
579 ) in user_ns
578
580
579 # Build matplotlib info banner
581 # Build matplotlib info banner
580 b="""
582 b="""
581 Welcome to pylab, a matplotlib-based Python environment.
583 Welcome to pylab, a matplotlib-based Python environment.
582 For more information, type 'help(pylab)'.
584 For more information, type 'help(pylab)'.
583 """
585 """
584 return user_ns,user_global_ns,b
586 return user_ns,user_global_ns,b
585
587
586 def mplot_exec(self,fname,*where,**kw):
588 def mplot_exec(self,fname,*where,**kw):
587 """Execute a matplotlib script.
589 """Execute a matplotlib script.
588
590
589 This is a call to execfile(), but wrapped in safeties to properly
591 This is a call to execfile(), but wrapped in safeties to properly
590 handle interactive rendering and backend switching."""
592 handle interactive rendering and backend switching."""
591
593
592 #print '*** Matplotlib runner ***' # dbg
594 #print '*** Matplotlib runner ***' # dbg
593 # turn off rendering until end of script
595 # turn off rendering until end of script
594 isInteractive = self.matplotlib.rcParams['interactive']
596 isInteractive = self.matplotlib.rcParams['interactive']
595 self.matplotlib.interactive(False)
597 self.matplotlib.interactive(False)
596 self.safe_execfile(fname,*where,**kw)
598 self.safe_execfile(fname,*where,**kw)
597 self.matplotlib.interactive(isInteractive)
599 self.matplotlib.interactive(isInteractive)
598 # make rendering call now, if the user tried to do it
600 # make rendering call now, if the user tried to do it
599 if self.pylab.draw_if_interactive.called:
601 if self.pylab.draw_if_interactive.called:
600 self.pylab.draw()
602 self.pylab.draw()
601 self.pylab.draw_if_interactive.called = False
603 self.pylab.draw_if_interactive.called = False
602
604
603 # if a backend switch was performed, reverse it now
605 # if a backend switch was performed, reverse it now
604 if self.mpl_use._called:
606 if self.mpl_use._called:
605 self.matplotlib.rcParams['backend'] = self.mpl_backend
607 self.matplotlib.rcParams['backend'] = self.mpl_backend
606
608
607 @testdec.skip_doctest
609 @testdec.skip_doctest
608 def magic_run(self,parameter_s=''):
610 def magic_run(self,parameter_s=''):
609 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
611 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
610
612
611 # Fix the docstring so users see the original as well
613 # Fix the docstring so users see the original as well
612 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
614 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
613 "\n *** Modified %run for Matplotlib,"
615 "\n *** Modified %run for Matplotlib,"
614 " with proper interactive handling ***")
616 " with proper interactive handling ***")
615
617
616 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
618 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
617 # and multithreaded. Note that these are meant for internal use, the IPShell*
619 # and multithreaded. Note that these are meant for internal use, the IPShell*
618 # classes below are the ones meant for public consumption.
620 # classes below are the ones meant for public consumption.
619
621
620 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
622 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
621 """Single-threaded shell with matplotlib support."""
623 """Single-threaded shell with matplotlib support."""
622
624
623 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
625 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
624 user_ns=None,user_global_ns=None,**kw):
626 user_ns=None,user_global_ns=None,**kw):
625 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
627 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
626 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
628 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
627 banner2=b2,**kw)
629 banner2=b2,**kw)
628
630
629 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
631 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
630 """Multi-threaded shell with matplotlib support."""
632 """Multi-threaded shell with matplotlib support."""
631
633
632 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
634 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
633 user_ns=None,user_global_ns=None, **kw):
635 user_ns=None,user_global_ns=None, **kw):
634 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
636 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
635 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
637 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
636 banner2=b2,**kw)
638 banner2=b2,**kw)
637
639
638 #-----------------------------------------------------------------------------
640 #-----------------------------------------------------------------------------
639 # Utility functions for the different GUI enabled IPShell* classes.
641 # Utility functions for the different GUI enabled IPShell* classes.
640
642
641 def get_tk():
643 def get_tk():
642 """Tries to import Tkinter and returns a withdrawn Tkinter root
644 """Tries to import Tkinter and returns a withdrawn Tkinter root
643 window. If Tkinter is already imported or not available, this
645 window. If Tkinter is already imported or not available, this
644 returns None. This function calls `hijack_tk` underneath.
646 returns None. This function calls `hijack_tk` underneath.
645 """
647 """
646 if not USE_TK or sys.modules.has_key('Tkinter'):
648 if not USE_TK or sys.modules.has_key('Tkinter'):
647 return None
649 return None
648 else:
650 else:
649 try:
651 try:
650 import Tkinter
652 import Tkinter
651 except ImportError:
653 except ImportError:
652 return None
654 return None
653 else:
655 else:
654 hijack_tk()
656 hijack_tk()
655 r = Tkinter.Tk()
657 r = Tkinter.Tk()
656 r.withdraw()
658 r.withdraw()
657 return r
659 return r
658
660
659 def hijack_tk():
661 def hijack_tk():
660 """Modifies Tkinter's mainloop with a dummy so when a module calls
662 """Modifies Tkinter's mainloop with a dummy so when a module calls
661 mainloop, it does not block.
663 mainloop, it does not block.
662
664
663 """
665 """
664 def misc_mainloop(self, n=0):
666 def misc_mainloop(self, n=0):
665 pass
667 pass
666 def tkinter_mainloop(n=0):
668 def tkinter_mainloop(n=0):
667 pass
669 pass
668
670
669 import Tkinter
671 import Tkinter
670 Tkinter.Misc.mainloop = misc_mainloop
672 Tkinter.Misc.mainloop = misc_mainloop
671 Tkinter.mainloop = tkinter_mainloop
673 Tkinter.mainloop = tkinter_mainloop
672
674
673 def update_tk(tk):
675 def update_tk(tk):
674 """Updates the Tkinter event loop. This is typically called from
676 """Updates the Tkinter event loop. This is typically called from
675 the respective WX or GTK mainloops.
677 the respective WX or GTK mainloops.
676 """
678 """
677 if tk:
679 if tk:
678 tk.update()
680 tk.update()
679
681
680 def hijack_wx():
682 def hijack_wx():
681 """Modifies wxPython's MainLoop with a dummy so user code does not
683 """Modifies wxPython's MainLoop with a dummy so user code does not
682 block IPython. The hijacked mainloop function is returned.
684 block IPython. The hijacked mainloop function is returned.
683 """
685 """
684 def dummy_mainloop(*args, **kw):
686 def dummy_mainloop(*args, **kw):
685 pass
687 pass
686
688
687 try:
689 try:
688 import wx
690 import wx
689 except ImportError:
691 except ImportError:
690 # For very old versions of WX
692 # For very old versions of WX
691 import wxPython as wx
693 import wxPython as wx
692
694
693 ver = wx.__version__
695 ver = wx.__version__
694 orig_mainloop = None
696 orig_mainloop = None
695 if ver[:3] >= '2.5':
697 if ver[:3] >= '2.5':
696 import wx
698 import wx
697 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
699 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
698 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
700 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
699 else: raise AttributeError('Could not find wx core module')
701 else: raise AttributeError('Could not find wx core module')
700 orig_mainloop = core.PyApp_MainLoop
702 orig_mainloop = core.PyApp_MainLoop
701 core.PyApp_MainLoop = dummy_mainloop
703 core.PyApp_MainLoop = dummy_mainloop
702 elif ver[:3] == '2.4':
704 elif ver[:3] == '2.4':
703 orig_mainloop = wx.wxc.wxPyApp_MainLoop
705 orig_mainloop = wx.wxc.wxPyApp_MainLoop
704 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
706 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
705 else:
707 else:
706 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
708 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
707 return orig_mainloop
709 return orig_mainloop
708
710
709 def hijack_gtk():
711 def hijack_gtk():
710 """Modifies pyGTK's mainloop with a dummy so user code does not
712 """Modifies pyGTK's mainloop with a dummy so user code does not
711 block IPython. This function returns the original `gtk.mainloop`
713 block IPython. This function returns the original `gtk.mainloop`
712 function that has been hijacked.
714 function that has been hijacked.
713 """
715 """
714 def dummy_mainloop(*args, **kw):
716 def dummy_mainloop(*args, **kw):
715 pass
717 pass
716 import gtk
718 import gtk
717 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
719 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
718 else: orig_mainloop = gtk.mainloop
720 else: orig_mainloop = gtk.mainloop
719 gtk.mainloop = dummy_mainloop
721 gtk.mainloop = dummy_mainloop
720 gtk.main = dummy_mainloop
722 gtk.main = dummy_mainloop
721 return orig_mainloop
723 return orig_mainloop
722
724
723 def hijack_qt():
725 def hijack_qt():
724 """Modifies PyQt's mainloop with a dummy so user code does not
726 """Modifies PyQt's mainloop with a dummy so user code does not
725 block IPython. This function returns the original
727 block IPython. This function returns the original
726 `qt.qApp.exec_loop` function that has been hijacked.
728 `qt.qApp.exec_loop` function that has been hijacked.
727 """
729 """
728 def dummy_mainloop(*args, **kw):
730 def dummy_mainloop(*args, **kw):
729 pass
731 pass
730 import qt
732 import qt
731 orig_mainloop = qt.qApp.exec_loop
733 orig_mainloop = qt.qApp.exec_loop
732 qt.qApp.exec_loop = dummy_mainloop
734 qt.qApp.exec_loop = dummy_mainloop
733 qt.QApplication.exec_loop = dummy_mainloop
735 qt.QApplication.exec_loop = dummy_mainloop
734 return orig_mainloop
736 return orig_mainloop
735
737
736 def hijack_qt4():
738 def hijack_qt4():
737 """Modifies PyQt4's mainloop with a dummy so user code does not
739 """Modifies PyQt4's mainloop with a dummy so user code does not
738 block IPython. This function returns the original
740 block IPython. This function returns the original
739 `QtGui.qApp.exec_` function that has been hijacked.
741 `QtGui.qApp.exec_` function that has been hijacked.
740 """
742 """
741 def dummy_mainloop(*args, **kw):
743 def dummy_mainloop(*args, **kw):
742 pass
744 pass
743 from PyQt4 import QtGui, QtCore
745 from PyQt4 import QtGui, QtCore
744 orig_mainloop = QtGui.qApp.exec_
746 orig_mainloop = QtGui.qApp.exec_
745 QtGui.qApp.exec_ = dummy_mainloop
747 QtGui.qApp.exec_ = dummy_mainloop
746 QtGui.QApplication.exec_ = dummy_mainloop
748 QtGui.QApplication.exec_ = dummy_mainloop
747 QtCore.QCoreApplication.exec_ = dummy_mainloop
749 QtCore.QCoreApplication.exec_ = dummy_mainloop
748 return orig_mainloop
750 return orig_mainloop
749
751
750 #-----------------------------------------------------------------------------
752 #-----------------------------------------------------------------------------
751 # The IPShell* classes below are the ones meant to be run by external code as
753 # The IPShell* classes below are the ones meant to be run by external code as
752 # IPython instances. Note that unless a specific threading strategy is
754 # IPython instances. Note that unless a specific threading strategy is
753 # desired, the factory function start() below should be used instead (it
755 # desired, the factory function start() below should be used instead (it
754 # selects the proper threaded class).
756 # selects the proper threaded class).
755
757
756 class IPThread(threading.Thread):
758 class IPThread(threading.Thread):
757 def run(self):
759 def run(self):
758 self.IP.mainloop(self._banner)
760 self.IP.mainloop(self._banner)
759 self.IP.kill()
761 self.IP.kill()
760
762
761 class IPShellGTK(IPThread):
763 class IPShellGTK(IPThread):
762 """Run a gtk mainloop() in a separate thread.
764 """Run a gtk mainloop() in a separate thread.
763
765
764 Python commands can be passed to the thread where they will be executed.
766 Python commands can be passed to the thread where they will be executed.
765 This is implemented by periodically checking for passed code using a
767 This is implemented by periodically checking for passed code using a
766 GTK timeout callback."""
768 GTK timeout callback."""
767
769
768 TIMEOUT = 100 # Millisecond interval between timeouts.
770 TIMEOUT = 100 # Millisecond interval between timeouts.
769
771
770 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
772 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
771 debug=1,shell_class=MTInteractiveShell):
773 debug=1,shell_class=MTInteractiveShell):
772
774
773 import gtk
775 import gtk
774 # Check for set_interactive, coming up in new pygtk.
776 # Check for set_interactive, coming up in new pygtk.
775 # Disable it so that this code works, but notify
777 # Disable it so that this code works, but notify
776 # the user that he has a better option as well.
778 # the user that he has a better option as well.
777 # XXX TODO better support when set_interactive is released
779 # XXX TODO better support when set_interactive is released
778 try:
780 try:
779 gtk.set_interactive(False)
781 gtk.set_interactive(False)
780 print "Your PyGtk has set_interactive(), so you can use the"
782 print "Your PyGtk has set_interactive(), so you can use the"
781 print "more stable single-threaded Gtk mode."
783 print "more stable single-threaded Gtk mode."
782 print "See https://bugs.launchpad.net/ipython/+bug/270856"
784 print "See https://bugs.launchpad.net/ipython/+bug/270856"
783 except AttributeError:
785 except AttributeError:
784 pass
786 pass
785
787
786 self.gtk = gtk
788 self.gtk = gtk
787 self.gtk_mainloop = hijack_gtk()
789 self.gtk_mainloop = hijack_gtk()
788
790
789 # Allows us to use both Tk and GTK.
791 # Allows us to use both Tk and GTK.
790 self.tk = get_tk()
792 self.tk = get_tk()
791
793
792 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
794 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
793 else: mainquit = self.gtk.mainquit
795 else: mainquit = self.gtk.mainquit
794
796
795 self.IP = make_IPython(argv,user_ns=user_ns,
797 self.IP = make_IPython(argv,user_ns=user_ns,
796 user_global_ns=user_global_ns,
798 user_global_ns=user_global_ns,
797 debug=debug,
799 debug=debug,
798 shell_class=shell_class,
800 shell_class=shell_class,
799 on_kill=[mainquit])
801 on_kill=[mainquit])
800
802
801 # HACK: slot for banner in self; it will be passed to the mainloop
803 # HACK: slot for banner in self; it will be passed to the mainloop
802 # method only and .run() needs it. The actual value will be set by
804 # method only and .run() needs it. The actual value will be set by
803 # .mainloop().
805 # .mainloop().
804 self._banner = None
806 self._banner = None
805
807
806 threading.Thread.__init__(self)
808 threading.Thread.__init__(self)
807
809
808 def mainloop(self,sys_exit=0,banner=None):
810 def mainloop(self,sys_exit=0,banner=None):
809
811
810 self._banner = banner
812 self._banner = banner
811
813
812 if self.gtk.pygtk_version >= (2,4,0):
814 if self.gtk.pygtk_version >= (2,4,0):
813 import gobject
815 import gobject
814 gobject.idle_add(self.on_timer)
816 gobject.idle_add(self.on_timer)
815 else:
817 else:
816 self.gtk.idle_add(self.on_timer)
818 self.gtk.idle_add(self.on_timer)
817
819
818 if sys.platform != 'win32':
820 if sys.platform != 'win32':
819 try:
821 try:
820 if self.gtk.gtk_version[0] >= 2:
822 if self.gtk.gtk_version[0] >= 2:
821 self.gtk.gdk.threads_init()
823 self.gtk.gdk.threads_init()
822 except AttributeError:
824 except AttributeError:
823 pass
825 pass
824 except RuntimeError:
826 except RuntimeError:
825 error('Your pyGTK likely has not been compiled with '
827 error('Your pyGTK likely has not been compiled with '
826 'threading support.\n'
828 'threading support.\n'
827 'The exception printout is below.\n'
829 'The exception printout is below.\n'
828 'You can either rebuild pyGTK with threads, or '
830 'You can either rebuild pyGTK with threads, or '
829 'try using \n'
831 'try using \n'
830 'matplotlib with a different backend (like Tk or WX).\n'
832 'matplotlib with a different backend (like Tk or WX).\n'
831 'Note that matplotlib will most likely not work in its '
833 'Note that matplotlib will most likely not work in its '
832 'current state!')
834 'current state!')
833 self.IP.InteractiveTB()
835 self.IP.InteractiveTB()
834
836
835 self.start()
837 self.start()
836 self.gtk.gdk.threads_enter()
838 self.gtk.gdk.threads_enter()
837 self.gtk_mainloop()
839 self.gtk_mainloop()
838 self.gtk.gdk.threads_leave()
840 self.gtk.gdk.threads_leave()
839 self.join()
841 self.join()
840
842
841 def on_timer(self):
843 def on_timer(self):
842 """Called when GTK is idle.
844 """Called when GTK is idle.
843
845
844 Must return True always, otherwise GTK stops calling it"""
846 Must return True always, otherwise GTK stops calling it"""
845
847
846 update_tk(self.tk)
848 update_tk(self.tk)
847 self.IP.runcode()
849 self.IP.runcode()
848 time.sleep(0.01)
850 time.sleep(0.01)
849 return True
851 return True
850
852
851
853
852 class IPShellWX(IPThread):
854 class IPShellWX(IPThread):
853 """Run a wx mainloop() in a separate thread.
855 """Run a wx mainloop() in a separate thread.
854
856
855 Python commands can be passed to the thread where they will be executed.
857 Python commands can be passed to the thread where they will be executed.
856 This is implemented by periodically checking for passed code using a
858 This is implemented by periodically checking for passed code using a
857 GTK timeout callback."""
859 GTK timeout callback."""
858
860
859 TIMEOUT = 100 # Millisecond interval between timeouts.
861 TIMEOUT = 100 # Millisecond interval between timeouts.
860
862
861 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
863 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
862 debug=1,shell_class=MTInteractiveShell):
864 debug=1,shell_class=MTInteractiveShell):
863
865
864 self.IP = make_IPython(argv,user_ns=user_ns,
866 self.IP = make_IPython(argv,user_ns=user_ns,
865 user_global_ns=user_global_ns,
867 user_global_ns=user_global_ns,
866 debug=debug,
868 debug=debug,
867 shell_class=shell_class,
869 shell_class=shell_class,
868 on_kill=[self.wxexit])
870 on_kill=[self.wxexit])
869
871
870 wantedwxversion=self.IP.rc.wxversion
872 wantedwxversion=self.IP.rc.wxversion
871 if wantedwxversion!="0":
873 if wantedwxversion!="0":
872 try:
874 try:
873 import wxversion
875 import wxversion
874 except ImportError:
876 except ImportError:
875 error('The wxversion module is needed for WX version selection')
877 error('The wxversion module is needed for WX version selection')
876 else:
878 else:
877 try:
879 try:
878 wxversion.select(wantedwxversion)
880 wxversion.select(wantedwxversion)
879 except:
881 except:
880 self.IP.InteractiveTB()
882 self.IP.InteractiveTB()
881 error('Requested wxPython version %s could not be loaded' %
883 error('Requested wxPython version %s could not be loaded' %
882 wantedwxversion)
884 wantedwxversion)
883
885
884 import wx
886 import wx
885
887
886 threading.Thread.__init__(self)
888 threading.Thread.__init__(self)
887 self.wx = wx
889 self.wx = wx
888 self.wx_mainloop = hijack_wx()
890 self.wx_mainloop = hijack_wx()
889
891
890 # Allows us to use both Tk and GTK.
892 # Allows us to use both Tk and GTK.
891 self.tk = get_tk()
893 self.tk = get_tk()
892
894
893 # HACK: slot for banner in self; it will be passed to the mainloop
895 # HACK: slot for banner in self; it will be passed to the mainloop
894 # method only and .run() needs it. The actual value will be set by
896 # method only and .run() needs it. The actual value will be set by
895 # .mainloop().
897 # .mainloop().
896 self._banner = None
898 self._banner = None
897
899
898 self.app = None
900 self.app = None
899
901
900 def wxexit(self, *args):
902 def wxexit(self, *args):
901 if self.app is not None:
903 if self.app is not None:
902 self.app.agent.timer.Stop()
904 self.app.agent.timer.Stop()
903 self.app.ExitMainLoop()
905 self.app.ExitMainLoop()
904
906
905 def mainloop(self,sys_exit=0,banner=None):
907 def mainloop(self,sys_exit=0,banner=None):
906
908
907 self._banner = banner
909 self._banner = banner
908
910
909 self.start()
911 self.start()
910
912
911 class TimerAgent(self.wx.MiniFrame):
913 class TimerAgent(self.wx.MiniFrame):
912 wx = self.wx
914 wx = self.wx
913 IP = self.IP
915 IP = self.IP
914 tk = self.tk
916 tk = self.tk
915 def __init__(self, parent, interval):
917 def __init__(self, parent, interval):
916 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
918 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
917 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
919 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
918 size=(100, 100),style=style)
920 size=(100, 100),style=style)
919 self.Show(False)
921 self.Show(False)
920 self.interval = interval
922 self.interval = interval
921 self.timerId = self.wx.NewId()
923 self.timerId = self.wx.NewId()
922
924
923 def StartWork(self):
925 def StartWork(self):
924 self.timer = self.wx.Timer(self, self.timerId)
926 self.timer = self.wx.Timer(self, self.timerId)
925 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
927 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
926 self.timer.Start(self.interval)
928 self.timer.Start(self.interval)
927
929
928 def OnTimer(self, event):
930 def OnTimer(self, event):
929 update_tk(self.tk)
931 update_tk(self.tk)
930 self.IP.runcode()
932 self.IP.runcode()
931
933
932 class App(self.wx.App):
934 class App(self.wx.App):
933 wx = self.wx
935 wx = self.wx
934 TIMEOUT = self.TIMEOUT
936 TIMEOUT = self.TIMEOUT
935 def OnInit(self):
937 def OnInit(self):
936 'Create the main window and insert the custom frame'
938 'Create the main window and insert the custom frame'
937 self.agent = TimerAgent(None, self.TIMEOUT)
939 self.agent = TimerAgent(None, self.TIMEOUT)
938 self.agent.Show(False)
940 self.agent.Show(False)
939 self.agent.StartWork()
941 self.agent.StartWork()
940 return True
942 return True
941
943
942 self.app = App(redirect=False)
944 self.app = App(redirect=False)
943 self.wx_mainloop(self.app)
945 self.wx_mainloop(self.app)
944 self.join()
946 self.join()
945
947
946
948
947 class IPShellQt(IPThread):
949 class IPShellQt(IPThread):
948 """Run a Qt event loop in a separate thread.
950 """Run a Qt event loop in a separate thread.
949
951
950 Python commands can be passed to the thread where they will be executed.
952 Python commands can be passed to the thread where they will be executed.
951 This is implemented by periodically checking for passed code using a
953 This is implemented by periodically checking for passed code using a
952 Qt timer / slot."""
954 Qt timer / slot."""
953
955
954 TIMEOUT = 100 # Millisecond interval between timeouts.
956 TIMEOUT = 100 # Millisecond interval between timeouts.
955
957
956 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
958 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
957 debug=0, shell_class=MTInteractiveShell):
959 debug=0, shell_class=MTInteractiveShell):
958
960
959 import qt
961 import qt
960
962
961 self.exec_loop = hijack_qt()
963 self.exec_loop = hijack_qt()
962
964
963 # Allows us to use both Tk and QT.
965 # Allows us to use both Tk and QT.
964 self.tk = get_tk()
966 self.tk = get_tk()
965
967
966 self.IP = make_IPython(argv,
968 self.IP = make_IPython(argv,
967 user_ns=user_ns,
969 user_ns=user_ns,
968 user_global_ns=user_global_ns,
970 user_global_ns=user_global_ns,
969 debug=debug,
971 debug=debug,
970 shell_class=shell_class,
972 shell_class=shell_class,
971 on_kill=[qt.qApp.exit])
973 on_kill=[qt.qApp.exit])
972
974
973 # HACK: slot for banner in self; it will be passed to the mainloop
975 # HACK: slot for banner in self; it will be passed to the mainloop
974 # method only and .run() needs it. The actual value will be set by
976 # method only and .run() needs it. The actual value will be set by
975 # .mainloop().
977 # .mainloop().
976 self._banner = None
978 self._banner = None
977
979
978 threading.Thread.__init__(self)
980 threading.Thread.__init__(self)
979
981
980 def mainloop(self, sys_exit=0, banner=None):
982 def mainloop(self, sys_exit=0, banner=None):
981
983
982 import qt
984 import qt
983
985
984 self._banner = banner
986 self._banner = banner
985
987
986 if qt.QApplication.startingUp():
988 if qt.QApplication.startingUp():
987 a = qt.QApplication(sys.argv)
989 a = qt.QApplication(sys.argv)
988
990
989 self.timer = qt.QTimer()
991 self.timer = qt.QTimer()
990 qt.QObject.connect(self.timer,
992 qt.QObject.connect(self.timer,
991 qt.SIGNAL('timeout()'),
993 qt.SIGNAL('timeout()'),
992 self.on_timer)
994 self.on_timer)
993
995
994 self.start()
996 self.start()
995 self.timer.start(self.TIMEOUT, True)
997 self.timer.start(self.TIMEOUT, True)
996 while True:
998 while True:
997 if self.IP._kill: break
999 if self.IP._kill: break
998 self.exec_loop()
1000 self.exec_loop()
999 self.join()
1001 self.join()
1000
1002
1001 def on_timer(self):
1003 def on_timer(self):
1002 update_tk(self.tk)
1004 update_tk(self.tk)
1003 result = self.IP.runcode()
1005 result = self.IP.runcode()
1004 self.timer.start(self.TIMEOUT, True)
1006 self.timer.start(self.TIMEOUT, True)
1005 return result
1007 return result
1006
1008
1007
1009
1008 class IPShellQt4(IPThread):
1010 class IPShellQt4(IPThread):
1009 """Run a Qt event loop in a separate thread.
1011 """Run a Qt event loop in a separate thread.
1010
1012
1011 Python commands can be passed to the thread where they will be executed.
1013 Python commands can be passed to the thread where they will be executed.
1012 This is implemented by periodically checking for passed code using a
1014 This is implemented by periodically checking for passed code using a
1013 Qt timer / slot."""
1015 Qt timer / slot."""
1014
1016
1015 TIMEOUT = 100 # Millisecond interval between timeouts.
1017 TIMEOUT = 100 # Millisecond interval between timeouts.
1016
1018
1017 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
1019 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
1018 debug=0, shell_class=MTInteractiveShell):
1020 debug=0, shell_class=MTInteractiveShell):
1019
1021
1020 from PyQt4 import QtCore, QtGui
1022 from PyQt4 import QtCore, QtGui
1021
1023
1022 try:
1024 try:
1023 # present in PyQt4-4.2.1 or later
1025 # present in PyQt4-4.2.1 or later
1024 QtCore.pyqtRemoveInputHook()
1026 QtCore.pyqtRemoveInputHook()
1025 except AttributeError:
1027 except AttributeError:
1026 pass
1028 pass
1027
1029
1028 if QtCore.PYQT_VERSION_STR == '4.3':
1030 if QtCore.PYQT_VERSION_STR == '4.3':
1029 warn('''PyQt4 version 4.3 detected.
1031 warn('''PyQt4 version 4.3 detected.
1030 If you experience repeated threading warnings, please update PyQt4.
1032 If you experience repeated threading warnings, please update PyQt4.
1031 ''')
1033 ''')
1032
1034
1033 self.exec_ = hijack_qt4()
1035 self.exec_ = hijack_qt4()
1034
1036
1035 # Allows us to use both Tk and QT.
1037 # Allows us to use both Tk and QT.
1036 self.tk = get_tk()
1038 self.tk = get_tk()
1037
1039
1038 self.IP = make_IPython(argv,
1040 self.IP = make_IPython(argv,
1039 user_ns=user_ns,
1041 user_ns=user_ns,
1040 user_global_ns=user_global_ns,
1042 user_global_ns=user_global_ns,
1041 debug=debug,
1043 debug=debug,
1042 shell_class=shell_class,
1044 shell_class=shell_class,
1043 on_kill=[QtGui.qApp.exit])
1045 on_kill=[QtGui.qApp.exit])
1044
1046
1045 # HACK: slot for banner in self; it will be passed to the mainloop
1047 # HACK: slot for banner in self; it will be passed to the mainloop
1046 # method only and .run() needs it. The actual value will be set by
1048 # method only and .run() needs it. The actual value will be set by
1047 # .mainloop().
1049 # .mainloop().
1048 self._banner = None
1050 self._banner = None
1049
1051
1050 threading.Thread.__init__(self)
1052 threading.Thread.__init__(self)
1051
1053
1052 def mainloop(self, sys_exit=0, banner=None):
1054 def mainloop(self, sys_exit=0, banner=None):
1053
1055
1054 from PyQt4 import QtCore, QtGui
1056 from PyQt4 import QtCore, QtGui
1055
1057
1056 self._banner = banner
1058 self._banner = banner
1057
1059
1058 if QtGui.QApplication.startingUp():
1060 if QtGui.QApplication.startingUp():
1059 a = QtGui.QApplication(sys.argv)
1061 a = QtGui.QApplication(sys.argv)
1060
1062
1061 self.timer = QtCore.QTimer()
1063 self.timer = QtCore.QTimer()
1062 QtCore.QObject.connect(self.timer,
1064 QtCore.QObject.connect(self.timer,
1063 QtCore.SIGNAL('timeout()'),
1065 QtCore.SIGNAL('timeout()'),
1064 self.on_timer)
1066 self.on_timer)
1065
1067
1066 self.start()
1068 self.start()
1067 self.timer.start(self.TIMEOUT)
1069 self.timer.start(self.TIMEOUT)
1068 while True:
1070 while True:
1069 if self.IP._kill: break
1071 if self.IP._kill: break
1070 self.exec_()
1072 self.exec_()
1071 self.join()
1073 self.join()
1072
1074
1073 def on_timer(self):
1075 def on_timer(self):
1074 update_tk(self.tk)
1076 update_tk(self.tk)
1075 result = self.IP.runcode()
1077 result = self.IP.runcode()
1076 self.timer.start(self.TIMEOUT)
1078 self.timer.start(self.TIMEOUT)
1077 return result
1079 return result
1078
1080
1079
1081
1080 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1082 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1081 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1083 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1082 def _load_pylab(user_ns):
1084 def _load_pylab(user_ns):
1083 """Allow users to disable pulling all of pylab into the top-level
1085 """Allow users to disable pulling all of pylab into the top-level
1084 namespace.
1086 namespace.
1085
1087
1086 This little utility must be called AFTER the actual ipython instance is
1088 This little utility must be called AFTER the actual ipython instance is
1087 running, since only then will the options file have been fully parsed."""
1089 running, since only then will the options file have been fully parsed."""
1088
1090
1089 ip = IPython.ipapi.get()
1091 ip = IPython.ipapi.get()
1090 if ip.options.pylab_import_all:
1092 if ip.options.pylab_import_all:
1091 ip.ex("from matplotlib.pylab import *")
1093 ip.ex("from matplotlib.pylab import *")
1092 ip.IP.user_config_ns.update(ip.user_ns)
1094 ip.IP.user_config_ns.update(ip.user_ns)
1093
1095
1094
1096
1095 class IPShellMatplotlib(IPShell):
1097 class IPShellMatplotlib(IPShell):
1096 """Subclass IPShell with MatplotlibShell as the internal shell.
1098 """Subclass IPShell with MatplotlibShell as the internal shell.
1097
1099
1098 Single-threaded class, meant for the Tk* and FLTK* backends.
1100 Single-threaded class, meant for the Tk* and FLTK* backends.
1099
1101
1100 Having this on a separate class simplifies the external driver code."""
1102 Having this on a separate class simplifies the external driver code."""
1101
1103
1102 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1104 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1103 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1105 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1104 shell_class=MatplotlibShell)
1106 shell_class=MatplotlibShell)
1105 _load_pylab(self.IP.user_ns)
1107 _load_pylab(self.IP.user_ns)
1106
1108
1107 class IPShellMatplotlibGTK(IPShellGTK):
1109 class IPShellMatplotlibGTK(IPShellGTK):
1108 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1110 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1109
1111
1110 Multi-threaded class, meant for the GTK* backends."""
1112 Multi-threaded class, meant for the GTK* backends."""
1111
1113
1112 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1114 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1113 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1115 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1114 shell_class=MatplotlibMTShell)
1116 shell_class=MatplotlibMTShell)
1115 _load_pylab(self.IP.user_ns)
1117 _load_pylab(self.IP.user_ns)
1116
1118
1117 class IPShellMatplotlibWX(IPShellWX):
1119 class IPShellMatplotlibWX(IPShellWX):
1118 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1120 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1119
1121
1120 Multi-threaded class, meant for the WX* backends."""
1122 Multi-threaded class, meant for the WX* backends."""
1121
1123
1122 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1124 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1123 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1125 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1124 shell_class=MatplotlibMTShell)
1126 shell_class=MatplotlibMTShell)
1125 _load_pylab(self.IP.user_ns)
1127 _load_pylab(self.IP.user_ns)
1126
1128
1127 class IPShellMatplotlibQt(IPShellQt):
1129 class IPShellMatplotlibQt(IPShellQt):
1128 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1130 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1129
1131
1130 Multi-threaded class, meant for the Qt* backends."""
1132 Multi-threaded class, meant for the Qt* backends."""
1131
1133
1132 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1134 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1133 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1135 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1134 shell_class=MatplotlibMTShell)
1136 shell_class=MatplotlibMTShell)
1135 _load_pylab(self.IP.user_ns)
1137 _load_pylab(self.IP.user_ns)
1136
1138
1137 class IPShellMatplotlibQt4(IPShellQt4):
1139 class IPShellMatplotlibQt4(IPShellQt4):
1138 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1140 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1139
1141
1140 Multi-threaded class, meant for the Qt4* backends."""
1142 Multi-threaded class, meant for the Qt4* backends."""
1141
1143
1142 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1144 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1143 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1145 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1144 shell_class=MatplotlibMTShell)
1146 shell_class=MatplotlibMTShell)
1145 _load_pylab(self.IP.user_ns)
1147 _load_pylab(self.IP.user_ns)
1146
1148
1147 #-----------------------------------------------------------------------------
1149 #-----------------------------------------------------------------------------
1148 # Factory functions to actually start the proper thread-aware shell
1150 # Factory functions to actually start the proper thread-aware shell
1149
1151
1150 def _select_shell(argv):
1152 def _select_shell(argv):
1151 """Select a shell from the given argv vector.
1153 """Select a shell from the given argv vector.
1152
1154
1153 This function implements the threading selection policy, allowing runtime
1155 This function implements the threading selection policy, allowing runtime
1154 control of the threading mode, both for general users and for matplotlib.
1156 control of the threading mode, both for general users and for matplotlib.
1155
1157
1156 Return:
1158 Return:
1157 Shell class to be instantiated for runtime operation.
1159 Shell class to be instantiated for runtime operation.
1158 """
1160 """
1159
1161
1160 global USE_TK
1162 global USE_TK
1161
1163
1162 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1164 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1163 'wthread' : IPShellMatplotlibWX,
1165 'wthread' : IPShellMatplotlibWX,
1164 'qthread' : IPShellMatplotlibQt,
1166 'qthread' : IPShellMatplotlibQt,
1165 'q4thread' : IPShellMatplotlibQt4,
1167 'q4thread' : IPShellMatplotlibQt4,
1166 'tkthread' : IPShellMatplotlib, # Tk is built-in
1168 'tkthread' : IPShellMatplotlib, # Tk is built-in
1167 }
1169 }
1168
1170
1169 th_shell = {'gthread' : IPShellGTK,
1171 th_shell = {'gthread' : IPShellGTK,
1170 'wthread' : IPShellWX,
1172 'wthread' : IPShellWX,
1171 'qthread' : IPShellQt,
1173 'qthread' : IPShellQt,
1172 'q4thread' : IPShellQt4,
1174 'q4thread' : IPShellQt4,
1173 'tkthread' : IPShell, # Tk is built-in
1175 'tkthread' : IPShell, # Tk is built-in
1174 }
1176 }
1175
1177
1176 backends = {'gthread' : 'GTKAgg',
1178 backends = {'gthread' : 'GTKAgg',
1177 'wthread' : 'WXAgg',
1179 'wthread' : 'WXAgg',
1178 'qthread' : 'QtAgg',
1180 'qthread' : 'QtAgg',
1179 'q4thread' :'Qt4Agg',
1181 'q4thread' :'Qt4Agg',
1180 'tkthread' :'TkAgg',
1182 'tkthread' :'TkAgg',
1181 }
1183 }
1182
1184
1183 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1185 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1184 'tkthread'])
1186 'tkthread'])
1185 user_opts = set([s.replace('-','') for s in argv[:3]])
1187 user_opts = set([s.replace('-','') for s in argv[:3]])
1186 special_opts = user_opts & all_opts
1188 special_opts = user_opts & all_opts
1187
1189
1188 if 'tk' in special_opts:
1190 if 'tk' in special_opts:
1189 USE_TK = True
1191 USE_TK = True
1190 special_opts.remove('tk')
1192 special_opts.remove('tk')
1191
1193
1192 if 'pylab' in special_opts:
1194 if 'pylab' in special_opts:
1193
1195
1194 try:
1196 try:
1195 import matplotlib
1197 import matplotlib
1196 except ImportError:
1198 except ImportError:
1197 error('matplotlib could NOT be imported! Starting normal IPython.')
1199 error('matplotlib could NOT be imported! Starting normal IPython.')
1198 return IPShell
1200 return IPShell
1199
1201
1200 special_opts.remove('pylab')
1202 special_opts.remove('pylab')
1201 # If there's any option left, it means the user wants to force the
1203 # If there's any option left, it means the user wants to force the
1202 # threading backend, else it's auto-selected from the rc file
1204 # threading backend, else it's auto-selected from the rc file
1203 if special_opts:
1205 if special_opts:
1204 th_mode = special_opts.pop()
1206 th_mode = special_opts.pop()
1205 matplotlib.rcParams['backend'] = backends[th_mode]
1207 matplotlib.rcParams['backend'] = backends[th_mode]
1206 else:
1208 else:
1207 backend = matplotlib.rcParams['backend']
1209 backend = matplotlib.rcParams['backend']
1208 if backend.startswith('GTK'):
1210 if backend.startswith('GTK'):
1209 th_mode = 'gthread'
1211 th_mode = 'gthread'
1210 elif backend.startswith('WX'):
1212 elif backend.startswith('WX'):
1211 th_mode = 'wthread'
1213 th_mode = 'wthread'
1212 elif backend.startswith('Qt4'):
1214 elif backend.startswith('Qt4'):
1213 th_mode = 'q4thread'
1215 th_mode = 'q4thread'
1214 elif backend.startswith('Qt'):
1216 elif backend.startswith('Qt'):
1215 th_mode = 'qthread'
1217 th_mode = 'qthread'
1216 else:
1218 else:
1217 # Any other backend, use plain Tk
1219 # Any other backend, use plain Tk
1218 th_mode = 'tkthread'
1220 th_mode = 'tkthread'
1219
1221
1220 return mpl_shell[th_mode]
1222 return mpl_shell[th_mode]
1221 else:
1223 else:
1222 # No pylab requested, just plain threads
1224 # No pylab requested, just plain threads
1223 try:
1225 try:
1224 th_mode = special_opts.pop()
1226 th_mode = special_opts.pop()
1225 except KeyError:
1227 except KeyError:
1226 th_mode = 'tkthread'
1228 th_mode = 'tkthread'
1227 return th_shell[th_mode]
1229 return th_shell[th_mode]
1228
1230
1229
1231
1230 # This is the one which should be called by external code.
1232 # This is the one which should be called by external code.
1231 def start(user_ns = None):
1233 def start(user_ns = None):
1232 """Return a running shell instance, dealing with threading options.
1234 """Return a running shell instance, dealing with threading options.
1233
1235
1234 This is a factory function which will instantiate the proper IPython shell
1236 This is a factory function which will instantiate the proper IPython shell
1235 based on the user's threading choice. Such a selector is needed because
1237 based on the user's threading choice. Such a selector is needed because
1236 different GUI toolkits require different thread handling details."""
1238 different GUI toolkits require different thread handling details."""
1237
1239
1238 shell = _select_shell(sys.argv)
1240 shell = _select_shell(sys.argv)
1239 return shell(user_ns = user_ns)
1241 return shell(user_ns = user_ns)
1240
1242
1241 # Some aliases for backwards compatibility
1243 # Some aliases for backwards compatibility
1242 IPythonShell = IPShell
1244 IPythonShell = IPShell
1243 IPythonShellEmbed = IPShellEmbed
1245 IPythonShellEmbed = IPShellEmbed
1244 #************************ End of file <Shell.py> ***************************
1246 #************************ End of file <Shell.py> ***************************
General Comments 0
You need to be logged in to leave comments. Login now