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