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