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