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