##// END OF EJS Templates
Small fix to pylab imports
fperez -
Show More
@@ -1,1061 +1,1061 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 2156 2007-03-19 02:32:19Z fperez $"""
7 $Id: Shell.py 2164 2007-03-20 00:15:03Z 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") in user_ns
449 "import matplotlib.pylab as pylab\n") in user_ns
450
450
451 # Build matplotlib info banner
451 # Build matplotlib info banner
452 b="""
452 b="""
453 Welcome to pylab, a matplotlib-based Python environment.
453 Welcome to pylab, a matplotlib-based Python environment.
454 For more information, type 'help(pylab)'.
454 For more information, type 'help(pylab)'.
455 """
455 """
456 return user_ns,b
456 return user_ns,b
457
457
458 def mplot_exec(self,fname,*where,**kw):
458 def mplot_exec(self,fname,*where,**kw):
459 """Execute a matplotlib script.
459 """Execute a matplotlib script.
460
460
461 This is a call to execfile(), but wrapped in safeties to properly
461 This is a call to execfile(), but wrapped in safeties to properly
462 handle interactive rendering and backend switching."""
462 handle interactive rendering and backend switching."""
463
463
464 #print '*** Matplotlib runner ***' # dbg
464 #print '*** Matplotlib runner ***' # dbg
465 # turn off rendering until end of script
465 # turn off rendering until end of script
466 isInteractive = self.matplotlib.rcParams['interactive']
466 isInteractive = self.matplotlib.rcParams['interactive']
467 self.matplotlib.interactive(False)
467 self.matplotlib.interactive(False)
468 self.safe_execfile(fname,*where,**kw)
468 self.safe_execfile(fname,*where,**kw)
469 self.matplotlib.interactive(isInteractive)
469 self.matplotlib.interactive(isInteractive)
470 # make rendering call now, if the user tried to do it
470 # make rendering call now, if the user tried to do it
471 if self.pylab.draw_if_interactive.called:
471 if self.pylab.draw_if_interactive.called:
472 self.pylab.draw()
472 self.pylab.draw()
473 self.pylab.draw_if_interactive.called = False
473 self.pylab.draw_if_interactive.called = False
474
474
475 # if a backend switch was performed, reverse it now
475 # if a backend switch was performed, reverse it now
476 if self.mpl_use._called:
476 if self.mpl_use._called:
477 self.matplotlib.rcParams['backend'] = self.mpl_backend
477 self.matplotlib.rcParams['backend'] = self.mpl_backend
478
478
479 def magic_run(self,parameter_s=''):
479 def magic_run(self,parameter_s=''):
480 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
480 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
481
481
482 # Fix the docstring so users see the original as well
482 # Fix the docstring so users see the original as well
483 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
483 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
484 "\n *** Modified %run for Matplotlib,"
484 "\n *** Modified %run for Matplotlib,"
485 " with proper interactive handling ***")
485 " with proper interactive handling ***")
486
486
487 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
487 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
488 # and multithreaded. Note that these are meant for internal use, the IPShell*
488 # and multithreaded. Note that these are meant for internal use, the IPShell*
489 # classes below are the ones meant for public consumption.
489 # classes below are the ones meant for public consumption.
490
490
491 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
491 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
492 """Single-threaded shell with matplotlib support."""
492 """Single-threaded shell with matplotlib support."""
493
493
494 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
494 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
495 user_ns=None,user_global_ns=None,**kw):
495 user_ns=None,user_global_ns=None,**kw):
496 user_ns,b2 = self._matplotlib_config(name,user_ns)
496 user_ns,b2 = self._matplotlib_config(name,user_ns)
497 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
497 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
498 banner2=b2,**kw)
498 banner2=b2,**kw)
499
499
500 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
500 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
501 """Multi-threaded shell with matplotlib support."""
501 """Multi-threaded shell with matplotlib support."""
502
502
503 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
503 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
504 user_ns=None,user_global_ns=None, **kw):
504 user_ns=None,user_global_ns=None, **kw):
505 user_ns,b2 = self._matplotlib_config(name,user_ns)
505 user_ns,b2 = self._matplotlib_config(name,user_ns)
506 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
506 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
507 banner2=b2,**kw)
507 banner2=b2,**kw)
508
508
509 #-----------------------------------------------------------------------------
509 #-----------------------------------------------------------------------------
510 # Utility functions for the different GUI enabled IPShell* classes.
510 # Utility functions for the different GUI enabled IPShell* classes.
511
511
512 def get_tk():
512 def get_tk():
513 """Tries to import Tkinter and returns a withdrawn Tkinter root
513 """Tries to import Tkinter and returns a withdrawn Tkinter root
514 window. If Tkinter is already imported or not available, this
514 window. If Tkinter is already imported or not available, this
515 returns None. This function calls `hijack_tk` underneath.
515 returns None. This function calls `hijack_tk` underneath.
516 """
516 """
517 if not USE_TK or sys.modules.has_key('Tkinter'):
517 if not USE_TK or sys.modules.has_key('Tkinter'):
518 return None
518 return None
519 else:
519 else:
520 try:
520 try:
521 import Tkinter
521 import Tkinter
522 except ImportError:
522 except ImportError:
523 return None
523 return None
524 else:
524 else:
525 hijack_tk()
525 hijack_tk()
526 r = Tkinter.Tk()
526 r = Tkinter.Tk()
527 r.withdraw()
527 r.withdraw()
528 return r
528 return r
529
529
530 def hijack_tk():
530 def hijack_tk():
531 """Modifies Tkinter's mainloop with a dummy so when a module calls
531 """Modifies Tkinter's mainloop with a dummy so when a module calls
532 mainloop, it does not block.
532 mainloop, it does not block.
533
533
534 """
534 """
535 def misc_mainloop(self, n=0):
535 def misc_mainloop(self, n=0):
536 pass
536 pass
537 def tkinter_mainloop(n=0):
537 def tkinter_mainloop(n=0):
538 pass
538 pass
539
539
540 import Tkinter
540 import Tkinter
541 Tkinter.Misc.mainloop = misc_mainloop
541 Tkinter.Misc.mainloop = misc_mainloop
542 Tkinter.mainloop = tkinter_mainloop
542 Tkinter.mainloop = tkinter_mainloop
543
543
544 def update_tk(tk):
544 def update_tk(tk):
545 """Updates the Tkinter event loop. This is typically called from
545 """Updates the Tkinter event loop. This is typically called from
546 the respective WX or GTK mainloops.
546 the respective WX or GTK mainloops.
547 """
547 """
548 if tk:
548 if tk:
549 tk.update()
549 tk.update()
550
550
551 def hijack_wx():
551 def hijack_wx():
552 """Modifies wxPython's MainLoop with a dummy so user code does not
552 """Modifies wxPython's MainLoop with a dummy so user code does not
553 block IPython. The hijacked mainloop function is returned.
553 block IPython. The hijacked mainloop function is returned.
554 """
554 """
555 def dummy_mainloop(*args, **kw):
555 def dummy_mainloop(*args, **kw):
556 pass
556 pass
557
557
558 try:
558 try:
559 import wx
559 import wx
560 except ImportError:
560 except ImportError:
561 # For very old versions of WX
561 # For very old versions of WX
562 import wxPython as wx
562 import wxPython as wx
563
563
564 ver = wx.__version__
564 ver = wx.__version__
565 orig_mainloop = None
565 orig_mainloop = None
566 if ver[:3] >= '2.5':
566 if ver[:3] >= '2.5':
567 import wx
567 import wx
568 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
568 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
569 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
569 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
570 else: raise AttributeError('Could not find wx core module')
570 else: raise AttributeError('Could not find wx core module')
571 orig_mainloop = core.PyApp_MainLoop
571 orig_mainloop = core.PyApp_MainLoop
572 core.PyApp_MainLoop = dummy_mainloop
572 core.PyApp_MainLoop = dummy_mainloop
573 elif ver[:3] == '2.4':
573 elif ver[:3] == '2.4':
574 orig_mainloop = wx.wxc.wxPyApp_MainLoop
574 orig_mainloop = wx.wxc.wxPyApp_MainLoop
575 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
575 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
576 else:
576 else:
577 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
577 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
578 return orig_mainloop
578 return orig_mainloop
579
579
580 def hijack_gtk():
580 def hijack_gtk():
581 """Modifies pyGTK's mainloop with a dummy so user code does not
581 """Modifies pyGTK's mainloop with a dummy so user code does not
582 block IPython. This function returns the original `gtk.mainloop`
582 block IPython. This function returns the original `gtk.mainloop`
583 function that has been hijacked.
583 function that has been hijacked.
584 """
584 """
585 def dummy_mainloop(*args, **kw):
585 def dummy_mainloop(*args, **kw):
586 pass
586 pass
587 import gtk
587 import gtk
588 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
588 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
589 else: orig_mainloop = gtk.mainloop
589 else: orig_mainloop = gtk.mainloop
590 gtk.mainloop = dummy_mainloop
590 gtk.mainloop = dummy_mainloop
591 gtk.main = dummy_mainloop
591 gtk.main = dummy_mainloop
592 return orig_mainloop
592 return orig_mainloop
593
593
594 #-----------------------------------------------------------------------------
594 #-----------------------------------------------------------------------------
595 # The IPShell* classes below are the ones meant to be run by external code as
595 # The IPShell* classes below are the ones meant to be run by external code as
596 # IPython instances. Note that unless a specific threading strategy is
596 # IPython instances. Note that unless a specific threading strategy is
597 # desired, the factory function start() below should be used instead (it
597 # desired, the factory function start() below should be used instead (it
598 # selects the proper threaded class).
598 # selects the proper threaded class).
599
599
600 class IPShellGTK(threading.Thread):
600 class IPShellGTK(threading.Thread):
601 """Run a gtk mainloop() in a separate thread.
601 """Run a gtk mainloop() in a separate thread.
602
602
603 Python commands can be passed to the thread where they will be executed.
603 Python commands can be passed to the thread where they will be executed.
604 This is implemented by periodically checking for passed code using a
604 This is implemented by periodically checking for passed code using a
605 GTK timeout callback."""
605 GTK timeout callback."""
606
606
607 TIMEOUT = 100 # Millisecond interval between timeouts.
607 TIMEOUT = 100 # Millisecond interval between timeouts.
608
608
609 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
609 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
610 debug=1,shell_class=MTInteractiveShell):
610 debug=1,shell_class=MTInteractiveShell):
611
611
612 import gtk
612 import gtk
613
613
614 self.gtk = gtk
614 self.gtk = gtk
615 self.gtk_mainloop = hijack_gtk()
615 self.gtk_mainloop = hijack_gtk()
616
616
617 # Allows us to use both Tk and GTK.
617 # Allows us to use both Tk and GTK.
618 self.tk = get_tk()
618 self.tk = get_tk()
619
619
620 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
620 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
621 else: mainquit = self.gtk.mainquit
621 else: mainquit = self.gtk.mainquit
622
622
623 self.IP = make_IPython(argv,user_ns=user_ns,
623 self.IP = make_IPython(argv,user_ns=user_ns,
624 user_global_ns=user_global_ns,
624 user_global_ns=user_global_ns,
625 debug=debug,
625 debug=debug,
626 shell_class=shell_class,
626 shell_class=shell_class,
627 on_kill=[mainquit])
627 on_kill=[mainquit])
628
628
629 # HACK: slot for banner in self; it will be passed to the mainloop
629 # HACK: slot for banner in self; it will be passed to the mainloop
630 # method only and .run() needs it. The actual value will be set by
630 # method only and .run() needs it. The actual value will be set by
631 # .mainloop().
631 # .mainloop().
632 self._banner = None
632 self._banner = None
633
633
634 threading.Thread.__init__(self)
634 threading.Thread.__init__(self)
635
635
636 def run(self):
636 def run(self):
637 self.IP.mainloop(self._banner)
637 self.IP.mainloop(self._banner)
638 self.IP.kill()
638 self.IP.kill()
639
639
640 def mainloop(self,sys_exit=0,banner=None):
640 def mainloop(self,sys_exit=0,banner=None):
641
641
642 self._banner = banner
642 self._banner = banner
643
643
644 if self.gtk.pygtk_version >= (2,4,0):
644 if self.gtk.pygtk_version >= (2,4,0):
645 import gobject
645 import gobject
646 gobject.idle_add(self.on_timer)
646 gobject.idle_add(self.on_timer)
647 else:
647 else:
648 self.gtk.idle_add(self.on_timer)
648 self.gtk.idle_add(self.on_timer)
649
649
650 if sys.platform != 'win32':
650 if sys.platform != 'win32':
651 try:
651 try:
652 if self.gtk.gtk_version[0] >= 2:
652 if self.gtk.gtk_version[0] >= 2:
653 self.gtk.gdk.threads_init()
653 self.gtk.gdk.threads_init()
654 except AttributeError:
654 except AttributeError:
655 pass
655 pass
656 except RuntimeError:
656 except RuntimeError:
657 error('Your pyGTK likely has not been compiled with '
657 error('Your pyGTK likely has not been compiled with '
658 'threading support.\n'
658 'threading support.\n'
659 'The exception printout is below.\n'
659 'The exception printout is below.\n'
660 'You can either rebuild pyGTK with threads, or '
660 'You can either rebuild pyGTK with threads, or '
661 'try using \n'
661 'try using \n'
662 'matplotlib with a different backend (like Tk or WX).\n'
662 'matplotlib with a different backend (like Tk or WX).\n'
663 'Note that matplotlib will most likely not work in its '
663 'Note that matplotlib will most likely not work in its '
664 'current state!')
664 'current state!')
665 self.IP.InteractiveTB()
665 self.IP.InteractiveTB()
666
666
667 self.start()
667 self.start()
668 self.gtk.gdk.threads_enter()
668 self.gtk.gdk.threads_enter()
669 self.gtk_mainloop()
669 self.gtk_mainloop()
670 self.gtk.gdk.threads_leave()
670 self.gtk.gdk.threads_leave()
671 self.join()
671 self.join()
672
672
673 def on_timer(self):
673 def on_timer(self):
674 """Called when GTK is idle.
674 """Called when GTK is idle.
675
675
676 Must return True always, otherwise GTK stops calling it"""
676 Must return True always, otherwise GTK stops calling it"""
677
677
678 update_tk(self.tk)
678 update_tk(self.tk)
679 self.IP.runcode()
679 self.IP.runcode()
680 time.sleep(0.01)
680 time.sleep(0.01)
681 return True
681 return True
682
682
683 class IPShellWX(threading.Thread):
683 class IPShellWX(threading.Thread):
684 """Run a wx mainloop() in a separate thread.
684 """Run a wx mainloop() in a separate thread.
685
685
686 Python commands can be passed to the thread where they will be executed.
686 Python commands can be passed to the thread where they will be executed.
687 This is implemented by periodically checking for passed code using a
687 This is implemented by periodically checking for passed code using a
688 GTK timeout callback."""
688 GTK timeout callback."""
689
689
690 TIMEOUT = 100 # Millisecond interval between timeouts.
690 TIMEOUT = 100 # Millisecond interval between timeouts.
691
691
692 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
692 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
693 debug=1,shell_class=MTInteractiveShell):
693 debug=1,shell_class=MTInteractiveShell):
694
694
695 self.IP = make_IPython(argv,user_ns=user_ns,
695 self.IP = make_IPython(argv,user_ns=user_ns,
696 user_global_ns=user_global_ns,
696 user_global_ns=user_global_ns,
697 debug=debug,
697 debug=debug,
698 shell_class=shell_class,
698 shell_class=shell_class,
699 on_kill=[self.wxexit])
699 on_kill=[self.wxexit])
700
700
701 wantedwxversion=self.IP.rc.wxversion
701 wantedwxversion=self.IP.rc.wxversion
702 if wantedwxversion!="0":
702 if wantedwxversion!="0":
703 try:
703 try:
704 import wxversion
704 import wxversion
705 except ImportError:
705 except ImportError:
706 error('The wxversion module is needed for WX version selection')
706 error('The wxversion module is needed for WX version selection')
707 else:
707 else:
708 try:
708 try:
709 wxversion.select(wantedwxversion)
709 wxversion.select(wantedwxversion)
710 except:
710 except:
711 self.IP.InteractiveTB()
711 self.IP.InteractiveTB()
712 error('Requested wxPython version %s could not be loaded' %
712 error('Requested wxPython version %s could not be loaded' %
713 wantedwxversion)
713 wantedwxversion)
714
714
715 import wx
715 import wx
716
716
717 threading.Thread.__init__(self)
717 threading.Thread.__init__(self)
718 self.wx = wx
718 self.wx = wx
719 self.wx_mainloop = hijack_wx()
719 self.wx_mainloop = hijack_wx()
720
720
721 # Allows us to use both Tk and GTK.
721 # Allows us to use both Tk and GTK.
722 self.tk = get_tk()
722 self.tk = get_tk()
723
723
724
724
725 # HACK: slot for banner in self; it will be passed to the mainloop
725 # HACK: slot for banner in self; it will be passed to the mainloop
726 # method only and .run() needs it. The actual value will be set by
726 # method only and .run() needs it. The actual value will be set by
727 # .mainloop().
727 # .mainloop().
728 self._banner = None
728 self._banner = None
729
729
730 self.app = None
730 self.app = None
731
731
732 def wxexit(self, *args):
732 def wxexit(self, *args):
733 if self.app is not None:
733 if self.app is not None:
734 self.app.agent.timer.Stop()
734 self.app.agent.timer.Stop()
735 self.app.ExitMainLoop()
735 self.app.ExitMainLoop()
736
736
737 def run(self):
737 def run(self):
738 self.IP.mainloop(self._banner)
738 self.IP.mainloop(self._banner)
739 self.IP.kill()
739 self.IP.kill()
740
740
741 def mainloop(self,sys_exit=0,banner=None):
741 def mainloop(self,sys_exit=0,banner=None):
742
742
743 self._banner = banner
743 self._banner = banner
744
744
745 self.start()
745 self.start()
746
746
747 class TimerAgent(self.wx.MiniFrame):
747 class TimerAgent(self.wx.MiniFrame):
748 wx = self.wx
748 wx = self.wx
749 IP = self.IP
749 IP = self.IP
750 tk = self.tk
750 tk = self.tk
751 def __init__(self, parent, interval):
751 def __init__(self, parent, interval):
752 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
752 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
753 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
753 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
754 size=(100, 100),style=style)
754 size=(100, 100),style=style)
755 self.Show(False)
755 self.Show(False)
756 self.interval = interval
756 self.interval = interval
757 self.timerId = self.wx.NewId()
757 self.timerId = self.wx.NewId()
758
758
759 def StartWork(self):
759 def StartWork(self):
760 self.timer = self.wx.Timer(self, self.timerId)
760 self.timer = self.wx.Timer(self, self.timerId)
761 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
761 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
762 self.timer.Start(self.interval)
762 self.timer.Start(self.interval)
763
763
764 def OnTimer(self, event):
764 def OnTimer(self, event):
765 update_tk(self.tk)
765 update_tk(self.tk)
766 self.IP.runcode()
766 self.IP.runcode()
767
767
768 class App(self.wx.App):
768 class App(self.wx.App):
769 wx = self.wx
769 wx = self.wx
770 TIMEOUT = self.TIMEOUT
770 TIMEOUT = self.TIMEOUT
771 def OnInit(self):
771 def OnInit(self):
772 'Create the main window and insert the custom frame'
772 'Create the main window and insert the custom frame'
773 self.agent = TimerAgent(None, self.TIMEOUT)
773 self.agent = TimerAgent(None, self.TIMEOUT)
774 self.agent.Show(False)
774 self.agent.Show(False)
775 self.agent.StartWork()
775 self.agent.StartWork()
776 return True
776 return True
777
777
778 self.app = App(redirect=False)
778 self.app = App(redirect=False)
779 self.wx_mainloop(self.app)
779 self.wx_mainloop(self.app)
780 self.join()
780 self.join()
781
781
782
782
783 class IPShellQt(threading.Thread):
783 class IPShellQt(threading.Thread):
784 """Run a Qt event loop in a separate thread.
784 """Run a Qt event loop in a separate thread.
785
785
786 Python commands can be passed to the thread where they will be executed.
786 Python commands can be passed to the thread where they will be executed.
787 This is implemented by periodically checking for passed code using a
787 This is implemented by periodically checking for passed code using a
788 Qt timer / slot."""
788 Qt timer / slot."""
789
789
790 TIMEOUT = 100 # Millisecond interval between timeouts.
790 TIMEOUT = 100 # Millisecond interval between timeouts.
791
791
792 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
792 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
793 debug=0,shell_class=MTInteractiveShell):
793 debug=0,shell_class=MTInteractiveShell):
794
794
795 import qt
795 import qt
796
796
797 class newQApplication:
797 class newQApplication:
798 def __init__( self ):
798 def __init__( self ):
799 self.QApplication = qt.QApplication
799 self.QApplication = qt.QApplication
800
800
801 def __call__( *args, **kwargs ):
801 def __call__( *args, **kwargs ):
802 return qt.qApp
802 return qt.qApp
803
803
804 def exec_loop( *args, **kwargs ):
804 def exec_loop( *args, **kwargs ):
805 pass
805 pass
806
806
807 def __getattr__( self, name ):
807 def __getattr__( self, name ):
808 return getattr( self.QApplication, name )
808 return getattr( self.QApplication, name )
809
809
810 qt.QApplication = newQApplication()
810 qt.QApplication = newQApplication()
811
811
812 # Allows us to use both Tk and QT.
812 # Allows us to use both Tk and QT.
813 self.tk = get_tk()
813 self.tk = get_tk()
814
814
815 self.IP = make_IPython(argv,user_ns=user_ns,
815 self.IP = make_IPython(argv,user_ns=user_ns,
816 user_global_ns=user_global_ns,
816 user_global_ns=user_global_ns,
817 debug=debug,
817 debug=debug,
818 shell_class=shell_class,
818 shell_class=shell_class,
819 on_kill=[qt.qApp.exit])
819 on_kill=[qt.qApp.exit])
820
820
821 # HACK: slot for banner in self; it will be passed to the mainloop
821 # HACK: slot for banner in self; it will be passed to the mainloop
822 # method only and .run() needs it. The actual value will be set by
822 # method only and .run() needs it. The actual value will be set by
823 # .mainloop().
823 # .mainloop().
824 self._banner = None
824 self._banner = None
825
825
826 threading.Thread.__init__(self)
826 threading.Thread.__init__(self)
827
827
828 def run(self):
828 def run(self):
829 self.IP.mainloop(self._banner)
829 self.IP.mainloop(self._banner)
830 self.IP.kill()
830 self.IP.kill()
831
831
832 def mainloop(self,sys_exit=0,banner=None):
832 def mainloop(self,sys_exit=0,banner=None):
833
833
834 import qt
834 import qt
835
835
836 self._banner = banner
836 self._banner = banner
837
837
838 if qt.QApplication.startingUp():
838 if qt.QApplication.startingUp():
839 a = qt.QApplication.QApplication(sys.argv)
839 a = qt.QApplication.QApplication(sys.argv)
840 self.timer = qt.QTimer()
840 self.timer = qt.QTimer()
841 qt.QObject.connect( self.timer, qt.SIGNAL( 'timeout()' ), self.on_timer )
841 qt.QObject.connect( self.timer, qt.SIGNAL( 'timeout()' ), self.on_timer )
842
842
843 self.start()
843 self.start()
844 self.timer.start( self.TIMEOUT, True )
844 self.timer.start( self.TIMEOUT, True )
845 while True:
845 while True:
846 if self.IP._kill: break
846 if self.IP._kill: break
847 qt.qApp.exec_loop()
847 qt.qApp.exec_loop()
848 self.join()
848 self.join()
849
849
850 def on_timer(self):
850 def on_timer(self):
851 update_tk(self.tk)
851 update_tk(self.tk)
852 result = self.IP.runcode()
852 result = self.IP.runcode()
853 self.timer.start( self.TIMEOUT, True )
853 self.timer.start( self.TIMEOUT, True )
854 return result
854 return result
855
855
856
856
857 class IPShellQt4(threading.Thread):
857 class IPShellQt4(threading.Thread):
858 """Run a Qt event loop in a separate thread.
858 """Run a Qt event loop in a separate thread.
859
859
860 Python commands can be passed to the thread where they will be executed.
860 Python commands can be passed to the thread where they will be executed.
861 This is implemented by periodically checking for passed code using a
861 This is implemented by periodically checking for passed code using a
862 Qt timer / slot."""
862 Qt timer / slot."""
863
863
864 TIMEOUT = 100 # Millisecond interval between timeouts.
864 TIMEOUT = 100 # Millisecond interval between timeouts.
865
865
866 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
866 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
867 debug=0,shell_class=MTInteractiveShell):
867 debug=0,shell_class=MTInteractiveShell):
868
868
869 from PyQt4 import QtCore, QtGui
869 from PyQt4 import QtCore, QtGui
870
870
871 class newQApplication:
871 class newQApplication:
872 def __init__( self ):
872 def __init__( self ):
873 self.QApplication = QtGui.QApplication
873 self.QApplication = QtGui.QApplication
874
874
875 def __call__( *args, **kwargs ):
875 def __call__( *args, **kwargs ):
876 return QtGui.qApp
876 return QtGui.qApp
877
877
878 def exec_loop( *args, **kwargs ):
878 def exec_loop( *args, **kwargs ):
879 pass
879 pass
880
880
881 def __getattr__( self, name ):
881 def __getattr__( self, name ):
882 return getattr( self.QApplication, name )
882 return getattr( self.QApplication, name )
883
883
884 QtGui.QApplication = newQApplication()
884 QtGui.QApplication = newQApplication()
885
885
886 # Allows us to use both Tk and QT.
886 # Allows us to use both Tk and QT.
887 self.tk = get_tk()
887 self.tk = get_tk()
888
888
889 self.IP = make_IPython(argv,user_ns=user_ns,
889 self.IP = make_IPython(argv,user_ns=user_ns,
890 user_global_ns=user_global_ns,
890 user_global_ns=user_global_ns,
891 debug=debug,
891 debug=debug,
892 shell_class=shell_class,
892 shell_class=shell_class,
893 on_kill=[QtGui.qApp.exit])
893 on_kill=[QtGui.qApp.exit])
894
894
895 # HACK: slot for banner in self; it will be passed to the mainloop
895 # HACK: slot for banner in self; it will be passed to the mainloop
896 # method only and .run() needs it. The actual value will be set by
896 # method only and .run() needs it. The actual value will be set by
897 # .mainloop().
897 # .mainloop().
898 self._banner = None
898 self._banner = None
899
899
900 threading.Thread.__init__(self)
900 threading.Thread.__init__(self)
901
901
902 def run(self):
902 def run(self):
903 self.IP.mainloop(self._banner)
903 self.IP.mainloop(self._banner)
904 self.IP.kill()
904 self.IP.kill()
905
905
906 def mainloop(self,sys_exit=0,banner=None):
906 def mainloop(self,sys_exit=0,banner=None):
907
907
908 from PyQt4 import QtCore, QtGui
908 from PyQt4 import QtCore, QtGui
909
909
910 self._banner = banner
910 self._banner = banner
911
911
912 if QtGui.QApplication.startingUp():
912 if QtGui.QApplication.startingUp():
913 a = QtGui.QApplication.QApplication(sys.argv)
913 a = QtGui.QApplication.QApplication(sys.argv)
914 self.timer = QtCore.QTimer()
914 self.timer = QtCore.QTimer()
915 QtCore.QObject.connect( self.timer, QtCore.SIGNAL( 'timeout()' ), self.on_timer )
915 QtCore.QObject.connect( self.timer, QtCore.SIGNAL( 'timeout()' ), self.on_timer )
916
916
917 self.start()
917 self.start()
918 self.timer.start( self.TIMEOUT )
918 self.timer.start( self.TIMEOUT )
919 while True:
919 while True:
920 if self.IP._kill: break
920 if self.IP._kill: break
921 QtGui.qApp.exec_()
921 QtGui.qApp.exec_()
922 self.join()
922 self.join()
923
923
924 def on_timer(self):
924 def on_timer(self):
925 update_tk(self.tk)
925 update_tk(self.tk)
926 result = self.IP.runcode()
926 result = self.IP.runcode()
927 self.timer.start( self.TIMEOUT )
927 self.timer.start( self.TIMEOUT )
928 return result
928 return result
929
929
930
930
931 # A set of matplotlib public IPython shell classes, for single-threaded
931 # A set of matplotlib public IPython shell classes, for single-threaded
932 # (Tk* and FLTK* backends) and multithreaded (GTK* and WX* backends) use.
932 # (Tk* and FLTK* backends) and multithreaded (GTK* and WX* backends) use.
933 def _load_pylab(user_ns):
933 def _load_pylab(user_ns):
934 """Allow users to disable pulling all of pylab into the top-level
934 """Allow users to disable pulling all of pylab into the top-level
935 namespace.
935 namespace.
936
936
937 This little utility must be called AFTER the actual ipython instance is
937 This little utility must be called AFTER the actual ipython instance is
938 running, since only then will the options file have been fully parsed."""
938 running, since only then will the options file have been fully parsed."""
939
939
940 ip = IPython.ipapi.get()
940 ip = IPython.ipapi.get()
941 if ip.options.pylab_import_all:
941 if ip.options.pylab_import_all:
942 exec "from matplotlib.pylab import *" in user_ns
942 exec "from matplotlib.pylab import *" in user_ns
943
943
944 class IPShellMatplotlib(IPShell):
944 class IPShellMatplotlib(IPShell):
945 """Subclass IPShell with MatplotlibShell as the internal shell.
945 """Subclass IPShell with MatplotlibShell as the internal shell.
946
946
947 Single-threaded class, meant for the Tk* and FLTK* backends.
947 Single-threaded class, meant for the Tk* and FLTK* backends.
948
948
949 Having this on a separate class simplifies the external driver code."""
949 Having this on a separate class simplifies the external driver code."""
950
950
951 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
951 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
952 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
952 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
953 shell_class=MatplotlibShell)
953 shell_class=MatplotlibShell)
954 _load_pylab(user_ns)
954 _load_pylab(self.IP.user_ns)
955
955
956 class IPShellMatplotlibGTK(IPShellGTK):
956 class IPShellMatplotlibGTK(IPShellGTK):
957 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
957 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
958
958
959 Multi-threaded class, meant for the GTK* backends."""
959 Multi-threaded class, meant for the GTK* backends."""
960
960
961 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
961 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
962 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
962 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
963 shell_class=MatplotlibMTShell)
963 shell_class=MatplotlibMTShell)
964 _load_pylab(user_ns)
964 _load_pylab(self.IP.user_ns)
965
965
966 class IPShellMatplotlibWX(IPShellWX):
966 class IPShellMatplotlibWX(IPShellWX):
967 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
967 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
968
968
969 Multi-threaded class, meant for the WX* backends."""
969 Multi-threaded class, meant for the WX* backends."""
970
970
971 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
971 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
972 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
972 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
973 shell_class=MatplotlibMTShell)
973 shell_class=MatplotlibMTShell)
974 _load_pylab(user_ns)
974 _load_pylab(self.IP.user_ns)
975
975
976 class IPShellMatplotlibQt(IPShellQt):
976 class IPShellMatplotlibQt(IPShellQt):
977 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
977 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
978
978
979 Multi-threaded class, meant for the Qt* backends."""
979 Multi-threaded class, meant for the Qt* backends."""
980
980
981 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
981 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
982 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
982 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
983 shell_class=MatplotlibMTShell)
983 shell_class=MatplotlibMTShell)
984 _load_pylab(user_ns)
984 _load_pylab(self.IP.user_ns)
985
985
986 class IPShellMatplotlibQt4(IPShellQt4):
986 class IPShellMatplotlibQt4(IPShellQt4):
987 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
987 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
988
988
989 Multi-threaded class, meant for the Qt4* backends."""
989 Multi-threaded class, meant for the Qt4* backends."""
990
990
991 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
991 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
992 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
992 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
993 shell_class=MatplotlibMTShell)
993 shell_class=MatplotlibMTShell)
994 _load_pylab(user_ns)
994 _load_pylab(self.IP.user_ns)
995
995
996 #-----------------------------------------------------------------------------
996 #-----------------------------------------------------------------------------
997 # Factory functions to actually start the proper thread-aware shell
997 # Factory functions to actually start the proper thread-aware shell
998
998
999 def _matplotlib_shell_class():
999 def _matplotlib_shell_class():
1000 """Factory function to handle shell class selection for matplotlib.
1000 """Factory function to handle shell class selection for matplotlib.
1001
1001
1002 The proper shell class to use depends on the matplotlib backend, since
1002 The proper shell class to use depends on the matplotlib backend, since
1003 each backend requires a different threading strategy."""
1003 each backend requires a different threading strategy."""
1004
1004
1005 try:
1005 try:
1006 import matplotlib
1006 import matplotlib
1007 except ImportError:
1007 except ImportError:
1008 error('matplotlib could NOT be imported! Starting normal IPython.')
1008 error('matplotlib could NOT be imported! Starting normal IPython.')
1009 sh_class = IPShell
1009 sh_class = IPShell
1010 else:
1010 else:
1011 backend = matplotlib.rcParams['backend']
1011 backend = matplotlib.rcParams['backend']
1012 if backend.startswith('GTK'):
1012 if backend.startswith('GTK'):
1013 sh_class = IPShellMatplotlibGTK
1013 sh_class = IPShellMatplotlibGTK
1014 elif backend.startswith('WX'):
1014 elif backend.startswith('WX'):
1015 sh_class = IPShellMatplotlibWX
1015 sh_class = IPShellMatplotlibWX
1016 elif backend.startswith('Qt4'):
1016 elif backend.startswith('Qt4'):
1017 sh_class = IPShellMatplotlibQt4
1017 sh_class = IPShellMatplotlibQt4
1018 elif backend.startswith('Qt'):
1018 elif backend.startswith('Qt'):
1019 sh_class = IPShellMatplotlibQt
1019 sh_class = IPShellMatplotlibQt
1020 else:
1020 else:
1021 sh_class = IPShellMatplotlib
1021 sh_class = IPShellMatplotlib
1022 #print 'Using %s with the %s backend.' % (sh_class,backend) # dbg
1022 #print 'Using %s with the %s backend.' % (sh_class,backend) # dbg
1023 return sh_class
1023 return sh_class
1024
1024
1025 # This is the one which should be called by external code.
1025 # This is the one which should be called by external code.
1026 def start(user_ns = None):
1026 def start(user_ns = None):
1027 """Return a running shell instance, dealing with threading options.
1027 """Return a running shell instance, dealing with threading options.
1028
1028
1029 This is a factory function which will instantiate the proper IPython shell
1029 This is a factory function which will instantiate the proper IPython shell
1030 based on the user's threading choice. Such a selector is needed because
1030 based on the user's threading choice. Such a selector is needed because
1031 different GUI toolkits require different thread handling details."""
1031 different GUI toolkits require different thread handling details."""
1032
1032
1033 global USE_TK
1033 global USE_TK
1034 # Crude sys.argv hack to extract the threading options.
1034 # Crude sys.argv hack to extract the threading options.
1035 argv = sys.argv
1035 argv = sys.argv
1036 if len(argv) > 1:
1036 if len(argv) > 1:
1037 if len(argv) > 2:
1037 if len(argv) > 2:
1038 arg2 = argv[2]
1038 arg2 = argv[2]
1039 if arg2.endswith('-tk'):
1039 if arg2.endswith('-tk'):
1040 USE_TK = True
1040 USE_TK = True
1041 arg1 = argv[1]
1041 arg1 = argv[1]
1042 if arg1.endswith('-gthread'):
1042 if arg1.endswith('-gthread'):
1043 shell = IPShellGTK
1043 shell = IPShellGTK
1044 elif arg1.endswith( '-qthread' ):
1044 elif arg1.endswith( '-qthread' ):
1045 shell = IPShellQt
1045 shell = IPShellQt
1046 elif arg1.endswith( '-q4thread' ):
1046 elif arg1.endswith( '-q4thread' ):
1047 shell = IPShellQt4
1047 shell = IPShellQt4
1048 elif arg1.endswith('-wthread'):
1048 elif arg1.endswith('-wthread'):
1049 shell = IPShellWX
1049 shell = IPShellWX
1050 elif arg1.endswith('-pylab'):
1050 elif arg1.endswith('-pylab'):
1051 shell = _matplotlib_shell_class()
1051 shell = _matplotlib_shell_class()
1052 else:
1052 else:
1053 shell = IPShell
1053 shell = IPShell
1054 else:
1054 else:
1055 shell = IPShell
1055 shell = IPShell
1056 return shell(user_ns = user_ns)
1056 return shell(user_ns = user_ns)
1057
1057
1058 # Some aliases for backwards compatibility
1058 # Some aliases for backwards compatibility
1059 IPythonShell = IPShell
1059 IPythonShell = IPShell
1060 IPythonShellEmbed = IPShellEmbed
1060 IPythonShellEmbed = IPShellEmbed
1061 #************************ End of file <Shell.py> ***************************
1061 #************************ End of file <Shell.py> ***************************
General Comments 0
You need to be logged in to leave comments. Login now