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