##// END OF EJS Templates
- I possibly cross-thread KeyboardInterrupt support for the multithreaded...
fperez -
Show More

The requested changes are too big and content was truncated. Show full diff

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