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