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