##// END OF EJS Templates
Fix wx deprecation warning
fperez -
Show More

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

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