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