##// END OF EJS Templates
MTInteractiveShell.runsource: execute code directly if worker thread is not running yet (this is the case in config files)
Ville M. Vainio -
Show More
@@ -1,1214 +1,1216 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 # Locking control variable.
361 # Locking control variable.
362 self.thread_ready = threading.Condition(threading.RLock())
362 self.thread_ready = threading.Condition(threading.RLock())
363
363
364 # A queue to hold the code to be executed. A scalar variable is NOT
364 # A queue to hold the code to be executed. A scalar variable is NOT
365 # enough, because uses like macros cause reentrancy.
365 # enough, because uses like macros cause reentrancy.
366 self.code_queue = Queue.Queue()
366 self.code_queue = Queue.Queue()
367
367
368 # Stuff to do at closing time
368 # Stuff to do at closing time
369 self._kill = False
369 self._kill = False
370 on_kill = kw.get('on_kill')
370 on_kill = kw.get('on_kill')
371 if on_kill is None:
371 if on_kill is None:
372 on_kill = []
372 on_kill = []
373 # Check that all things to kill are callable:
373 # Check that all things to kill are callable:
374 for t in on_kill:
374 for t in on_kill:
375 if not callable(t):
375 if not callable(t):
376 raise TypeError,'on_kill must be a list of callables'
376 raise TypeError,'on_kill must be a list of callables'
377 self.on_kill = on_kill
377 self.on_kill = on_kill
378 # thread identity of the "worker thread" (that may execute code directly)
378 # thread identity of the "worker thread" (that may execute code directly)
379 self.worker_ident = None
379 self.worker_ident = None
380 def runsource(self, source, filename="<input>", symbol="single"):
380 def runsource(self, source, filename="<input>", symbol="single"):
381 """Compile and run some source in the interpreter.
381 """Compile and run some source in the interpreter.
382
382
383 Modified version of code.py's runsource(), to handle threading issues.
383 Modified version of code.py's runsource(), to handle threading issues.
384 See the original for full docstring details."""
384 See the original for full docstring details."""
385
385
386 global KBINT
386 global KBINT
387
387
388 # If Ctrl-C was typed, we reset the flag and return right away
388 # If Ctrl-C was typed, we reset the flag and return right away
389 if KBINT:
389 if KBINT:
390 KBINT = False
390 KBINT = False
391 return False
391 return False
392
392
393 try:
393 try:
394 code = self.compile(source, filename, symbol)
394 code = self.compile(source, filename, symbol)
395 except (OverflowError, SyntaxError, ValueError):
395 except (OverflowError, SyntaxError, ValueError):
396 # Case 1
396 # Case 1
397 self.showsyntaxerror(filename)
397 self.showsyntaxerror(filename)
398 return False
398 return False
399
399
400 if code is None:
400 if code is None:
401 # Case 2
401 # Case 2
402 return True
402 return True
403
403
404 # Case 3
404 # Case 3
405 # Store code in queue, so the execution thread can handle it.
405 # Store code in queue, so the execution thread can handle it.
406
406
407 # Note that with macros and other applications, we MAY re-enter this
407 # Note that with macros and other applications, we MAY re-enter this
408 # section, so we have to acquire the lock with non-blocking semantics,
408 # section, so we have to acquire the lock with non-blocking semantics,
409 # else we deadlock.
409 # else we deadlock.
410
410
411 # shortcut - if we are in worker thread, execute directly (to allow recursion)
411 # shortcut - if we are in worker thread, or the worker thread is not running,
412 # execute directly (to allow recursion and prevent deadlock if code is run early
413 # in IPython construction)
412
414
413 if self.worker_ident == thread.get_ident():
415 if self.worker_ident is None or self.worker_ident == thread.get_ident():
414 InteractiveShell.runcode(self,code)
416 InteractiveShell.runcode(self,code)
415 return
417 return
416
418
417 got_lock = self.thread_ready.acquire(blocking=False)
419 got_lock = self.thread_ready.acquire(blocking=False)
418 self.code_queue.put(code)
420 self.code_queue.put(code)
419 if got_lock:
421 if got_lock:
420 self.thread_ready.wait() # Wait until processed in timeout interval
422 self.thread_ready.wait() # Wait until processed in timeout interval
421 self.thread_ready.release()
423 self.thread_ready.release()
422
424
423 return False
425 return False
424
426
425 def runcode(self):
427 def runcode(self):
426 """Execute a code object.
428 """Execute a code object.
427
429
428 Multithreaded wrapper around IPython's runcode()."""
430 Multithreaded wrapper around IPython's runcode()."""
429
431
430 global CODE_RUN
432 global CODE_RUN
431 # lock thread-protected stuff
433 # lock thread-protected stuff
432 self.worker_ident = thread.get_ident()
434 self.worker_ident = thread.get_ident()
433 got_lock = self.thread_ready.acquire()
435 got_lock = self.thread_ready.acquire()
434
436
435 if self._kill:
437 if self._kill:
436 print >>Term.cout, 'Closing threads...',
438 print >>Term.cout, 'Closing threads...',
437 Term.cout.flush()
439 Term.cout.flush()
438 for tokill in self.on_kill:
440 for tokill in self.on_kill:
439 tokill()
441 tokill()
440 print >>Term.cout, 'Done.'
442 print >>Term.cout, 'Done.'
441
443
442 # Install sigint handler. We do it every time to ensure that if user
444 # Install sigint handler. We do it every time to ensure that if user
443 # code modifies it, we restore our own handling.
445 # code modifies it, we restore our own handling.
444 try:
446 try:
445 signal(SIGINT,sigint_handler)
447 signal(SIGINT,sigint_handler)
446 except SystemError:
448 except SystemError:
447 # This happens under Windows, which seems to have all sorts
449 # This happens under Windows, which seems to have all sorts
448 # of problems with signal handling. Oh well...
450 # of problems with signal handling. Oh well...
449 pass
451 pass
450
452
451 # Flush queue of pending code by calling the run methood of the parent
453 # Flush queue of pending code by calling the run methood of the parent
452 # class with all items which may be in the queue.
454 # class with all items which may be in the queue.
453 code_to_run = None
455 code_to_run = None
454 while 1:
456 while 1:
455 try:
457 try:
456 code_to_run = self.code_queue.get_nowait()
458 code_to_run = self.code_queue.get_nowait()
457 except Queue.Empty:
459 except Queue.Empty:
458 break
460 break
459 # Exceptions need to be raised differently depending on which
461 # Exceptions need to be raised differently depending on which
460 # thread is active. This convoluted try/except is only there to
462 # thread is active. This convoluted try/except is only there to
461 # protect against asynchronous exceptions, to ensure that a KBINT
463 # protect against asynchronous exceptions, to ensure that a KBINT
462 # at the wrong time doesn't deadlock everything. The global
464 # at the wrong time doesn't deadlock everything. The global
463 # CODE_TO_RUN is set to true/false as close as possible to the
465 # CODE_TO_RUN is set to true/false as close as possible to the
464 # runcode() call, so that the KBINT handler is correctly informed.
466 # runcode() call, so that the KBINT handler is correctly informed.
465 try:
467 try:
466 try:
468 try:
467 CODE_RUN = True
469 CODE_RUN = True
468 InteractiveShell.runcode(self,code_to_run)
470 InteractiveShell.runcode(self,code_to_run)
469 except KeyboardInterrupt:
471 except KeyboardInterrupt:
470 print "Keyboard interrupted in mainloop"
472 print "Keyboard interrupted in mainloop"
471 while not self.code_queue.empty():
473 while not self.code_queue.empty():
472 self.code_queue.get_nowait()
474 self.code_queue.get_nowait()
473 break
475 break
474 finally:
476 finally:
475 if got_lock:
477 if got_lock:
476 CODE_RUN = False
478 CODE_RUN = False
477
479
478 # We're done with thread-protected variables
480 # We're done with thread-protected variables
479 if code_to_run is not None:
481 if code_to_run is not None:
480 self.thread_ready.notify()
482 self.thread_ready.notify()
481 self.thread_ready.release()
483 self.thread_ready.release()
482
484
483 # We're done...
485 # We're done...
484 CODE_RUN = False
486 CODE_RUN = False
485 # This MUST return true for gtk threading to work
487 # This MUST return true for gtk threading to work
486 return True
488 return True
487
489
488 def kill(self):
490 def kill(self):
489 """Kill the thread, returning when it has been shut down."""
491 """Kill the thread, returning when it has been shut down."""
490 got_lock = self.thread_ready.acquire(False)
492 got_lock = self.thread_ready.acquire(False)
491 self._kill = True
493 self._kill = True
492 if got_lock:
494 if got_lock:
493 self.thread_ready.release()
495 self.thread_ready.release()
494
496
495 class MatplotlibShellBase:
497 class MatplotlibShellBase:
496 """Mixin class to provide the necessary modifications to regular IPython
498 """Mixin class to provide the necessary modifications to regular IPython
497 shell classes for matplotlib support.
499 shell classes for matplotlib support.
498
500
499 Given Python's MRO, this should be used as the FIRST class in the
501 Given Python's MRO, this should be used as the FIRST class in the
500 inheritance hierarchy, so that it overrides the relevant methods."""
502 inheritance hierarchy, so that it overrides the relevant methods."""
501
503
502 def _matplotlib_config(self,name,user_ns):
504 def _matplotlib_config(self,name,user_ns):
503 """Return items needed to setup the user's shell with matplotlib"""
505 """Return items needed to setup the user's shell with matplotlib"""
504
506
505 # Initialize matplotlib to interactive mode always
507 # Initialize matplotlib to interactive mode always
506 import matplotlib
508 import matplotlib
507 from matplotlib import backends
509 from matplotlib import backends
508 matplotlib.interactive(True)
510 matplotlib.interactive(True)
509
511
510 def use(arg):
512 def use(arg):
511 """IPython wrapper for matplotlib's backend switcher.
513 """IPython wrapper for matplotlib's backend switcher.
512
514
513 In interactive use, we can not allow switching to a different
515 In interactive use, we can not allow switching to a different
514 interactive backend, since thread conflicts will most likely crash
516 interactive backend, since thread conflicts will most likely crash
515 the python interpreter. This routine does a safety check first,
517 the python interpreter. This routine does a safety check first,
516 and refuses to perform a dangerous switch. It still allows
518 and refuses to perform a dangerous switch. It still allows
517 switching to non-interactive backends."""
519 switching to non-interactive backends."""
518
520
519 if arg in backends.interactive_bk and arg != self.mpl_backend:
521 if arg in backends.interactive_bk and arg != self.mpl_backend:
520 m=('invalid matplotlib backend switch.\n'
522 m=('invalid matplotlib backend switch.\n'
521 'This script attempted to switch to the interactive '
523 'This script attempted to switch to the interactive '
522 'backend: `%s`\n'
524 'backend: `%s`\n'
523 'Your current choice of interactive backend is: `%s`\n\n'
525 'Your current choice of interactive backend is: `%s`\n\n'
524 'Switching interactive matplotlib backends at runtime\n'
526 'Switching interactive matplotlib backends at runtime\n'
525 'would crash the python interpreter, '
527 'would crash the python interpreter, '
526 'and IPython has blocked it.\n\n'
528 'and IPython has blocked it.\n\n'
527 'You need to either change your choice of matplotlib backend\n'
529 'You need to either change your choice of matplotlib backend\n'
528 'by editing your .matplotlibrc file, or run this script as a \n'
530 'by editing your .matplotlibrc file, or run this script as a \n'
529 'standalone file from the command line, not using IPython.\n' %
531 'standalone file from the command line, not using IPython.\n' %
530 (arg,self.mpl_backend) )
532 (arg,self.mpl_backend) )
531 raise RuntimeError, m
533 raise RuntimeError, m
532 else:
534 else:
533 self.mpl_use(arg)
535 self.mpl_use(arg)
534 self.mpl_use._called = True
536 self.mpl_use._called = True
535
537
536 self.matplotlib = matplotlib
538 self.matplotlib = matplotlib
537 self.mpl_backend = matplotlib.rcParams['backend']
539 self.mpl_backend = matplotlib.rcParams['backend']
538
540
539 # we also need to block switching of interactive backends by use()
541 # we also need to block switching of interactive backends by use()
540 self.mpl_use = matplotlib.use
542 self.mpl_use = matplotlib.use
541 self.mpl_use._called = False
543 self.mpl_use._called = False
542 # overwrite the original matplotlib.use with our wrapper
544 # overwrite the original matplotlib.use with our wrapper
543 matplotlib.use = use
545 matplotlib.use = use
544
546
545 # This must be imported last in the matplotlib series, after
547 # This must be imported last in the matplotlib series, after
546 # backend/interactivity choices have been made
548 # backend/interactivity choices have been made
547 import matplotlib.pylab as pylab
549 import matplotlib.pylab as pylab
548 self.pylab = pylab
550 self.pylab = pylab
549
551
550 self.pylab.show._needmain = False
552 self.pylab.show._needmain = False
551 # We need to detect at runtime whether show() is called by the user.
553 # We need to detect at runtime whether show() is called by the user.
552 # For this, we wrap it into a decorator which adds a 'called' flag.
554 # For this, we wrap it into a decorator which adds a 'called' flag.
553 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
555 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
554
556
555 # Build a user namespace initialized with matplotlib/matlab features.
557 # Build a user namespace initialized with matplotlib/matlab features.
556 user_ns = IPython.ipapi.make_user_ns(user_ns)
558 user_ns = IPython.ipapi.make_user_ns(user_ns)
557
559
558 exec ("import matplotlib\n"
560 exec ("import matplotlib\n"
559 "import matplotlib.pylab as pylab\n") in user_ns
561 "import matplotlib.pylab as pylab\n") in user_ns
560
562
561 # Build matplotlib info banner
563 # Build matplotlib info banner
562 b="""
564 b="""
563 Welcome to pylab, a matplotlib-based Python environment.
565 Welcome to pylab, a matplotlib-based Python environment.
564 For more information, type 'help(pylab)'.
566 For more information, type 'help(pylab)'.
565 """
567 """
566 return user_ns,b
568 return user_ns,b
567
569
568 def mplot_exec(self,fname,*where,**kw):
570 def mplot_exec(self,fname,*where,**kw):
569 """Execute a matplotlib script.
571 """Execute a matplotlib script.
570
572
571 This is a call to execfile(), but wrapped in safeties to properly
573 This is a call to execfile(), but wrapped in safeties to properly
572 handle interactive rendering and backend switching."""
574 handle interactive rendering and backend switching."""
573
575
574 #print '*** Matplotlib runner ***' # dbg
576 #print '*** Matplotlib runner ***' # dbg
575 # turn off rendering until end of script
577 # turn off rendering until end of script
576 isInteractive = self.matplotlib.rcParams['interactive']
578 isInteractive = self.matplotlib.rcParams['interactive']
577 self.matplotlib.interactive(False)
579 self.matplotlib.interactive(False)
578 self.safe_execfile(fname,*where,**kw)
580 self.safe_execfile(fname,*where,**kw)
579 self.matplotlib.interactive(isInteractive)
581 self.matplotlib.interactive(isInteractive)
580 # make rendering call now, if the user tried to do it
582 # make rendering call now, if the user tried to do it
581 if self.pylab.draw_if_interactive.called:
583 if self.pylab.draw_if_interactive.called:
582 self.pylab.draw()
584 self.pylab.draw()
583 self.pylab.draw_if_interactive.called = False
585 self.pylab.draw_if_interactive.called = False
584
586
585 # if a backend switch was performed, reverse it now
587 # if a backend switch was performed, reverse it now
586 if self.mpl_use._called:
588 if self.mpl_use._called:
587 self.matplotlib.rcParams['backend'] = self.mpl_backend
589 self.matplotlib.rcParams['backend'] = self.mpl_backend
588
590
589 def magic_run(self,parameter_s=''):
591 def magic_run(self,parameter_s=''):
590 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
592 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
591
593
592 # Fix the docstring so users see the original as well
594 # Fix the docstring so users see the original as well
593 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
595 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
594 "\n *** Modified %run for Matplotlib,"
596 "\n *** Modified %run for Matplotlib,"
595 " with proper interactive handling ***")
597 " with proper interactive handling ***")
596
598
597 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
599 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
598 # and multithreaded. Note that these are meant for internal use, the IPShell*
600 # and multithreaded. Note that these are meant for internal use, the IPShell*
599 # classes below are the ones meant for public consumption.
601 # classes below are the ones meant for public consumption.
600
602
601 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
603 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
602 """Single-threaded shell with matplotlib support."""
604 """Single-threaded shell with matplotlib support."""
603
605
604 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
606 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
605 user_ns=None,user_global_ns=None,**kw):
607 user_ns=None,user_global_ns=None,**kw):
606 user_ns,b2 = self._matplotlib_config(name,user_ns)
608 user_ns,b2 = self._matplotlib_config(name,user_ns)
607 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
609 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
608 banner2=b2,**kw)
610 banner2=b2,**kw)
609
611
610 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
612 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
611 """Multi-threaded shell with matplotlib support."""
613 """Multi-threaded shell with matplotlib support."""
612
614
613 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
615 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
614 user_ns=None,user_global_ns=None, **kw):
616 user_ns=None,user_global_ns=None, **kw):
615 user_ns,b2 = self._matplotlib_config(name,user_ns)
617 user_ns,b2 = self._matplotlib_config(name,user_ns)
616 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
618 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
617 banner2=b2,**kw)
619 banner2=b2,**kw)
618
620
619 #-----------------------------------------------------------------------------
621 #-----------------------------------------------------------------------------
620 # Utility functions for the different GUI enabled IPShell* classes.
622 # Utility functions for the different GUI enabled IPShell* classes.
621
623
622 def get_tk():
624 def get_tk():
623 """Tries to import Tkinter and returns a withdrawn Tkinter root
625 """Tries to import Tkinter and returns a withdrawn Tkinter root
624 window. If Tkinter is already imported or not available, this
626 window. If Tkinter is already imported or not available, this
625 returns None. This function calls `hijack_tk` underneath.
627 returns None. This function calls `hijack_tk` underneath.
626 """
628 """
627 if not USE_TK or sys.modules.has_key('Tkinter'):
629 if not USE_TK or sys.modules.has_key('Tkinter'):
628 return None
630 return None
629 else:
631 else:
630 try:
632 try:
631 import Tkinter
633 import Tkinter
632 except ImportError:
634 except ImportError:
633 return None
635 return None
634 else:
636 else:
635 hijack_tk()
637 hijack_tk()
636 r = Tkinter.Tk()
638 r = Tkinter.Tk()
637 r.withdraw()
639 r.withdraw()
638 return r
640 return r
639
641
640 def hijack_tk():
642 def hijack_tk():
641 """Modifies Tkinter's mainloop with a dummy so when a module calls
643 """Modifies Tkinter's mainloop with a dummy so when a module calls
642 mainloop, it does not block.
644 mainloop, it does not block.
643
645
644 """
646 """
645 def misc_mainloop(self, n=0):
647 def misc_mainloop(self, n=0):
646 pass
648 pass
647 def tkinter_mainloop(n=0):
649 def tkinter_mainloop(n=0):
648 pass
650 pass
649
651
650 import Tkinter
652 import Tkinter
651 Tkinter.Misc.mainloop = misc_mainloop
653 Tkinter.Misc.mainloop = misc_mainloop
652 Tkinter.mainloop = tkinter_mainloop
654 Tkinter.mainloop = tkinter_mainloop
653
655
654 def update_tk(tk):
656 def update_tk(tk):
655 """Updates the Tkinter event loop. This is typically called from
657 """Updates the Tkinter event loop. This is typically called from
656 the respective WX or GTK mainloops.
658 the respective WX or GTK mainloops.
657 """
659 """
658 if tk:
660 if tk:
659 tk.update()
661 tk.update()
660
662
661 def hijack_wx():
663 def hijack_wx():
662 """Modifies wxPython's MainLoop with a dummy so user code does not
664 """Modifies wxPython's MainLoop with a dummy so user code does not
663 block IPython. The hijacked mainloop function is returned.
665 block IPython. The hijacked mainloop function is returned.
664 """
666 """
665 def dummy_mainloop(*args, **kw):
667 def dummy_mainloop(*args, **kw):
666 pass
668 pass
667
669
668 try:
670 try:
669 import wx
671 import wx
670 except ImportError:
672 except ImportError:
671 # For very old versions of WX
673 # For very old versions of WX
672 import wxPython as wx
674 import wxPython as wx
673
675
674 ver = wx.__version__
676 ver = wx.__version__
675 orig_mainloop = None
677 orig_mainloop = None
676 if ver[:3] >= '2.5':
678 if ver[:3] >= '2.5':
677 import wx
679 import wx
678 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
680 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
679 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
681 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
680 else: raise AttributeError('Could not find wx core module')
682 else: raise AttributeError('Could not find wx core module')
681 orig_mainloop = core.PyApp_MainLoop
683 orig_mainloop = core.PyApp_MainLoop
682 core.PyApp_MainLoop = dummy_mainloop
684 core.PyApp_MainLoop = dummy_mainloop
683 elif ver[:3] == '2.4':
685 elif ver[:3] == '2.4':
684 orig_mainloop = wx.wxc.wxPyApp_MainLoop
686 orig_mainloop = wx.wxc.wxPyApp_MainLoop
685 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
687 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
686 else:
688 else:
687 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
689 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
688 return orig_mainloop
690 return orig_mainloop
689
691
690 def hijack_gtk():
692 def hijack_gtk():
691 """Modifies pyGTK's mainloop with a dummy so user code does not
693 """Modifies pyGTK's mainloop with a dummy so user code does not
692 block IPython. This function returns the original `gtk.mainloop`
694 block IPython. This function returns the original `gtk.mainloop`
693 function that has been hijacked.
695 function that has been hijacked.
694 """
696 """
695 def dummy_mainloop(*args, **kw):
697 def dummy_mainloop(*args, **kw):
696 pass
698 pass
697 import gtk
699 import gtk
698 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
700 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
699 else: orig_mainloop = gtk.mainloop
701 else: orig_mainloop = gtk.mainloop
700 gtk.mainloop = dummy_mainloop
702 gtk.mainloop = dummy_mainloop
701 gtk.main = dummy_mainloop
703 gtk.main = dummy_mainloop
702 return orig_mainloop
704 return orig_mainloop
703
705
704 def hijack_qt():
706 def hijack_qt():
705 """Modifies PyQt's mainloop with a dummy so user code does not
707 """Modifies PyQt's mainloop with a dummy so user code does not
706 block IPython. This function returns the original
708 block IPython. This function returns the original
707 `qt.qApp.exec_loop` function that has been hijacked.
709 `qt.qApp.exec_loop` function that has been hijacked.
708 """
710 """
709 def dummy_mainloop(*args, **kw):
711 def dummy_mainloop(*args, **kw):
710 pass
712 pass
711 import qt
713 import qt
712 orig_mainloop = qt.qApp.exec_loop
714 orig_mainloop = qt.qApp.exec_loop
713 qt.qApp.exec_loop = dummy_mainloop
715 qt.qApp.exec_loop = dummy_mainloop
714 qt.QApplication.exec_loop = dummy_mainloop
716 qt.QApplication.exec_loop = dummy_mainloop
715 return orig_mainloop
717 return orig_mainloop
716
718
717 def hijack_qt4():
719 def hijack_qt4():
718 """Modifies PyQt4's mainloop with a dummy so user code does not
720 """Modifies PyQt4's mainloop with a dummy so user code does not
719 block IPython. This function returns the original
721 block IPython. This function returns the original
720 `QtGui.qApp.exec_` function that has been hijacked.
722 `QtGui.qApp.exec_` function that has been hijacked.
721 """
723 """
722 def dummy_mainloop(*args, **kw):
724 def dummy_mainloop(*args, **kw):
723 pass
725 pass
724 from PyQt4 import QtGui, QtCore
726 from PyQt4 import QtGui, QtCore
725 orig_mainloop = QtGui.qApp.exec_
727 orig_mainloop = QtGui.qApp.exec_
726 QtGui.qApp.exec_ = dummy_mainloop
728 QtGui.qApp.exec_ = dummy_mainloop
727 QtGui.QApplication.exec_ = dummy_mainloop
729 QtGui.QApplication.exec_ = dummy_mainloop
728 QtCore.QCoreApplication.exec_ = dummy_mainloop
730 QtCore.QCoreApplication.exec_ = dummy_mainloop
729 return orig_mainloop
731 return orig_mainloop
730
732
731 #-----------------------------------------------------------------------------
733 #-----------------------------------------------------------------------------
732 # The IPShell* classes below are the ones meant to be run by external code as
734 # The IPShell* classes below are the ones meant to be run by external code as
733 # IPython instances. Note that unless a specific threading strategy is
735 # IPython instances. Note that unless a specific threading strategy is
734 # desired, the factory function start() below should be used instead (it
736 # desired, the factory function start() below should be used instead (it
735 # selects the proper threaded class).
737 # selects the proper threaded class).
736
738
737 class IPThread(threading.Thread):
739 class IPThread(threading.Thread):
738 def run(self):
740 def run(self):
739 self.IP.mainloop(self._banner)
741 self.IP.mainloop(self._banner)
740 self.IP.kill()
742 self.IP.kill()
741
743
742 class IPShellGTK(IPThread):
744 class IPShellGTK(IPThread):
743 """Run a gtk mainloop() in a separate thread.
745 """Run a gtk mainloop() in a separate thread.
744
746
745 Python commands can be passed to the thread where they will be executed.
747 Python commands can be passed to the thread where they will be executed.
746 This is implemented by periodically checking for passed code using a
748 This is implemented by periodically checking for passed code using a
747 GTK timeout callback."""
749 GTK timeout callback."""
748
750
749 TIMEOUT = 100 # Millisecond interval between timeouts.
751 TIMEOUT = 100 # Millisecond interval between timeouts.
750
752
751 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
753 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
752 debug=1,shell_class=MTInteractiveShell):
754 debug=1,shell_class=MTInteractiveShell):
753
755
754 import gtk
756 import gtk
755
757
756 self.gtk = gtk
758 self.gtk = gtk
757 self.gtk_mainloop = hijack_gtk()
759 self.gtk_mainloop = hijack_gtk()
758
760
759 # Allows us to use both Tk and GTK.
761 # Allows us to use both Tk and GTK.
760 self.tk = get_tk()
762 self.tk = get_tk()
761
763
762 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
764 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
763 else: mainquit = self.gtk.mainquit
765 else: mainquit = self.gtk.mainquit
764
766
765 self.IP = make_IPython(argv,user_ns=user_ns,
767 self.IP = make_IPython(argv,user_ns=user_ns,
766 user_global_ns=user_global_ns,
768 user_global_ns=user_global_ns,
767 debug=debug,
769 debug=debug,
768 shell_class=shell_class,
770 shell_class=shell_class,
769 on_kill=[mainquit])
771 on_kill=[mainquit])
770
772
771 # HACK: slot for banner in self; it will be passed to the mainloop
773 # HACK: slot for banner in self; it will be passed to the mainloop
772 # method only and .run() needs it. The actual value will be set by
774 # method only and .run() needs it. The actual value will be set by
773 # .mainloop().
775 # .mainloop().
774 self._banner = None
776 self._banner = None
775
777
776 threading.Thread.__init__(self)
778 threading.Thread.__init__(self)
777
779
778 def mainloop(self,sys_exit=0,banner=None):
780 def mainloop(self,sys_exit=0,banner=None):
779
781
780 self._banner = banner
782 self._banner = banner
781
783
782 if self.gtk.pygtk_version >= (2,4,0):
784 if self.gtk.pygtk_version >= (2,4,0):
783 import gobject
785 import gobject
784 gobject.idle_add(self.on_timer)
786 gobject.idle_add(self.on_timer)
785 else:
787 else:
786 self.gtk.idle_add(self.on_timer)
788 self.gtk.idle_add(self.on_timer)
787
789
788 if sys.platform != 'win32':
790 if sys.platform != 'win32':
789 try:
791 try:
790 if self.gtk.gtk_version[0] >= 2:
792 if self.gtk.gtk_version[0] >= 2:
791 self.gtk.gdk.threads_init()
793 self.gtk.gdk.threads_init()
792 except AttributeError:
794 except AttributeError:
793 pass
795 pass
794 except RuntimeError:
796 except RuntimeError:
795 error('Your pyGTK likely has not been compiled with '
797 error('Your pyGTK likely has not been compiled with '
796 'threading support.\n'
798 'threading support.\n'
797 'The exception printout is below.\n'
799 'The exception printout is below.\n'
798 'You can either rebuild pyGTK with threads, or '
800 'You can either rebuild pyGTK with threads, or '
799 'try using \n'
801 'try using \n'
800 'matplotlib with a different backend (like Tk or WX).\n'
802 'matplotlib with a different backend (like Tk or WX).\n'
801 'Note that matplotlib will most likely not work in its '
803 'Note that matplotlib will most likely not work in its '
802 'current state!')
804 'current state!')
803 self.IP.InteractiveTB()
805 self.IP.InteractiveTB()
804
806
805 self.start()
807 self.start()
806 self.gtk.gdk.threads_enter()
808 self.gtk.gdk.threads_enter()
807 self.gtk_mainloop()
809 self.gtk_mainloop()
808 self.gtk.gdk.threads_leave()
810 self.gtk.gdk.threads_leave()
809 self.join()
811 self.join()
810
812
811 def on_timer(self):
813 def on_timer(self):
812 """Called when GTK is idle.
814 """Called when GTK is idle.
813
815
814 Must return True always, otherwise GTK stops calling it"""
816 Must return True always, otherwise GTK stops calling it"""
815
817
816 update_tk(self.tk)
818 update_tk(self.tk)
817 self.IP.runcode()
819 self.IP.runcode()
818 time.sleep(0.01)
820 time.sleep(0.01)
819 return True
821 return True
820
822
821
823
822 class IPShellWX(IPThread):
824 class IPShellWX(IPThread):
823 """Run a wx mainloop() in a separate thread.
825 """Run a wx mainloop() in a separate thread.
824
826
825 Python commands can be passed to the thread where they will be executed.
827 Python commands can be passed to the thread where they will be executed.
826 This is implemented by periodically checking for passed code using a
828 This is implemented by periodically checking for passed code using a
827 GTK timeout callback."""
829 GTK timeout callback."""
828
830
829 TIMEOUT = 100 # Millisecond interval between timeouts.
831 TIMEOUT = 100 # Millisecond interval between timeouts.
830
832
831 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
833 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
832 debug=1,shell_class=MTInteractiveShell):
834 debug=1,shell_class=MTInteractiveShell):
833
835
834 self.IP = make_IPython(argv,user_ns=user_ns,
836 self.IP = make_IPython(argv,user_ns=user_ns,
835 user_global_ns=user_global_ns,
837 user_global_ns=user_global_ns,
836 debug=debug,
838 debug=debug,
837 shell_class=shell_class,
839 shell_class=shell_class,
838 on_kill=[self.wxexit])
840 on_kill=[self.wxexit])
839
841
840 wantedwxversion=self.IP.rc.wxversion
842 wantedwxversion=self.IP.rc.wxversion
841 if wantedwxversion!="0":
843 if wantedwxversion!="0":
842 try:
844 try:
843 import wxversion
845 import wxversion
844 except ImportError:
846 except ImportError:
845 error('The wxversion module is needed for WX version selection')
847 error('The wxversion module is needed for WX version selection')
846 else:
848 else:
847 try:
849 try:
848 wxversion.select(wantedwxversion)
850 wxversion.select(wantedwxversion)
849 except:
851 except:
850 self.IP.InteractiveTB()
852 self.IP.InteractiveTB()
851 error('Requested wxPython version %s could not be loaded' %
853 error('Requested wxPython version %s could not be loaded' %
852 wantedwxversion)
854 wantedwxversion)
853
855
854 import wx
856 import wx
855
857
856 threading.Thread.__init__(self)
858 threading.Thread.__init__(self)
857 self.wx = wx
859 self.wx = wx
858 self.wx_mainloop = hijack_wx()
860 self.wx_mainloop = hijack_wx()
859
861
860 # Allows us to use both Tk and GTK.
862 # Allows us to use both Tk and GTK.
861 self.tk = get_tk()
863 self.tk = get_tk()
862
864
863 # HACK: slot for banner in self; it will be passed to the mainloop
865 # HACK: slot for banner in self; it will be passed to the mainloop
864 # method only and .run() needs it. The actual value will be set by
866 # method only and .run() needs it. The actual value will be set by
865 # .mainloop().
867 # .mainloop().
866 self._banner = None
868 self._banner = None
867
869
868 self.app = None
870 self.app = None
869
871
870 def wxexit(self, *args):
872 def wxexit(self, *args):
871 if self.app is not None:
873 if self.app is not None:
872 self.app.agent.timer.Stop()
874 self.app.agent.timer.Stop()
873 self.app.ExitMainLoop()
875 self.app.ExitMainLoop()
874
876
875 def mainloop(self,sys_exit=0,banner=None):
877 def mainloop(self,sys_exit=0,banner=None):
876
878
877 self._banner = banner
879 self._banner = banner
878
880
879 self.start()
881 self.start()
880
882
881 class TimerAgent(self.wx.MiniFrame):
883 class TimerAgent(self.wx.MiniFrame):
882 wx = self.wx
884 wx = self.wx
883 IP = self.IP
885 IP = self.IP
884 tk = self.tk
886 tk = self.tk
885 def __init__(self, parent, interval):
887 def __init__(self, parent, interval):
886 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
888 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
887 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
889 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
888 size=(100, 100),style=style)
890 size=(100, 100),style=style)
889 self.Show(False)
891 self.Show(False)
890 self.interval = interval
892 self.interval = interval
891 self.timerId = self.wx.NewId()
893 self.timerId = self.wx.NewId()
892
894
893 def StartWork(self):
895 def StartWork(self):
894 self.timer = self.wx.Timer(self, self.timerId)
896 self.timer = self.wx.Timer(self, self.timerId)
895 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
897 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
896 self.timer.Start(self.interval)
898 self.timer.Start(self.interval)
897
899
898 def OnTimer(self, event):
900 def OnTimer(self, event):
899 update_tk(self.tk)
901 update_tk(self.tk)
900 self.IP.runcode()
902 self.IP.runcode()
901
903
902 class App(self.wx.App):
904 class App(self.wx.App):
903 wx = self.wx
905 wx = self.wx
904 TIMEOUT = self.TIMEOUT
906 TIMEOUT = self.TIMEOUT
905 def OnInit(self):
907 def OnInit(self):
906 'Create the main window and insert the custom frame'
908 'Create the main window and insert the custom frame'
907 self.agent = TimerAgent(None, self.TIMEOUT)
909 self.agent = TimerAgent(None, self.TIMEOUT)
908 self.agent.Show(False)
910 self.agent.Show(False)
909 self.agent.StartWork()
911 self.agent.StartWork()
910 return True
912 return True
911
913
912 self.app = App(redirect=False)
914 self.app = App(redirect=False)
913 self.wx_mainloop(self.app)
915 self.wx_mainloop(self.app)
914 self.join()
916 self.join()
915
917
916
918
917 class IPShellQt(IPThread):
919 class IPShellQt(IPThread):
918 """Run a Qt event loop in a separate thread.
920 """Run a Qt event loop in a separate thread.
919
921
920 Python commands can be passed to the thread where they will be executed.
922 Python commands can be passed to the thread where they will be executed.
921 This is implemented by periodically checking for passed code using a
923 This is implemented by periodically checking for passed code using a
922 Qt timer / slot."""
924 Qt timer / slot."""
923
925
924 TIMEOUT = 100 # Millisecond interval between timeouts.
926 TIMEOUT = 100 # Millisecond interval between timeouts.
925
927
926 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
928 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
927 debug=0, shell_class=MTInteractiveShell):
929 debug=0, shell_class=MTInteractiveShell):
928
930
929 import qt
931 import qt
930
932
931 self.exec_loop = hijack_qt()
933 self.exec_loop = hijack_qt()
932
934
933 # Allows us to use both Tk and QT.
935 # Allows us to use both Tk and QT.
934 self.tk = get_tk()
936 self.tk = get_tk()
935
937
936 self.IP = make_IPython(argv,
938 self.IP = make_IPython(argv,
937 user_ns=user_ns,
939 user_ns=user_ns,
938 user_global_ns=user_global_ns,
940 user_global_ns=user_global_ns,
939 debug=debug,
941 debug=debug,
940 shell_class=shell_class,
942 shell_class=shell_class,
941 on_kill=[qt.qApp.exit])
943 on_kill=[qt.qApp.exit])
942
944
943 # HACK: slot for banner in self; it will be passed to the mainloop
945 # HACK: slot for banner in self; it will be passed to the mainloop
944 # method only and .run() needs it. The actual value will be set by
946 # method only and .run() needs it. The actual value will be set by
945 # .mainloop().
947 # .mainloop().
946 self._banner = None
948 self._banner = None
947
949
948 threading.Thread.__init__(self)
950 threading.Thread.__init__(self)
949
951
950 def mainloop(self, sys_exit=0, banner=None):
952 def mainloop(self, sys_exit=0, banner=None):
951
953
952 import qt
954 import qt
953
955
954 self._banner = banner
956 self._banner = banner
955
957
956 if qt.QApplication.startingUp():
958 if qt.QApplication.startingUp():
957 a = qt.QApplication(sys.argv)
959 a = qt.QApplication(sys.argv)
958
960
959 self.timer = qt.QTimer()
961 self.timer = qt.QTimer()
960 qt.QObject.connect(self.timer,
962 qt.QObject.connect(self.timer,
961 qt.SIGNAL('timeout()'),
963 qt.SIGNAL('timeout()'),
962 self.on_timer)
964 self.on_timer)
963
965
964 self.start()
966 self.start()
965 self.timer.start(self.TIMEOUT, True)
967 self.timer.start(self.TIMEOUT, True)
966 while True:
968 while True:
967 if self.IP._kill: break
969 if self.IP._kill: break
968 self.exec_loop()
970 self.exec_loop()
969 self.join()
971 self.join()
970
972
971 def on_timer(self):
973 def on_timer(self):
972 update_tk(self.tk)
974 update_tk(self.tk)
973 result = self.IP.runcode()
975 result = self.IP.runcode()
974 self.timer.start(self.TIMEOUT, True)
976 self.timer.start(self.TIMEOUT, True)
975 return result
977 return result
976
978
977
979
978 class IPShellQt4(IPThread):
980 class IPShellQt4(IPThread):
979 """Run a Qt event loop in a separate thread.
981 """Run a Qt event loop in a separate thread.
980
982
981 Python commands can be passed to the thread where they will be executed.
983 Python commands can be passed to the thread where they will be executed.
982 This is implemented by periodically checking for passed code using a
984 This is implemented by periodically checking for passed code using a
983 Qt timer / slot."""
985 Qt timer / slot."""
984
986
985 TIMEOUT = 100 # Millisecond interval between timeouts.
987 TIMEOUT = 100 # Millisecond interval between timeouts.
986
988
987 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
989 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
988 debug=0, shell_class=MTInteractiveShell):
990 debug=0, shell_class=MTInteractiveShell):
989
991
990 from PyQt4 import QtCore, QtGui
992 from PyQt4 import QtCore, QtGui
991
993
992 try:
994 try:
993 # present in PyQt4-4.2.1 or later
995 # present in PyQt4-4.2.1 or later
994 QtCore.pyqtRemoveInputHook()
996 QtCore.pyqtRemoveInputHook()
995 except AttributeError:
997 except AttributeError:
996 pass
998 pass
997
999
998 if QtCore.PYQT_VERSION_STR == '4.3':
1000 if QtCore.PYQT_VERSION_STR == '4.3':
999 warn('''PyQt4 version 4.3 detected.
1001 warn('''PyQt4 version 4.3 detected.
1000 If you experience repeated threading warnings, please update PyQt4.
1002 If you experience repeated threading warnings, please update PyQt4.
1001 ''')
1003 ''')
1002
1004
1003 self.exec_ = hijack_qt4()
1005 self.exec_ = hijack_qt4()
1004
1006
1005 # Allows us to use both Tk and QT.
1007 # Allows us to use both Tk and QT.
1006 self.tk = get_tk()
1008 self.tk = get_tk()
1007
1009
1008 self.IP = make_IPython(argv,
1010 self.IP = make_IPython(argv,
1009 user_ns=user_ns,
1011 user_ns=user_ns,
1010 user_global_ns=user_global_ns,
1012 user_global_ns=user_global_ns,
1011 debug=debug,
1013 debug=debug,
1012 shell_class=shell_class,
1014 shell_class=shell_class,
1013 on_kill=[QtGui.qApp.exit])
1015 on_kill=[QtGui.qApp.exit])
1014
1016
1015 # HACK: slot for banner in self; it will be passed to the mainloop
1017 # HACK: slot for banner in self; it will be passed to the mainloop
1016 # method only and .run() needs it. The actual value will be set by
1018 # method only and .run() needs it. The actual value will be set by
1017 # .mainloop().
1019 # .mainloop().
1018 self._banner = None
1020 self._banner = None
1019
1021
1020 threading.Thread.__init__(self)
1022 threading.Thread.__init__(self)
1021
1023
1022 def mainloop(self, sys_exit=0, banner=None):
1024 def mainloop(self, sys_exit=0, banner=None):
1023
1025
1024 from PyQt4 import QtCore, QtGui
1026 from PyQt4 import QtCore, QtGui
1025
1027
1026 self._banner = banner
1028 self._banner = banner
1027
1029
1028 if QtGui.QApplication.startingUp():
1030 if QtGui.QApplication.startingUp():
1029 a = QtGui.QApplication(sys.argv)
1031 a = QtGui.QApplication(sys.argv)
1030
1032
1031 self.timer = QtCore.QTimer()
1033 self.timer = QtCore.QTimer()
1032 QtCore.QObject.connect(self.timer,
1034 QtCore.QObject.connect(self.timer,
1033 QtCore.SIGNAL('timeout()'),
1035 QtCore.SIGNAL('timeout()'),
1034 self.on_timer)
1036 self.on_timer)
1035
1037
1036 self.start()
1038 self.start()
1037 self.timer.start(self.TIMEOUT)
1039 self.timer.start(self.TIMEOUT)
1038 while True:
1040 while True:
1039 if self.IP._kill: break
1041 if self.IP._kill: break
1040 self.exec_()
1042 self.exec_()
1041 self.join()
1043 self.join()
1042
1044
1043 def on_timer(self):
1045 def on_timer(self):
1044 update_tk(self.tk)
1046 update_tk(self.tk)
1045 result = self.IP.runcode()
1047 result = self.IP.runcode()
1046 self.timer.start(self.TIMEOUT)
1048 self.timer.start(self.TIMEOUT)
1047 return result
1049 return result
1048
1050
1049
1051
1050 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1052 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1051 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1053 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1052 def _load_pylab(user_ns):
1054 def _load_pylab(user_ns):
1053 """Allow users to disable pulling all of pylab into the top-level
1055 """Allow users to disable pulling all of pylab into the top-level
1054 namespace.
1056 namespace.
1055
1057
1056 This little utility must be called AFTER the actual ipython instance is
1058 This little utility must be called AFTER the actual ipython instance is
1057 running, since only then will the options file have been fully parsed."""
1059 running, since only then will the options file have been fully parsed."""
1058
1060
1059 ip = IPython.ipapi.get()
1061 ip = IPython.ipapi.get()
1060 if ip.options.pylab_import_all:
1062 if ip.options.pylab_import_all:
1061 ip.ex("from matplotlib.pylab import *")
1063 ip.ex("from matplotlib.pylab import *")
1062 ip.IP.user_config_ns.update(ip.user_ns)
1064 ip.IP.user_config_ns.update(ip.user_ns)
1063
1065
1064
1066
1065 class IPShellMatplotlib(IPShell):
1067 class IPShellMatplotlib(IPShell):
1066 """Subclass IPShell with MatplotlibShell as the internal shell.
1068 """Subclass IPShell with MatplotlibShell as the internal shell.
1067
1069
1068 Single-threaded class, meant for the Tk* and FLTK* backends.
1070 Single-threaded class, meant for the Tk* and FLTK* backends.
1069
1071
1070 Having this on a separate class simplifies the external driver code."""
1072 Having this on a separate class simplifies the external driver code."""
1071
1073
1072 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1074 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1073 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1075 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1074 shell_class=MatplotlibShell)
1076 shell_class=MatplotlibShell)
1075 _load_pylab(self.IP.user_ns)
1077 _load_pylab(self.IP.user_ns)
1076
1078
1077 class IPShellMatplotlibGTK(IPShellGTK):
1079 class IPShellMatplotlibGTK(IPShellGTK):
1078 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1080 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1079
1081
1080 Multi-threaded class, meant for the GTK* backends."""
1082 Multi-threaded class, meant for the GTK* backends."""
1081
1083
1082 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1084 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1083 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1085 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1084 shell_class=MatplotlibMTShell)
1086 shell_class=MatplotlibMTShell)
1085 _load_pylab(self.IP.user_ns)
1087 _load_pylab(self.IP.user_ns)
1086
1088
1087 class IPShellMatplotlibWX(IPShellWX):
1089 class IPShellMatplotlibWX(IPShellWX):
1088 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1090 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1089
1091
1090 Multi-threaded class, meant for the WX* backends."""
1092 Multi-threaded class, meant for the WX* backends."""
1091
1093
1092 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1094 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1093 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1095 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1094 shell_class=MatplotlibMTShell)
1096 shell_class=MatplotlibMTShell)
1095 _load_pylab(self.IP.user_ns)
1097 _load_pylab(self.IP.user_ns)
1096
1098
1097 class IPShellMatplotlibQt(IPShellQt):
1099 class IPShellMatplotlibQt(IPShellQt):
1098 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1100 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1099
1101
1100 Multi-threaded class, meant for the Qt* backends."""
1102 Multi-threaded class, meant for the Qt* backends."""
1101
1103
1102 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1104 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1103 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1105 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1104 shell_class=MatplotlibMTShell)
1106 shell_class=MatplotlibMTShell)
1105 _load_pylab(self.IP.user_ns)
1107 _load_pylab(self.IP.user_ns)
1106
1108
1107 class IPShellMatplotlibQt4(IPShellQt4):
1109 class IPShellMatplotlibQt4(IPShellQt4):
1108 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1110 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1109
1111
1110 Multi-threaded class, meant for the Qt4* backends."""
1112 Multi-threaded class, meant for the Qt4* backends."""
1111
1113
1112 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1114 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1113 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1115 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1114 shell_class=MatplotlibMTShell)
1116 shell_class=MatplotlibMTShell)
1115 _load_pylab(self.IP.user_ns)
1117 _load_pylab(self.IP.user_ns)
1116
1118
1117 #-----------------------------------------------------------------------------
1119 #-----------------------------------------------------------------------------
1118 # Factory functions to actually start the proper thread-aware shell
1120 # Factory functions to actually start the proper thread-aware shell
1119
1121
1120 def _select_shell(argv):
1122 def _select_shell(argv):
1121 """Select a shell from the given argv vector.
1123 """Select a shell from the given argv vector.
1122
1124
1123 This function implements the threading selection policy, allowing runtime
1125 This function implements the threading selection policy, allowing runtime
1124 control of the threading mode, both for general users and for matplotlib.
1126 control of the threading mode, both for general users and for matplotlib.
1125
1127
1126 Return:
1128 Return:
1127 Shell class to be instantiated for runtime operation.
1129 Shell class to be instantiated for runtime operation.
1128 """
1130 """
1129
1131
1130 global USE_TK
1132 global USE_TK
1131
1133
1132 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1134 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1133 'wthread' : IPShellMatplotlibWX,
1135 'wthread' : IPShellMatplotlibWX,
1134 'qthread' : IPShellMatplotlibQt,
1136 'qthread' : IPShellMatplotlibQt,
1135 'q4thread' : IPShellMatplotlibQt4,
1137 'q4thread' : IPShellMatplotlibQt4,
1136 'tkthread' : IPShellMatplotlib, # Tk is built-in
1138 'tkthread' : IPShellMatplotlib, # Tk is built-in
1137 }
1139 }
1138
1140
1139 th_shell = {'gthread' : IPShellGTK,
1141 th_shell = {'gthread' : IPShellGTK,
1140 'wthread' : IPShellWX,
1142 'wthread' : IPShellWX,
1141 'qthread' : IPShellQt,
1143 'qthread' : IPShellQt,
1142 'q4thread' : IPShellQt4,
1144 'q4thread' : IPShellQt4,
1143 'tkthread' : IPShell, # Tk is built-in
1145 'tkthread' : IPShell, # Tk is built-in
1144 }
1146 }
1145
1147
1146 backends = {'gthread' : 'GTKAgg',
1148 backends = {'gthread' : 'GTKAgg',
1147 'wthread' : 'WXAgg',
1149 'wthread' : 'WXAgg',
1148 'qthread' : 'QtAgg',
1150 'qthread' : 'QtAgg',
1149 'q4thread' :'Qt4Agg',
1151 'q4thread' :'Qt4Agg',
1150 'tkthread' :'TkAgg',
1152 'tkthread' :'TkAgg',
1151 }
1153 }
1152
1154
1153 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1155 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1154 'tkthread'])
1156 'tkthread'])
1155 user_opts = set([s.replace('-','') for s in argv[:3]])
1157 user_opts = set([s.replace('-','') for s in argv[:3]])
1156 special_opts = user_opts & all_opts
1158 special_opts = user_opts & all_opts
1157
1159
1158 if 'tk' in special_opts:
1160 if 'tk' in special_opts:
1159 USE_TK = True
1161 USE_TK = True
1160 special_opts.remove('tk')
1162 special_opts.remove('tk')
1161
1163
1162 if 'pylab' in special_opts:
1164 if 'pylab' in special_opts:
1163
1165
1164 try:
1166 try:
1165 import matplotlib
1167 import matplotlib
1166 except ImportError:
1168 except ImportError:
1167 error('matplotlib could NOT be imported! Starting normal IPython.')
1169 error('matplotlib could NOT be imported! Starting normal IPython.')
1168 return IPShell
1170 return IPShell
1169
1171
1170 special_opts.remove('pylab')
1172 special_opts.remove('pylab')
1171 # If there's any option left, it means the user wants to force the
1173 # If there's any option left, it means the user wants to force the
1172 # threading backend, else it's auto-selected from the rc file
1174 # threading backend, else it's auto-selected from the rc file
1173 if special_opts:
1175 if special_opts:
1174 th_mode = special_opts.pop()
1176 th_mode = special_opts.pop()
1175 matplotlib.rcParams['backend'] = backends[th_mode]
1177 matplotlib.rcParams['backend'] = backends[th_mode]
1176 else:
1178 else:
1177 backend = matplotlib.rcParams['backend']
1179 backend = matplotlib.rcParams['backend']
1178 if backend.startswith('GTK'):
1180 if backend.startswith('GTK'):
1179 th_mode = 'gthread'
1181 th_mode = 'gthread'
1180 elif backend.startswith('WX'):
1182 elif backend.startswith('WX'):
1181 th_mode = 'wthread'
1183 th_mode = 'wthread'
1182 elif backend.startswith('Qt4'):
1184 elif backend.startswith('Qt4'):
1183 th_mode = 'q4thread'
1185 th_mode = 'q4thread'
1184 elif backend.startswith('Qt'):
1186 elif backend.startswith('Qt'):
1185 th_mode = 'qthread'
1187 th_mode = 'qthread'
1186 else:
1188 else:
1187 # Any other backend, use plain Tk
1189 # Any other backend, use plain Tk
1188 th_mode = 'tkthread'
1190 th_mode = 'tkthread'
1189
1191
1190 return mpl_shell[th_mode]
1192 return mpl_shell[th_mode]
1191 else:
1193 else:
1192 # No pylab requested, just plain threads
1194 # No pylab requested, just plain threads
1193 try:
1195 try:
1194 th_mode = special_opts.pop()
1196 th_mode = special_opts.pop()
1195 except KeyError:
1197 except KeyError:
1196 th_mode = 'tkthread'
1198 th_mode = 'tkthread'
1197 return th_shell[th_mode]
1199 return th_shell[th_mode]
1198
1200
1199
1201
1200 # This is the one which should be called by external code.
1202 # This is the one which should be called by external code.
1201 def start(user_ns = None):
1203 def start(user_ns = None):
1202 """Return a running shell instance, dealing with threading options.
1204 """Return a running shell instance, dealing with threading options.
1203
1205
1204 This is a factory function which will instantiate the proper IPython shell
1206 This is a factory function which will instantiate the proper IPython shell
1205 based on the user's threading choice. Such a selector is needed because
1207 based on the user's threading choice. Such a selector is needed because
1206 different GUI toolkits require different thread handling details."""
1208 different GUI toolkits require different thread handling details."""
1207
1209
1208 shell = _select_shell(sys.argv)
1210 shell = _select_shell(sys.argv)
1209 return shell(user_ns = user_ns)
1211 return shell(user_ns = user_ns)
1210
1212
1211 # Some aliases for backwards compatibility
1213 # Some aliases for backwards compatibility
1212 IPythonShell = IPShell
1214 IPythonShell = IPShell
1213 IPythonShellEmbed = IPShellEmbed
1215 IPythonShellEmbed = IPShellEmbed
1214 #************************ End of file <Shell.py> ***************************
1216 #************************ End of file <Shell.py> ***************************
General Comments 0
You need to be logged in to leave comments. Login now