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