##// END OF EJS Templates
ipmaker.py => coore/ipmaker.py and imports updated.
Brian Granger -
Show More
@@ -1,1247 +1,1247 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
7
8 #*****************************************************************************
8 #*****************************************************************************
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #*****************************************************************************
13 #*****************************************************************************
14
14
15 # Code begins
15 # Code begins
16 # Stdlib imports
16 # Stdlib imports
17 import __builtin__
17 import __builtin__
18 import __main__
18 import __main__
19 import Queue
19 import Queue
20 import inspect
20 import inspect
21 import os
21 import os
22 import sys
22 import sys
23 import thread
23 import thread
24 import threading
24 import threading
25 import time
25 import time
26
26
27 from signal import signal, SIGINT
27 from signal import signal, SIGINT
28
28
29 try:
29 try:
30 import ctypes
30 import ctypes
31 HAS_CTYPES = True
31 HAS_CTYPES = True
32 except ImportError:
32 except ImportError:
33 HAS_CTYPES = False
33 HAS_CTYPES = False
34
34
35 # IPython imports
35 # IPython imports
36 import IPython
36 import IPython
37 from IPython import ultraTB
37 from IPython import ultraTB
38 from IPython.core import ipapi
38 from IPython.core import ipapi
39 from IPython.Magic import Magic
39 from IPython.Magic import Magic
40 from IPython.utils.genutils import Term,warn,error,flag_calls, ask_yes_no
40 from IPython.utils.genutils import Term,warn,error,flag_calls, ask_yes_no
41 from IPython.core.iplib import InteractiveShell
41 from IPython.core.iplib import InteractiveShell
42 from IPython.ipmaker import make_IPython
42 from IPython.core.ipmaker import make_IPython
43 from IPython.ipstruct import Struct
43 from IPython.ipstruct import Struct
44 from IPython.testing import decorators as testdec
44 from IPython.testing import decorators as testdec
45
45
46 # Globals
46 # Globals
47 # global flag to pass around information about Ctrl-C without exceptions
47 # global flag to pass around information about Ctrl-C without exceptions
48 KBINT = False
48 KBINT = False
49
49
50 # global flag to turn on/off Tk support.
50 # global flag to turn on/off Tk support.
51 USE_TK = False
51 USE_TK = False
52
52
53 # ID for the main thread, used for cross-thread exceptions
53 # ID for the main thread, used for cross-thread exceptions
54 MAIN_THREAD_ID = thread.get_ident()
54 MAIN_THREAD_ID = thread.get_ident()
55
55
56 # Tag when runcode() is active, for exception handling
56 # Tag when runcode() is active, for exception handling
57 CODE_RUN = None
57 CODE_RUN = None
58
58
59 # Default timeout for waiting for multithreaded shells (in seconds)
59 # Default timeout for waiting for multithreaded shells (in seconds)
60 GUI_TIMEOUT = 10
60 GUI_TIMEOUT = 10
61
61
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63 # This class is trivial now, but I want to have it in to publish a clean
63 # This class is trivial now, but I want to have it in to publish a clean
64 # interface. Later when the internals are reorganized, code that uses this
64 # interface. Later when the internals are reorganized, code that uses this
65 # shouldn't have to change.
65 # shouldn't have to change.
66
66
67 class IPShell:
67 class IPShell:
68 """Create an IPython instance."""
68 """Create an IPython instance."""
69
69
70 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
70 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
71 debug=1,shell_class=InteractiveShell):
71 debug=1,shell_class=InteractiveShell):
72 self.IP = make_IPython(argv,user_ns=user_ns,
72 self.IP = make_IPython(argv,user_ns=user_ns,
73 user_global_ns=user_global_ns,
73 user_global_ns=user_global_ns,
74 debug=debug,shell_class=shell_class)
74 debug=debug,shell_class=shell_class)
75
75
76 def mainloop(self,sys_exit=0,banner=None):
76 def mainloop(self,sys_exit=0,banner=None):
77 self.IP.mainloop(banner)
77 self.IP.mainloop(banner)
78 if sys_exit:
78 if sys_exit:
79 sys.exit()
79 sys.exit()
80
80
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 def kill_embedded(self,parameter_s=''):
82 def kill_embedded(self,parameter_s=''):
83 """%kill_embedded : deactivate for good the current embedded IPython.
83 """%kill_embedded : deactivate for good the current embedded IPython.
84
84
85 This function (after asking for confirmation) sets an internal flag so that
85 This function (after asking for confirmation) sets an internal flag so that
86 an embedded IPython will never activate again. This is useful to
86 an embedded IPython will never activate again. This is useful to
87 permanently disable a shell that is being called inside a loop: once you've
87 permanently disable a shell that is being called inside a loop: once you've
88 figured out what you needed from it, you may then kill it and the program
88 figured out what you needed from it, you may then kill it and the program
89 will then continue to run without the interactive shell interfering again.
89 will then continue to run without the interactive shell interfering again.
90 """
90 """
91
91
92 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
92 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
93 "(y/n)? [y/N] ",'n')
93 "(y/n)? [y/N] ",'n')
94 if kill:
94 if kill:
95 self.shell.embedded_active = False
95 self.shell.embedded_active = False
96 print "This embedded IPython will not reactivate anymore once you exit."
96 print "This embedded IPython will not reactivate anymore once you exit."
97
97
98 class IPShellEmbed:
98 class IPShellEmbed:
99 """Allow embedding an IPython shell into a running program.
99 """Allow embedding an IPython shell into a running program.
100
100
101 Instances of this class are callable, with the __call__ method being an
101 Instances of this class are callable, with the __call__ method being an
102 alias to the embed() method of an InteractiveShell instance.
102 alias to the embed() method of an InteractiveShell instance.
103
103
104 Usage (see also the example-embed.py file for a running example):
104 Usage (see also the example-embed.py file for a running example):
105
105
106 ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
106 ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
107
107
108 - argv: list containing valid command-line options for IPython, as they
108 - argv: list containing valid command-line options for IPython, as they
109 would appear in sys.argv[1:].
109 would appear in sys.argv[1:].
110
110
111 For example, the following command-line options:
111 For example, the following command-line options:
112
112
113 $ ipython -prompt_in1 'Input <\\#>' -colors LightBG
113 $ ipython -prompt_in1 'Input <\\#>' -colors LightBG
114
114
115 would be passed in the argv list as:
115 would be passed in the argv list as:
116
116
117 ['-prompt_in1','Input <\\#>','-colors','LightBG']
117 ['-prompt_in1','Input <\\#>','-colors','LightBG']
118
118
119 - banner: string which gets printed every time the interpreter starts.
119 - banner: string which gets printed every time the interpreter starts.
120
120
121 - exit_msg: string which gets printed every time the interpreter exits.
121 - exit_msg: string which gets printed every time the interpreter exits.
122
122
123 - rc_override: a dict or Struct of configuration options such as those
123 - rc_override: a dict or Struct of configuration options such as those
124 used by IPython. These options are read from your ~/.ipython/ipythonrc
124 used by IPython. These options are read from your ~/.ipython/ipythonrc
125 file when the Shell object is created. Passing an explicit rc_override
125 file when the Shell object is created. Passing an explicit rc_override
126 dict with any options you want allows you to override those values at
126 dict with any options you want allows you to override those values at
127 creation time without having to modify the file. This way you can create
127 creation time without having to modify the file. This way you can create
128 embeddable instances configured in any way you want without editing any
128 embeddable instances configured in any way you want without editing any
129 global files (thus keeping your interactive IPython configuration
129 global files (thus keeping your interactive IPython configuration
130 unchanged).
130 unchanged).
131
131
132 Then the ipshell instance can be called anywhere inside your code:
132 Then the ipshell instance can be called anywhere inside your code:
133
133
134 ipshell(header='') -> Opens up an IPython shell.
134 ipshell(header='') -> Opens up an IPython shell.
135
135
136 - header: string printed by the IPython shell upon startup. This can let
136 - header: string printed by the IPython shell upon startup. This can let
137 you know where in your code you are when dropping into the shell. Note
137 you know where in your code you are when dropping into the shell. Note
138 that 'banner' gets prepended to all calls, so header is used for
138 that 'banner' gets prepended to all calls, so header is used for
139 location-specific information.
139 location-specific information.
140
140
141 For more details, see the __call__ method below.
141 For more details, see the __call__ method below.
142
142
143 When the IPython shell is exited with Ctrl-D, normal program execution
143 When the IPython shell is exited with Ctrl-D, normal program execution
144 resumes.
144 resumes.
145
145
146 This functionality was inspired by a posting on comp.lang.python by cmkl
146 This functionality was inspired by a posting on comp.lang.python by cmkl
147 <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
147 <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
148 by the IDL stop/continue commands."""
148 by the IDL stop/continue commands."""
149
149
150 def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None,
150 def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None,
151 user_ns=None):
151 user_ns=None):
152 """Note that argv here is a string, NOT a list."""
152 """Note that argv here is a string, NOT a list."""
153 self.set_banner(banner)
153 self.set_banner(banner)
154 self.set_exit_msg(exit_msg)
154 self.set_exit_msg(exit_msg)
155 self.set_dummy_mode(0)
155 self.set_dummy_mode(0)
156
156
157 # sys.displayhook is a global, we need to save the user's original
157 # sys.displayhook is a global, we need to save the user's original
158 # Don't rely on __displayhook__, as the user may have changed that.
158 # Don't rely on __displayhook__, as the user may have changed that.
159 self.sys_displayhook_ori = sys.displayhook
159 self.sys_displayhook_ori = sys.displayhook
160
160
161 # save readline completer status
161 # save readline completer status
162 try:
162 try:
163 #print 'Save completer',sys.ipcompleter # dbg
163 #print 'Save completer',sys.ipcompleter # dbg
164 self.sys_ipcompleter_ori = sys.ipcompleter
164 self.sys_ipcompleter_ori = sys.ipcompleter
165 except:
165 except:
166 pass # not nested with IPython
166 pass # not nested with IPython
167
167
168 self.IP = make_IPython(argv,rc_override=rc_override,
168 self.IP = make_IPython(argv,rc_override=rc_override,
169 embedded=True,
169 embedded=True,
170 user_ns=user_ns)
170 user_ns=user_ns)
171
171
172 ip = ipapi.IPApi(self.IP)
172 ip = ipapi.IPApi(self.IP)
173 ip.expose_magic("kill_embedded",kill_embedded)
173 ip.expose_magic("kill_embedded",kill_embedded)
174
174
175 # copy our own displayhook also
175 # copy our own displayhook also
176 self.sys_displayhook_embed = sys.displayhook
176 self.sys_displayhook_embed = sys.displayhook
177 # and leave the system's display hook clean
177 # and leave the system's display hook clean
178 sys.displayhook = self.sys_displayhook_ori
178 sys.displayhook = self.sys_displayhook_ori
179 # don't use the ipython crash handler so that user exceptions aren't
179 # don't use the ipython crash handler so that user exceptions aren't
180 # trapped
180 # trapped
181 sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
181 sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
182 mode = self.IP.rc.xmode,
182 mode = self.IP.rc.xmode,
183 call_pdb = self.IP.rc.pdb)
183 call_pdb = self.IP.rc.pdb)
184 self.restore_system_completer()
184 self.restore_system_completer()
185
185
186 def restore_system_completer(self):
186 def restore_system_completer(self):
187 """Restores the readline completer which was in place.
187 """Restores the readline completer which was in place.
188
188
189 This allows embedded IPython within IPython not to disrupt the
189 This allows embedded IPython within IPython not to disrupt the
190 parent's completion.
190 parent's completion.
191 """
191 """
192
192
193 try:
193 try:
194 self.IP.readline.set_completer(self.sys_ipcompleter_ori)
194 self.IP.readline.set_completer(self.sys_ipcompleter_ori)
195 sys.ipcompleter = self.sys_ipcompleter_ori
195 sys.ipcompleter = self.sys_ipcompleter_ori
196 except:
196 except:
197 pass
197 pass
198
198
199 def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
199 def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
200 """Activate the interactive interpreter.
200 """Activate the interactive interpreter.
201
201
202 __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
202 __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
203 the interpreter shell with the given local and global namespaces, and
203 the interpreter shell with the given local and global namespaces, and
204 optionally print a header string at startup.
204 optionally print a header string at startup.
205
205
206 The shell can be globally activated/deactivated using the
206 The shell can be globally activated/deactivated using the
207 set/get_dummy_mode methods. This allows you to turn off a shell used
207 set/get_dummy_mode methods. This allows you to turn off a shell used
208 for debugging globally.
208 for debugging globally.
209
209
210 However, *each* time you call the shell you can override the current
210 However, *each* time you call the shell you can override the current
211 state of dummy_mode with the optional keyword parameter 'dummy'. For
211 state of dummy_mode with the optional keyword parameter 'dummy'. For
212 example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
212 example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
213 can still have a specific call work by making it as IPShell(dummy=0).
213 can still have a specific call work by making it as IPShell(dummy=0).
214
214
215 The optional keyword parameter dummy controls whether the call
215 The optional keyword parameter dummy controls whether the call
216 actually does anything. """
216 actually does anything. """
217
217
218 # If the user has turned it off, go away
218 # If the user has turned it off, go away
219 if not self.IP.embedded_active:
219 if not self.IP.embedded_active:
220 return
220 return
221
221
222 # Normal exits from interactive mode set this flag, so the shell can't
222 # Normal exits from interactive mode set this flag, so the shell can't
223 # re-enter (it checks this variable at the start of interactive mode).
223 # re-enter (it checks this variable at the start of interactive mode).
224 self.IP.exit_now = False
224 self.IP.exit_now = False
225
225
226 # Allow the dummy parameter to override the global __dummy_mode
226 # Allow the dummy parameter to override the global __dummy_mode
227 if dummy or (dummy != 0 and self.__dummy_mode):
227 if dummy or (dummy != 0 and self.__dummy_mode):
228 return
228 return
229
229
230 # Set global subsystems (display,completions) to our values
230 # Set global subsystems (display,completions) to our values
231 sys.displayhook = self.sys_displayhook_embed
231 sys.displayhook = self.sys_displayhook_embed
232 if self.IP.has_readline:
232 if self.IP.has_readline:
233 self.IP.set_completer()
233 self.IP.set_completer()
234
234
235 if self.banner and header:
235 if self.banner and header:
236 format = '%s\n%s\n'
236 format = '%s\n%s\n'
237 else:
237 else:
238 format = '%s%s\n'
238 format = '%s%s\n'
239 banner = format % (self.banner,header)
239 banner = format % (self.banner,header)
240
240
241 # Call the embedding code with a stack depth of 1 so it can skip over
241 # Call the embedding code with a stack depth of 1 so it can skip over
242 # our call and get the original caller's namespaces.
242 # our call and get the original caller's namespaces.
243 self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
243 self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
244
244
245 if self.exit_msg:
245 if self.exit_msg:
246 print self.exit_msg
246 print self.exit_msg
247
247
248 # Restore global systems (display, completion)
248 # Restore global systems (display, completion)
249 sys.displayhook = self.sys_displayhook_ori
249 sys.displayhook = self.sys_displayhook_ori
250 self.restore_system_completer()
250 self.restore_system_completer()
251
251
252 def set_dummy_mode(self,dummy):
252 def set_dummy_mode(self,dummy):
253 """Sets the embeddable shell's dummy mode parameter.
253 """Sets the embeddable shell's dummy mode parameter.
254
254
255 set_dummy_mode(dummy): dummy = 0 or 1.
255 set_dummy_mode(dummy): dummy = 0 or 1.
256
256
257 This parameter is persistent and makes calls to the embeddable shell
257 This parameter is persistent and makes calls to the embeddable shell
258 silently return without performing any action. This allows you to
258 silently return without performing any action. This allows you to
259 globally activate or deactivate a shell you're using with a single call.
259 globally activate or deactivate a shell you're using with a single call.
260
260
261 If you need to manually"""
261 If you need to manually"""
262
262
263 if dummy not in [0,1,False,True]:
263 if dummy not in [0,1,False,True]:
264 raise ValueError,'dummy parameter must be boolean'
264 raise ValueError,'dummy parameter must be boolean'
265 self.__dummy_mode = dummy
265 self.__dummy_mode = dummy
266
266
267 def get_dummy_mode(self):
267 def get_dummy_mode(self):
268 """Return the current value of the dummy mode parameter.
268 """Return the current value of the dummy mode parameter.
269 """
269 """
270 return self.__dummy_mode
270 return self.__dummy_mode
271
271
272 def set_banner(self,banner):
272 def set_banner(self,banner):
273 """Sets the global banner.
273 """Sets the global banner.
274
274
275 This banner gets prepended to every header printed when the shell
275 This banner gets prepended to every header printed when the shell
276 instance is called."""
276 instance is called."""
277
277
278 self.banner = banner
278 self.banner = banner
279
279
280 def set_exit_msg(self,exit_msg):
280 def set_exit_msg(self,exit_msg):
281 """Sets the global exit_msg.
281 """Sets the global exit_msg.
282
282
283 This exit message gets printed upon exiting every time the embedded
283 This exit message gets printed upon exiting every time the embedded
284 shell is called. It is None by default. """
284 shell is called. It is None by default. """
285
285
286 self.exit_msg = exit_msg
286 self.exit_msg = exit_msg
287
287
288 #-----------------------------------------------------------------------------
288 #-----------------------------------------------------------------------------
289 if HAS_CTYPES:
289 if HAS_CTYPES:
290 # Add async exception support. Trick taken from:
290 # Add async exception support. Trick taken from:
291 # http://sebulba.wikispaces.com/recipe+thread2
291 # http://sebulba.wikispaces.com/recipe+thread2
292 def _async_raise(tid, exctype):
292 def _async_raise(tid, exctype):
293 """raises the exception, performs cleanup if needed"""
293 """raises the exception, performs cleanup if needed"""
294 if not inspect.isclass(exctype):
294 if not inspect.isclass(exctype):
295 raise TypeError("Only types can be raised (not instances)")
295 raise TypeError("Only types can be raised (not instances)")
296 # Explicit cast to c_long is necessary for 64-bit support:
296 # Explicit cast to c_long is necessary for 64-bit support:
297 # See https://bugs.launchpad.net/ipython/+bug/237073
297 # See https://bugs.launchpad.net/ipython/+bug/237073
298 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid),
298 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid),
299 ctypes.py_object(exctype))
299 ctypes.py_object(exctype))
300 if res == 0:
300 if res == 0:
301 raise ValueError("invalid thread id")
301 raise ValueError("invalid thread id")
302 elif res != 1:
302 elif res != 1:
303 # If it returns a number greater than one, you're in trouble,
303 # If it returns a number greater than one, you're in trouble,
304 # and you should call it again with exc=NULL to revert the effect
304 # and you should call it again with exc=NULL to revert the effect
305 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
305 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
306 raise SystemError("PyThreadState_SetAsyncExc failed")
306 raise SystemError("PyThreadState_SetAsyncExc failed")
307
307
308 def sigint_handler(signum,stack_frame):
308 def sigint_handler(signum,stack_frame):
309 """Sigint handler for threaded apps.
309 """Sigint handler for threaded apps.
310
310
311 This is a horrible hack to pass information about SIGINT _without_
311 This is a horrible hack to pass information about SIGINT _without_
312 using exceptions, since I haven't been able to properly manage
312 using exceptions, since I haven't been able to properly manage
313 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
313 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
314 done (or at least that's my understanding from a c.l.py thread where
314 done (or at least that's my understanding from a c.l.py thread where
315 this was discussed)."""
315 this was discussed)."""
316
316
317 global KBINT
317 global KBINT
318
318
319 if CODE_RUN:
319 if CODE_RUN:
320 _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
320 _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
321 else:
321 else:
322 KBINT = True
322 KBINT = True
323 print '\nKeyboardInterrupt - Press <Enter> to continue.',
323 print '\nKeyboardInterrupt - Press <Enter> to continue.',
324 Term.cout.flush()
324 Term.cout.flush()
325
325
326 else:
326 else:
327 def sigint_handler(signum,stack_frame):
327 def sigint_handler(signum,stack_frame):
328 """Sigint handler for threaded apps.
328 """Sigint handler for threaded apps.
329
329
330 This is a horrible hack to pass information about SIGINT _without_
330 This is a horrible hack to pass information about SIGINT _without_
331 using exceptions, since I haven't been able to properly manage
331 using exceptions, since I haven't been able to properly manage
332 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
332 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
333 done (or at least that's my understanding from a c.l.py thread where
333 done (or at least that's my understanding from a c.l.py thread where
334 this was discussed)."""
334 this was discussed)."""
335
335
336 global KBINT
336 global KBINT
337
337
338 print '\nKeyboardInterrupt - Press <Enter> to continue.',
338 print '\nKeyboardInterrupt - Press <Enter> to continue.',
339 Term.cout.flush()
339 Term.cout.flush()
340 # Set global flag so that runsource can know that Ctrl-C was hit
340 # Set global flag so that runsource can know that Ctrl-C was hit
341 KBINT = True
341 KBINT = True
342
342
343
343
344 class MTInteractiveShell(InteractiveShell):
344 class MTInteractiveShell(InteractiveShell):
345 """Simple multi-threaded shell."""
345 """Simple multi-threaded shell."""
346
346
347 # Threading strategy taken from:
347 # Threading strategy taken from:
348 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
348 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
349 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
349 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
350 # from the pygtk mailing list, to avoid lockups with system calls.
350 # from the pygtk mailing list, to avoid lockups with system calls.
351
351
352 # class attribute to indicate whether the class supports threads or not.
352 # class attribute to indicate whether the class supports threads or not.
353 # Subclasses with thread support should override this as needed.
353 # Subclasses with thread support should override this as needed.
354 isthreaded = True
354 isthreaded = True
355
355
356 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
356 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
357 user_ns=None,user_global_ns=None,banner2='',
357 user_ns=None,user_global_ns=None,banner2='',
358 gui_timeout=GUI_TIMEOUT,**kw):
358 gui_timeout=GUI_TIMEOUT,**kw):
359 """Similar to the normal InteractiveShell, but with threading control"""
359 """Similar to the normal InteractiveShell, but with threading control"""
360
360
361 InteractiveShell.__init__(self,name,usage,rc,user_ns,
361 InteractiveShell.__init__(self,name,usage,rc,user_ns,
362 user_global_ns,banner2)
362 user_global_ns,banner2)
363
363
364 # Timeout we wait for GUI thread
364 # Timeout we wait for GUI thread
365 self.gui_timeout = gui_timeout
365 self.gui_timeout = gui_timeout
366
366
367 # A queue to hold the code to be executed.
367 # A queue to hold the code to be executed.
368 self.code_queue = Queue.Queue()
368 self.code_queue = Queue.Queue()
369
369
370 # Stuff to do at closing time
370 # Stuff to do at closing time
371 self._kill = None
371 self._kill = None
372 on_kill = kw.get('on_kill', [])
372 on_kill = kw.get('on_kill', [])
373 # Check that all things to kill are callable:
373 # Check that all things to kill are callable:
374 for t in on_kill:
374 for t in on_kill:
375 if not callable(t):
375 if not callable(t):
376 raise TypeError,'on_kill must be a list of callables'
376 raise TypeError,'on_kill must be a list of callables'
377 self.on_kill = on_kill
377 self.on_kill = on_kill
378 # thread identity of the "worker thread" (that may execute code directly)
378 # thread identity of the "worker thread" (that may execute code directly)
379 self.worker_ident = None
379 self.worker_ident = None
380
380
381 def runsource(self, source, filename="<input>", symbol="single"):
381 def runsource(self, source, filename="<input>", symbol="single"):
382 """Compile and run some source in the interpreter.
382 """Compile and run some source in the interpreter.
383
383
384 Modified version of code.py's runsource(), to handle threading issues.
384 Modified version of code.py's runsource(), to handle threading issues.
385 See the original for full docstring details."""
385 See the original for full docstring details."""
386
386
387 global KBINT
387 global KBINT
388
388
389 # If Ctrl-C was typed, we reset the flag and return right away
389 # If Ctrl-C was typed, we reset the flag and return right away
390 if KBINT:
390 if KBINT:
391 KBINT = False
391 KBINT = False
392 return False
392 return False
393
393
394 if self._kill:
394 if self._kill:
395 # can't queue new code if we are being killed
395 # can't queue new code if we are being killed
396 return True
396 return True
397
397
398 try:
398 try:
399 code = self.compile(source, filename, symbol)
399 code = self.compile(source, filename, symbol)
400 except (OverflowError, SyntaxError, ValueError):
400 except (OverflowError, SyntaxError, ValueError):
401 # Case 1
401 # Case 1
402 self.showsyntaxerror(filename)
402 self.showsyntaxerror(filename)
403 return False
403 return False
404
404
405 if code is None:
405 if code is None:
406 # Case 2
406 # Case 2
407 return True
407 return True
408
408
409 # shortcut - if we are in worker thread, or the worker thread is not
409 # shortcut - if we are in worker thread, or the worker thread is not
410 # running, execute directly (to allow recursion and prevent deadlock if
410 # running, execute directly (to allow recursion and prevent deadlock if
411 # code is run early in IPython construction)
411 # code is run early in IPython construction)
412
412
413 if (self.worker_ident is None
413 if (self.worker_ident is None
414 or self.worker_ident == thread.get_ident() ):
414 or self.worker_ident == thread.get_ident() ):
415 InteractiveShell.runcode(self,code)
415 InteractiveShell.runcode(self,code)
416 return False
416 return False
417
417
418 # Case 3
418 # Case 3
419 # Store code in queue, so the execution thread can handle it.
419 # Store code in queue, so the execution thread can handle it.
420
420
421 completed_ev, received_ev = threading.Event(), threading.Event()
421 completed_ev, received_ev = threading.Event(), threading.Event()
422
422
423 self.code_queue.put((code,completed_ev, received_ev))
423 self.code_queue.put((code,completed_ev, received_ev))
424 # first make sure the message was received, with timeout
424 # first make sure the message was received, with timeout
425 received_ev.wait(self.gui_timeout)
425 received_ev.wait(self.gui_timeout)
426 if not received_ev.isSet():
426 if not received_ev.isSet():
427 # the mainloop is dead, start executing code directly
427 # the mainloop is dead, start executing code directly
428 print "Warning: Timeout for mainloop thread exceeded"
428 print "Warning: Timeout for mainloop thread exceeded"
429 print "switching to nonthreaded mode (until mainloop wakes up again)"
429 print "switching to nonthreaded mode (until mainloop wakes up again)"
430 self.worker_ident = None
430 self.worker_ident = None
431 else:
431 else:
432 completed_ev.wait()
432 completed_ev.wait()
433 return False
433 return False
434
434
435 def runcode(self):
435 def runcode(self):
436 """Execute a code object.
436 """Execute a code object.
437
437
438 Multithreaded wrapper around IPython's runcode()."""
438 Multithreaded wrapper around IPython's runcode()."""
439
439
440 global CODE_RUN
440 global CODE_RUN
441
441
442 # we are in worker thread, stash out the id for runsource()
442 # we are in worker thread, stash out the id for runsource()
443 self.worker_ident = thread.get_ident()
443 self.worker_ident = thread.get_ident()
444
444
445 if self._kill:
445 if self._kill:
446 print >>Term.cout, 'Closing threads...',
446 print >>Term.cout, 'Closing threads...',
447 Term.cout.flush()
447 Term.cout.flush()
448 for tokill in self.on_kill:
448 for tokill in self.on_kill:
449 tokill()
449 tokill()
450 print >>Term.cout, 'Done.'
450 print >>Term.cout, 'Done.'
451 # allow kill() to return
451 # allow kill() to return
452 self._kill.set()
452 self._kill.set()
453 return True
453 return True
454
454
455 # Install sigint handler. We do it every time to ensure that if user
455 # Install sigint handler. We do it every time to ensure that if user
456 # code modifies it, we restore our own handling.
456 # code modifies it, we restore our own handling.
457 try:
457 try:
458 signal(SIGINT,sigint_handler)
458 signal(SIGINT,sigint_handler)
459 except SystemError:
459 except SystemError:
460 # This happens under Windows, which seems to have all sorts
460 # This happens under Windows, which seems to have all sorts
461 # of problems with signal handling. Oh well...
461 # of problems with signal handling. Oh well...
462 pass
462 pass
463
463
464 # Flush queue of pending code by calling the run methood of the parent
464 # Flush queue of pending code by calling the run methood of the parent
465 # class with all items which may be in the queue.
465 # class with all items which may be in the queue.
466 code_to_run = None
466 code_to_run = None
467 while 1:
467 while 1:
468 try:
468 try:
469 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
469 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
470 except Queue.Empty:
470 except Queue.Empty:
471 break
471 break
472 received_ev.set()
472 received_ev.set()
473
473
474 # Exceptions need to be raised differently depending on which
474 # Exceptions need to be raised differently depending on which
475 # thread is active. This convoluted try/except is only there to
475 # thread is active. This convoluted try/except is only there to
476 # protect against asynchronous exceptions, to ensure that a KBINT
476 # protect against asynchronous exceptions, to ensure that a KBINT
477 # at the wrong time doesn't deadlock everything. The global
477 # at the wrong time doesn't deadlock everything. The global
478 # CODE_TO_RUN is set to true/false as close as possible to the
478 # CODE_TO_RUN is set to true/false as close as possible to the
479 # runcode() call, so that the KBINT handler is correctly informed.
479 # runcode() call, so that the KBINT handler is correctly informed.
480 try:
480 try:
481 try:
481 try:
482 CODE_RUN = True
482 CODE_RUN = True
483 InteractiveShell.runcode(self,code_to_run)
483 InteractiveShell.runcode(self,code_to_run)
484 except KeyboardInterrupt:
484 except KeyboardInterrupt:
485 print "Keyboard interrupted in mainloop"
485 print "Keyboard interrupted in mainloop"
486 while not self.code_queue.empty():
486 while not self.code_queue.empty():
487 code, ev1,ev2 = self.code_queue.get_nowait()
487 code, ev1,ev2 = self.code_queue.get_nowait()
488 ev1.set()
488 ev1.set()
489 ev2.set()
489 ev2.set()
490 break
490 break
491 finally:
491 finally:
492 CODE_RUN = False
492 CODE_RUN = False
493 # allow runsource() return from wait
493 # allow runsource() return from wait
494 completed_ev.set()
494 completed_ev.set()
495
495
496
496
497 # This MUST return true for gtk threading to work
497 # This MUST return true for gtk threading to work
498 return True
498 return True
499
499
500 def kill(self):
500 def kill(self):
501 """Kill the thread, returning when it has been shut down."""
501 """Kill the thread, returning when it has been shut down."""
502 self._kill = threading.Event()
502 self._kill = threading.Event()
503 self._kill.wait()
503 self._kill.wait()
504
504
505 class MatplotlibShellBase:
505 class MatplotlibShellBase:
506 """Mixin class to provide the necessary modifications to regular IPython
506 """Mixin class to provide the necessary modifications to regular IPython
507 shell classes for matplotlib support.
507 shell classes for matplotlib support.
508
508
509 Given Python's MRO, this should be used as the FIRST class in the
509 Given Python's MRO, this should be used as the FIRST class in the
510 inheritance hierarchy, so that it overrides the relevant methods."""
510 inheritance hierarchy, so that it overrides the relevant methods."""
511
511
512 def _matplotlib_config(self,name,user_ns,user_global_ns=None):
512 def _matplotlib_config(self,name,user_ns,user_global_ns=None):
513 """Return items needed to setup the user's shell with matplotlib"""
513 """Return items needed to setup the user's shell with matplotlib"""
514
514
515 # Initialize matplotlib to interactive mode always
515 # Initialize matplotlib to interactive mode always
516 import matplotlib
516 import matplotlib
517 from matplotlib import backends
517 from matplotlib import backends
518 matplotlib.interactive(True)
518 matplotlib.interactive(True)
519
519
520 def use(arg):
520 def use(arg):
521 """IPython wrapper for matplotlib's backend switcher.
521 """IPython wrapper for matplotlib's backend switcher.
522
522
523 In interactive use, we can not allow switching to a different
523 In interactive use, we can not allow switching to a different
524 interactive backend, since thread conflicts will most likely crash
524 interactive backend, since thread conflicts will most likely crash
525 the python interpreter. This routine does a safety check first,
525 the python interpreter. This routine does a safety check first,
526 and refuses to perform a dangerous switch. It still allows
526 and refuses to perform a dangerous switch. It still allows
527 switching to non-interactive backends."""
527 switching to non-interactive backends."""
528
528
529 if arg in backends.interactive_bk and arg != self.mpl_backend:
529 if arg in backends.interactive_bk and arg != self.mpl_backend:
530 m=('invalid matplotlib backend switch.\n'
530 m=('invalid matplotlib backend switch.\n'
531 'This script attempted to switch to the interactive '
531 'This script attempted to switch to the interactive '
532 'backend: `%s`\n'
532 'backend: `%s`\n'
533 'Your current choice of interactive backend is: `%s`\n\n'
533 'Your current choice of interactive backend is: `%s`\n\n'
534 'Switching interactive matplotlib backends at runtime\n'
534 'Switching interactive matplotlib backends at runtime\n'
535 'would crash the python interpreter, '
535 'would crash the python interpreter, '
536 'and IPython has blocked it.\n\n'
536 'and IPython has blocked it.\n\n'
537 'You need to either change your choice of matplotlib backend\n'
537 'You need to either change your choice of matplotlib backend\n'
538 'by editing your .matplotlibrc file, or run this script as a \n'
538 'by editing your .matplotlibrc file, or run this script as a \n'
539 'standalone file from the command line, not using IPython.\n' %
539 'standalone file from the command line, not using IPython.\n' %
540 (arg,self.mpl_backend) )
540 (arg,self.mpl_backend) )
541 raise RuntimeError, m
541 raise RuntimeError, m
542 else:
542 else:
543 self.mpl_use(arg)
543 self.mpl_use(arg)
544 self.mpl_use._called = True
544 self.mpl_use._called = True
545
545
546 self.matplotlib = matplotlib
546 self.matplotlib = matplotlib
547 self.mpl_backend = matplotlib.rcParams['backend']
547 self.mpl_backend = matplotlib.rcParams['backend']
548
548
549 # we also need to block switching of interactive backends by use()
549 # we also need to block switching of interactive backends by use()
550 self.mpl_use = matplotlib.use
550 self.mpl_use = matplotlib.use
551 self.mpl_use._called = False
551 self.mpl_use._called = False
552 # overwrite the original matplotlib.use with our wrapper
552 # overwrite the original matplotlib.use with our wrapper
553 matplotlib.use = use
553 matplotlib.use = use
554
554
555 # This must be imported last in the matplotlib series, after
555 # This must be imported last in the matplotlib series, after
556 # backend/interactivity choices have been made
556 # backend/interactivity choices have been made
557 import matplotlib.pylab as pylab
557 import matplotlib.pylab as pylab
558 self.pylab = pylab
558 self.pylab = pylab
559
559
560 self.pylab.show._needmain = False
560 self.pylab.show._needmain = False
561 # We need to detect at runtime whether show() is called by the user.
561 # We need to detect at runtime whether show() is called by the user.
562 # For this, we wrap it into a decorator which adds a 'called' flag.
562 # For this, we wrap it into a decorator which adds a 'called' flag.
563 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
563 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
564
564
565 # Build a user namespace initialized with matplotlib/matlab features.
565 # Build a user namespace initialized with matplotlib/matlab features.
566 user_ns, user_global_ns = ipapi.make_user_namespaces(user_ns,
566 user_ns, user_global_ns = ipapi.make_user_namespaces(user_ns,
567 user_global_ns)
567 user_global_ns)
568
568
569 # Import numpy as np/pyplot as plt are conventions we're trying to
569 # Import numpy as np/pyplot as plt are conventions we're trying to
570 # somewhat standardize on. Making them available to users by default
570 # somewhat standardize on. Making them available to users by default
571 # will greatly help this.
571 # will greatly help this.
572 exec ("import numpy\n"
572 exec ("import numpy\n"
573 "import numpy as np\n"
573 "import numpy as np\n"
574 "import matplotlib\n"
574 "import matplotlib\n"
575 "import matplotlib.pylab as pylab\n"
575 "import matplotlib.pylab as pylab\n"
576 "try:\n"
576 "try:\n"
577 " import matplotlib.pyplot as plt\n"
577 " import matplotlib.pyplot as plt\n"
578 "except ImportError:\n"
578 "except ImportError:\n"
579 " pass\n"
579 " pass\n"
580 ) in user_ns
580 ) in user_ns
581
581
582 # Build matplotlib info banner
582 # Build matplotlib info banner
583 b="""
583 b="""
584 Welcome to pylab, a matplotlib-based Python environment.
584 Welcome to pylab, a matplotlib-based Python environment.
585 For more information, type 'help(pylab)'.
585 For more information, type 'help(pylab)'.
586 """
586 """
587 return user_ns,user_global_ns,b
587 return user_ns,user_global_ns,b
588
588
589 def mplot_exec(self,fname,*where,**kw):
589 def mplot_exec(self,fname,*where,**kw):
590 """Execute a matplotlib script.
590 """Execute a matplotlib script.
591
591
592 This is a call to execfile(), but wrapped in safeties to properly
592 This is a call to execfile(), but wrapped in safeties to properly
593 handle interactive rendering and backend switching."""
593 handle interactive rendering and backend switching."""
594
594
595 #print '*** Matplotlib runner ***' # dbg
595 #print '*** Matplotlib runner ***' # dbg
596 # turn off rendering until end of script
596 # turn off rendering until end of script
597 isInteractive = self.matplotlib.rcParams['interactive']
597 isInteractive = self.matplotlib.rcParams['interactive']
598 self.matplotlib.interactive(False)
598 self.matplotlib.interactive(False)
599 self.safe_execfile(fname,*where,**kw)
599 self.safe_execfile(fname,*where,**kw)
600 self.matplotlib.interactive(isInteractive)
600 self.matplotlib.interactive(isInteractive)
601 # make rendering call now, if the user tried to do it
601 # make rendering call now, if the user tried to do it
602 if self.pylab.draw_if_interactive.called:
602 if self.pylab.draw_if_interactive.called:
603 self.pylab.draw()
603 self.pylab.draw()
604 self.pylab.draw_if_interactive.called = False
604 self.pylab.draw_if_interactive.called = False
605
605
606 # if a backend switch was performed, reverse it now
606 # if a backend switch was performed, reverse it now
607 if self.mpl_use._called:
607 if self.mpl_use._called:
608 self.matplotlib.rcParams['backend'] = self.mpl_backend
608 self.matplotlib.rcParams['backend'] = self.mpl_backend
609
609
610 @testdec.skip_doctest
610 @testdec.skip_doctest
611 def magic_run(self,parameter_s=''):
611 def magic_run(self,parameter_s=''):
612 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
612 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
613
613
614 # Fix the docstring so users see the original as well
614 # Fix the docstring so users see the original as well
615 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
615 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
616 "\n *** Modified %run for Matplotlib,"
616 "\n *** Modified %run for Matplotlib,"
617 " with proper interactive handling ***")
617 " with proper interactive handling ***")
618
618
619 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
619 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
620 # and multithreaded. Note that these are meant for internal use, the IPShell*
620 # and multithreaded. Note that these are meant for internal use, the IPShell*
621 # classes below are the ones meant for public consumption.
621 # classes below are the ones meant for public consumption.
622
622
623 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
623 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
624 """Single-threaded shell with matplotlib support."""
624 """Single-threaded shell with matplotlib support."""
625
625
626 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
626 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
627 user_ns=None,user_global_ns=None,**kw):
627 user_ns=None,user_global_ns=None,**kw):
628 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
628 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
629 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
629 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
630 banner2=b2,**kw)
630 banner2=b2,**kw)
631
631
632 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
632 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
633 """Multi-threaded shell with matplotlib support."""
633 """Multi-threaded shell with matplotlib support."""
634
634
635 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
635 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
636 user_ns=None,user_global_ns=None, **kw):
636 user_ns=None,user_global_ns=None, **kw):
637 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
637 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
638 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
638 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
639 banner2=b2,**kw)
639 banner2=b2,**kw)
640
640
641 #-----------------------------------------------------------------------------
641 #-----------------------------------------------------------------------------
642 # Utility functions for the different GUI enabled IPShell* classes.
642 # Utility functions for the different GUI enabled IPShell* classes.
643
643
644 def get_tk():
644 def get_tk():
645 """Tries to import Tkinter and returns a withdrawn Tkinter root
645 """Tries to import Tkinter and returns a withdrawn Tkinter root
646 window. If Tkinter is already imported or not available, this
646 window. If Tkinter is already imported or not available, this
647 returns None. This function calls `hijack_tk` underneath.
647 returns None. This function calls `hijack_tk` underneath.
648 """
648 """
649 if not USE_TK or sys.modules.has_key('Tkinter'):
649 if not USE_TK or sys.modules.has_key('Tkinter'):
650 return None
650 return None
651 else:
651 else:
652 try:
652 try:
653 import Tkinter
653 import Tkinter
654 except ImportError:
654 except ImportError:
655 return None
655 return None
656 else:
656 else:
657 hijack_tk()
657 hijack_tk()
658 r = Tkinter.Tk()
658 r = Tkinter.Tk()
659 r.withdraw()
659 r.withdraw()
660 return r
660 return r
661
661
662 def hijack_tk():
662 def hijack_tk():
663 """Modifies Tkinter's mainloop with a dummy so when a module calls
663 """Modifies Tkinter's mainloop with a dummy so when a module calls
664 mainloop, it does not block.
664 mainloop, it does not block.
665
665
666 """
666 """
667 def misc_mainloop(self, n=0):
667 def misc_mainloop(self, n=0):
668 pass
668 pass
669 def tkinter_mainloop(n=0):
669 def tkinter_mainloop(n=0):
670 pass
670 pass
671
671
672 import Tkinter
672 import Tkinter
673 Tkinter.Misc.mainloop = misc_mainloop
673 Tkinter.Misc.mainloop = misc_mainloop
674 Tkinter.mainloop = tkinter_mainloop
674 Tkinter.mainloop = tkinter_mainloop
675
675
676 def update_tk(tk):
676 def update_tk(tk):
677 """Updates the Tkinter event loop. This is typically called from
677 """Updates the Tkinter event loop. This is typically called from
678 the respective WX or GTK mainloops.
678 the respective WX or GTK mainloops.
679 """
679 """
680 if tk:
680 if tk:
681 tk.update()
681 tk.update()
682
682
683 def hijack_wx():
683 def hijack_wx():
684 """Modifies wxPython's MainLoop with a dummy so user code does not
684 """Modifies wxPython's MainLoop with a dummy so user code does not
685 block IPython. The hijacked mainloop function is returned.
685 block IPython. The hijacked mainloop function is returned.
686 """
686 """
687 def dummy_mainloop(*args, **kw):
687 def dummy_mainloop(*args, **kw):
688 pass
688 pass
689
689
690 try:
690 try:
691 import wx
691 import wx
692 except ImportError:
692 except ImportError:
693 # For very old versions of WX
693 # For very old versions of WX
694 import wxPython as wx
694 import wxPython as wx
695
695
696 ver = wx.__version__
696 ver = wx.__version__
697 orig_mainloop = None
697 orig_mainloop = None
698 if ver[:3] >= '2.5':
698 if ver[:3] >= '2.5':
699 import wx
699 import wx
700 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
700 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
701 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
701 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
702 else: raise AttributeError('Could not find wx core module')
702 else: raise AttributeError('Could not find wx core module')
703 orig_mainloop = core.PyApp_MainLoop
703 orig_mainloop = core.PyApp_MainLoop
704 core.PyApp_MainLoop = dummy_mainloop
704 core.PyApp_MainLoop = dummy_mainloop
705 elif ver[:3] == '2.4':
705 elif ver[:3] == '2.4':
706 orig_mainloop = wx.wxc.wxPyApp_MainLoop
706 orig_mainloop = wx.wxc.wxPyApp_MainLoop
707 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
707 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
708 else:
708 else:
709 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
709 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
710 return orig_mainloop
710 return orig_mainloop
711
711
712 def hijack_gtk():
712 def hijack_gtk():
713 """Modifies pyGTK's mainloop with a dummy so user code does not
713 """Modifies pyGTK's mainloop with a dummy so user code does not
714 block IPython. This function returns the original `gtk.mainloop`
714 block IPython. This function returns the original `gtk.mainloop`
715 function that has been hijacked.
715 function that has been hijacked.
716 """
716 """
717 def dummy_mainloop(*args, **kw):
717 def dummy_mainloop(*args, **kw):
718 pass
718 pass
719 import gtk
719 import gtk
720 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
720 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
721 else: orig_mainloop = gtk.mainloop
721 else: orig_mainloop = gtk.mainloop
722 gtk.mainloop = dummy_mainloop
722 gtk.mainloop = dummy_mainloop
723 gtk.main = dummy_mainloop
723 gtk.main = dummy_mainloop
724 return orig_mainloop
724 return orig_mainloop
725
725
726 def hijack_qt():
726 def hijack_qt():
727 """Modifies PyQt's mainloop with a dummy so user code does not
727 """Modifies PyQt's mainloop with a dummy so user code does not
728 block IPython. This function returns the original
728 block IPython. This function returns the original
729 `qt.qApp.exec_loop` function that has been hijacked.
729 `qt.qApp.exec_loop` function that has been hijacked.
730 """
730 """
731 def dummy_mainloop(*args, **kw):
731 def dummy_mainloop(*args, **kw):
732 pass
732 pass
733 import qt
733 import qt
734 orig_mainloop = qt.qApp.exec_loop
734 orig_mainloop = qt.qApp.exec_loop
735 qt.qApp.exec_loop = dummy_mainloop
735 qt.qApp.exec_loop = dummy_mainloop
736 qt.QApplication.exec_loop = dummy_mainloop
736 qt.QApplication.exec_loop = dummy_mainloop
737 return orig_mainloop
737 return orig_mainloop
738
738
739 def hijack_qt4():
739 def hijack_qt4():
740 """Modifies PyQt4's mainloop with a dummy so user code does not
740 """Modifies PyQt4's mainloop with a dummy so user code does not
741 block IPython. This function returns the original
741 block IPython. This function returns the original
742 `QtGui.qApp.exec_` function that has been hijacked.
742 `QtGui.qApp.exec_` function that has been hijacked.
743 """
743 """
744 def dummy_mainloop(*args, **kw):
744 def dummy_mainloop(*args, **kw):
745 pass
745 pass
746 from PyQt4 import QtGui, QtCore
746 from PyQt4 import QtGui, QtCore
747 orig_mainloop = QtGui.qApp.exec_
747 orig_mainloop = QtGui.qApp.exec_
748 QtGui.qApp.exec_ = dummy_mainloop
748 QtGui.qApp.exec_ = dummy_mainloop
749 QtGui.QApplication.exec_ = dummy_mainloop
749 QtGui.QApplication.exec_ = dummy_mainloop
750 QtCore.QCoreApplication.exec_ = dummy_mainloop
750 QtCore.QCoreApplication.exec_ = dummy_mainloop
751 return orig_mainloop
751 return orig_mainloop
752
752
753 #-----------------------------------------------------------------------------
753 #-----------------------------------------------------------------------------
754 # The IPShell* classes below are the ones meant to be run by external code as
754 # The IPShell* classes below are the ones meant to be run by external code as
755 # IPython instances. Note that unless a specific threading strategy is
755 # IPython instances. Note that unless a specific threading strategy is
756 # desired, the factory function start() below should be used instead (it
756 # desired, the factory function start() below should be used instead (it
757 # selects the proper threaded class).
757 # selects the proper threaded class).
758
758
759 class IPThread(threading.Thread):
759 class IPThread(threading.Thread):
760 def run(self):
760 def run(self):
761 self.IP.mainloop(self._banner)
761 self.IP.mainloop(self._banner)
762 self.IP.kill()
762 self.IP.kill()
763
763
764 class IPShellGTK(IPThread):
764 class IPShellGTK(IPThread):
765 """Run a gtk mainloop() in a separate thread.
765 """Run a gtk mainloop() in a separate thread.
766
766
767 Python commands can be passed to the thread where they will be executed.
767 Python commands can be passed to the thread where they will be executed.
768 This is implemented by periodically checking for passed code using a
768 This is implemented by periodically checking for passed code using a
769 GTK timeout callback."""
769 GTK timeout callback."""
770
770
771 TIMEOUT = 100 # Millisecond interval between timeouts.
771 TIMEOUT = 100 # Millisecond interval between timeouts.
772
772
773 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
773 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
774 debug=1,shell_class=MTInteractiveShell):
774 debug=1,shell_class=MTInteractiveShell):
775
775
776 import gtk
776 import gtk
777 # Check for set_interactive, coming up in new pygtk.
777 # Check for set_interactive, coming up in new pygtk.
778 # Disable it so that this code works, but notify
778 # Disable it so that this code works, but notify
779 # the user that he has a better option as well.
779 # the user that he has a better option as well.
780 # XXX TODO better support when set_interactive is released
780 # XXX TODO better support when set_interactive is released
781 try:
781 try:
782 gtk.set_interactive(False)
782 gtk.set_interactive(False)
783 print "Your PyGtk has set_interactive(), so you can use the"
783 print "Your PyGtk has set_interactive(), so you can use the"
784 print "more stable single-threaded Gtk mode."
784 print "more stable single-threaded Gtk mode."
785 print "See https://bugs.launchpad.net/ipython/+bug/270856"
785 print "See https://bugs.launchpad.net/ipython/+bug/270856"
786 except AttributeError:
786 except AttributeError:
787 pass
787 pass
788
788
789 self.gtk = gtk
789 self.gtk = gtk
790 self.gtk_mainloop = hijack_gtk()
790 self.gtk_mainloop = hijack_gtk()
791
791
792 # Allows us to use both Tk and GTK.
792 # Allows us to use both Tk and GTK.
793 self.tk = get_tk()
793 self.tk = get_tk()
794
794
795 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
795 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
796 else: mainquit = self.gtk.mainquit
796 else: mainquit = self.gtk.mainquit
797
797
798 self.IP = make_IPython(argv,user_ns=user_ns,
798 self.IP = make_IPython(argv,user_ns=user_ns,
799 user_global_ns=user_global_ns,
799 user_global_ns=user_global_ns,
800 debug=debug,
800 debug=debug,
801 shell_class=shell_class,
801 shell_class=shell_class,
802 on_kill=[mainquit])
802 on_kill=[mainquit])
803
803
804 # HACK: slot for banner in self; it will be passed to the mainloop
804 # HACK: slot for banner in self; it will be passed to the mainloop
805 # method only and .run() needs it. The actual value will be set by
805 # method only and .run() needs it. The actual value will be set by
806 # .mainloop().
806 # .mainloop().
807 self._banner = None
807 self._banner = None
808
808
809 threading.Thread.__init__(self)
809 threading.Thread.__init__(self)
810
810
811 def mainloop(self,sys_exit=0,banner=None):
811 def mainloop(self,sys_exit=0,banner=None):
812
812
813 self._banner = banner
813 self._banner = banner
814
814
815 if self.gtk.pygtk_version >= (2,4,0):
815 if self.gtk.pygtk_version >= (2,4,0):
816 import gobject
816 import gobject
817 gobject.idle_add(self.on_timer)
817 gobject.idle_add(self.on_timer)
818 else:
818 else:
819 self.gtk.idle_add(self.on_timer)
819 self.gtk.idle_add(self.on_timer)
820
820
821 if sys.platform != 'win32':
821 if sys.platform != 'win32':
822 try:
822 try:
823 if self.gtk.gtk_version[0] >= 2:
823 if self.gtk.gtk_version[0] >= 2:
824 self.gtk.gdk.threads_init()
824 self.gtk.gdk.threads_init()
825 except AttributeError:
825 except AttributeError:
826 pass
826 pass
827 except RuntimeError:
827 except RuntimeError:
828 error('Your pyGTK likely has not been compiled with '
828 error('Your pyGTK likely has not been compiled with '
829 'threading support.\n'
829 'threading support.\n'
830 'The exception printout is below.\n'
830 'The exception printout is below.\n'
831 'You can either rebuild pyGTK with threads, or '
831 'You can either rebuild pyGTK with threads, or '
832 'try using \n'
832 'try using \n'
833 'matplotlib with a different backend (like Tk or WX).\n'
833 'matplotlib with a different backend (like Tk or WX).\n'
834 'Note that matplotlib will most likely not work in its '
834 'Note that matplotlib will most likely not work in its '
835 'current state!')
835 'current state!')
836 self.IP.InteractiveTB()
836 self.IP.InteractiveTB()
837
837
838 self.start()
838 self.start()
839 self.gtk.gdk.threads_enter()
839 self.gtk.gdk.threads_enter()
840 self.gtk_mainloop()
840 self.gtk_mainloop()
841 self.gtk.gdk.threads_leave()
841 self.gtk.gdk.threads_leave()
842 self.join()
842 self.join()
843
843
844 def on_timer(self):
844 def on_timer(self):
845 """Called when GTK is idle.
845 """Called when GTK is idle.
846
846
847 Must return True always, otherwise GTK stops calling it"""
847 Must return True always, otherwise GTK stops calling it"""
848
848
849 update_tk(self.tk)
849 update_tk(self.tk)
850 self.IP.runcode()
850 self.IP.runcode()
851 time.sleep(0.01)
851 time.sleep(0.01)
852 return True
852 return True
853
853
854
854
855 class IPShellWX(IPThread):
855 class IPShellWX(IPThread):
856 """Run a wx mainloop() in a separate thread.
856 """Run a wx mainloop() in a separate thread.
857
857
858 Python commands can be passed to the thread where they will be executed.
858 Python commands can be passed to the thread where they will be executed.
859 This is implemented by periodically checking for passed code using a
859 This is implemented by periodically checking for passed code using a
860 GTK timeout callback."""
860 GTK timeout callback."""
861
861
862 TIMEOUT = 100 # Millisecond interval between timeouts.
862 TIMEOUT = 100 # Millisecond interval between timeouts.
863
863
864 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
864 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
865 debug=1,shell_class=MTInteractiveShell):
865 debug=1,shell_class=MTInteractiveShell):
866
866
867 self.IP = make_IPython(argv,user_ns=user_ns,
867 self.IP = make_IPython(argv,user_ns=user_ns,
868 user_global_ns=user_global_ns,
868 user_global_ns=user_global_ns,
869 debug=debug,
869 debug=debug,
870 shell_class=shell_class,
870 shell_class=shell_class,
871 on_kill=[self.wxexit])
871 on_kill=[self.wxexit])
872
872
873 wantedwxversion=self.IP.rc.wxversion
873 wantedwxversion=self.IP.rc.wxversion
874 if wantedwxversion!="0":
874 if wantedwxversion!="0":
875 try:
875 try:
876 import wxversion
876 import wxversion
877 except ImportError:
877 except ImportError:
878 error('The wxversion module is needed for WX version selection')
878 error('The wxversion module is needed for WX version selection')
879 else:
879 else:
880 try:
880 try:
881 wxversion.select(wantedwxversion)
881 wxversion.select(wantedwxversion)
882 except:
882 except:
883 self.IP.InteractiveTB()
883 self.IP.InteractiveTB()
884 error('Requested wxPython version %s could not be loaded' %
884 error('Requested wxPython version %s could not be loaded' %
885 wantedwxversion)
885 wantedwxversion)
886
886
887 import wx
887 import wx
888
888
889 threading.Thread.__init__(self)
889 threading.Thread.__init__(self)
890 self.wx = wx
890 self.wx = wx
891 self.wx_mainloop = hijack_wx()
891 self.wx_mainloop = hijack_wx()
892
892
893 # Allows us to use both Tk and GTK.
893 # Allows us to use both Tk and GTK.
894 self.tk = get_tk()
894 self.tk = get_tk()
895
895
896 # HACK: slot for banner in self; it will be passed to the mainloop
896 # HACK: slot for banner in self; it will be passed to the mainloop
897 # method only and .run() needs it. The actual value will be set by
897 # method only and .run() needs it. The actual value will be set by
898 # .mainloop().
898 # .mainloop().
899 self._banner = None
899 self._banner = None
900
900
901 self.app = None
901 self.app = None
902
902
903 def wxexit(self, *args):
903 def wxexit(self, *args):
904 if self.app is not None:
904 if self.app is not None:
905 self.app.agent.timer.Stop()
905 self.app.agent.timer.Stop()
906 self.app.ExitMainLoop()
906 self.app.ExitMainLoop()
907
907
908 def mainloop(self,sys_exit=0,banner=None):
908 def mainloop(self,sys_exit=0,banner=None):
909
909
910 self._banner = banner
910 self._banner = banner
911
911
912 self.start()
912 self.start()
913
913
914 class TimerAgent(self.wx.MiniFrame):
914 class TimerAgent(self.wx.MiniFrame):
915 wx = self.wx
915 wx = self.wx
916 IP = self.IP
916 IP = self.IP
917 tk = self.tk
917 tk = self.tk
918 def __init__(self, parent, interval):
918 def __init__(self, parent, interval):
919 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
919 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
920 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
920 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
921 size=(100, 100),style=style)
921 size=(100, 100),style=style)
922 self.Show(False)
922 self.Show(False)
923 self.interval = interval
923 self.interval = interval
924 self.timerId = self.wx.NewId()
924 self.timerId = self.wx.NewId()
925
925
926 def StartWork(self):
926 def StartWork(self):
927 self.timer = self.wx.Timer(self, self.timerId)
927 self.timer = self.wx.Timer(self, self.timerId)
928 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
928 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
929 self.timer.Start(self.interval)
929 self.timer.Start(self.interval)
930
930
931 def OnTimer(self, event):
931 def OnTimer(self, event):
932 update_tk(self.tk)
932 update_tk(self.tk)
933 self.IP.runcode()
933 self.IP.runcode()
934
934
935 class App(self.wx.App):
935 class App(self.wx.App):
936 wx = self.wx
936 wx = self.wx
937 TIMEOUT = self.TIMEOUT
937 TIMEOUT = self.TIMEOUT
938 def OnInit(self):
938 def OnInit(self):
939 'Create the main window and insert the custom frame'
939 'Create the main window and insert the custom frame'
940 self.agent = TimerAgent(None, self.TIMEOUT)
940 self.agent = TimerAgent(None, self.TIMEOUT)
941 self.agent.Show(False)
941 self.agent.Show(False)
942 self.agent.StartWork()
942 self.agent.StartWork()
943 return True
943 return True
944
944
945 self.app = App(redirect=False)
945 self.app = App(redirect=False)
946 self.wx_mainloop(self.app)
946 self.wx_mainloop(self.app)
947 self.join()
947 self.join()
948
948
949
949
950 class IPShellQt(IPThread):
950 class IPShellQt(IPThread):
951 """Run a Qt event loop in a separate thread.
951 """Run a Qt event loop in a separate thread.
952
952
953 Python commands can be passed to the thread where they will be executed.
953 Python commands can be passed to the thread where they will be executed.
954 This is implemented by periodically checking for passed code using a
954 This is implemented by periodically checking for passed code using a
955 Qt timer / slot."""
955 Qt timer / slot."""
956
956
957 TIMEOUT = 100 # Millisecond interval between timeouts.
957 TIMEOUT = 100 # Millisecond interval between timeouts.
958
958
959 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
959 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
960 debug=0, shell_class=MTInteractiveShell):
960 debug=0, shell_class=MTInteractiveShell):
961
961
962 import qt
962 import qt
963
963
964 self.exec_loop = hijack_qt()
964 self.exec_loop = hijack_qt()
965
965
966 # Allows us to use both Tk and QT.
966 # Allows us to use both Tk and QT.
967 self.tk = get_tk()
967 self.tk = get_tk()
968
968
969 self.IP = make_IPython(argv,
969 self.IP = make_IPython(argv,
970 user_ns=user_ns,
970 user_ns=user_ns,
971 user_global_ns=user_global_ns,
971 user_global_ns=user_global_ns,
972 debug=debug,
972 debug=debug,
973 shell_class=shell_class,
973 shell_class=shell_class,
974 on_kill=[qt.qApp.exit])
974 on_kill=[qt.qApp.exit])
975
975
976 # HACK: slot for banner in self; it will be passed to the mainloop
976 # HACK: slot for banner in self; it will be passed to the mainloop
977 # method only and .run() needs it. The actual value will be set by
977 # method only and .run() needs it. The actual value will be set by
978 # .mainloop().
978 # .mainloop().
979 self._banner = None
979 self._banner = None
980
980
981 threading.Thread.__init__(self)
981 threading.Thread.__init__(self)
982
982
983 def mainloop(self, sys_exit=0, banner=None):
983 def mainloop(self, sys_exit=0, banner=None):
984
984
985 import qt
985 import qt
986
986
987 self._banner = banner
987 self._banner = banner
988
988
989 if qt.QApplication.startingUp():
989 if qt.QApplication.startingUp():
990 a = qt.QApplication(sys.argv)
990 a = qt.QApplication(sys.argv)
991
991
992 self.timer = qt.QTimer()
992 self.timer = qt.QTimer()
993 qt.QObject.connect(self.timer,
993 qt.QObject.connect(self.timer,
994 qt.SIGNAL('timeout()'),
994 qt.SIGNAL('timeout()'),
995 self.on_timer)
995 self.on_timer)
996
996
997 self.start()
997 self.start()
998 self.timer.start(self.TIMEOUT, True)
998 self.timer.start(self.TIMEOUT, True)
999 while True:
999 while True:
1000 if self.IP._kill: break
1000 if self.IP._kill: break
1001 self.exec_loop()
1001 self.exec_loop()
1002 self.join()
1002 self.join()
1003
1003
1004 def on_timer(self):
1004 def on_timer(self):
1005 update_tk(self.tk)
1005 update_tk(self.tk)
1006 result = self.IP.runcode()
1006 result = self.IP.runcode()
1007 self.timer.start(self.TIMEOUT, True)
1007 self.timer.start(self.TIMEOUT, True)
1008 return result
1008 return result
1009
1009
1010
1010
1011 class IPShellQt4(IPThread):
1011 class IPShellQt4(IPThread):
1012 """Run a Qt event loop in a separate thread.
1012 """Run a Qt event loop in a separate thread.
1013
1013
1014 Python commands can be passed to the thread where they will be executed.
1014 Python commands can be passed to the thread where they will be executed.
1015 This is implemented by periodically checking for passed code using a
1015 This is implemented by periodically checking for passed code using a
1016 Qt timer / slot."""
1016 Qt timer / slot."""
1017
1017
1018 TIMEOUT = 100 # Millisecond interval between timeouts.
1018 TIMEOUT = 100 # Millisecond interval between timeouts.
1019
1019
1020 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
1020 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
1021 debug=0, shell_class=MTInteractiveShell):
1021 debug=0, shell_class=MTInteractiveShell):
1022
1022
1023 from PyQt4 import QtCore, QtGui
1023 from PyQt4 import QtCore, QtGui
1024
1024
1025 try:
1025 try:
1026 # present in PyQt4-4.2.1 or later
1026 # present in PyQt4-4.2.1 or later
1027 QtCore.pyqtRemoveInputHook()
1027 QtCore.pyqtRemoveInputHook()
1028 except AttributeError:
1028 except AttributeError:
1029 pass
1029 pass
1030
1030
1031 if QtCore.PYQT_VERSION_STR == '4.3':
1031 if QtCore.PYQT_VERSION_STR == '4.3':
1032 warn('''PyQt4 version 4.3 detected.
1032 warn('''PyQt4 version 4.3 detected.
1033 If you experience repeated threading warnings, please update PyQt4.
1033 If you experience repeated threading warnings, please update PyQt4.
1034 ''')
1034 ''')
1035
1035
1036 self.exec_ = hijack_qt4()
1036 self.exec_ = hijack_qt4()
1037
1037
1038 # Allows us to use both Tk and QT.
1038 # Allows us to use both Tk and QT.
1039 self.tk = get_tk()
1039 self.tk = get_tk()
1040
1040
1041 self.IP = make_IPython(argv,
1041 self.IP = make_IPython(argv,
1042 user_ns=user_ns,
1042 user_ns=user_ns,
1043 user_global_ns=user_global_ns,
1043 user_global_ns=user_global_ns,
1044 debug=debug,
1044 debug=debug,
1045 shell_class=shell_class,
1045 shell_class=shell_class,
1046 on_kill=[QtGui.qApp.exit])
1046 on_kill=[QtGui.qApp.exit])
1047
1047
1048 # HACK: slot for banner in self; it will be passed to the mainloop
1048 # HACK: slot for banner in self; it will be passed to the mainloop
1049 # method only and .run() needs it. The actual value will be set by
1049 # method only and .run() needs it. The actual value will be set by
1050 # .mainloop().
1050 # .mainloop().
1051 self._banner = None
1051 self._banner = None
1052
1052
1053 threading.Thread.__init__(self)
1053 threading.Thread.__init__(self)
1054
1054
1055 def mainloop(self, sys_exit=0, banner=None):
1055 def mainloop(self, sys_exit=0, banner=None):
1056
1056
1057 from PyQt4 import QtCore, QtGui
1057 from PyQt4 import QtCore, QtGui
1058
1058
1059 self._banner = banner
1059 self._banner = banner
1060
1060
1061 if QtGui.QApplication.startingUp():
1061 if QtGui.QApplication.startingUp():
1062 a = QtGui.QApplication(sys.argv)
1062 a = QtGui.QApplication(sys.argv)
1063
1063
1064 self.timer = QtCore.QTimer()
1064 self.timer = QtCore.QTimer()
1065 QtCore.QObject.connect(self.timer,
1065 QtCore.QObject.connect(self.timer,
1066 QtCore.SIGNAL('timeout()'),
1066 QtCore.SIGNAL('timeout()'),
1067 self.on_timer)
1067 self.on_timer)
1068
1068
1069 self.start()
1069 self.start()
1070 self.timer.start(self.TIMEOUT)
1070 self.timer.start(self.TIMEOUT)
1071 while True:
1071 while True:
1072 if self.IP._kill: break
1072 if self.IP._kill: break
1073 self.exec_()
1073 self.exec_()
1074 self.join()
1074 self.join()
1075
1075
1076 def on_timer(self):
1076 def on_timer(self):
1077 update_tk(self.tk)
1077 update_tk(self.tk)
1078 result = self.IP.runcode()
1078 result = self.IP.runcode()
1079 self.timer.start(self.TIMEOUT)
1079 self.timer.start(self.TIMEOUT)
1080 return result
1080 return result
1081
1081
1082
1082
1083 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1083 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1084 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1084 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1085 def _load_pylab(user_ns):
1085 def _load_pylab(user_ns):
1086 """Allow users to disable pulling all of pylab into the top-level
1086 """Allow users to disable pulling all of pylab into the top-level
1087 namespace.
1087 namespace.
1088
1088
1089 This little utility must be called AFTER the actual ipython instance is
1089 This little utility must be called AFTER the actual ipython instance is
1090 running, since only then will the options file have been fully parsed."""
1090 running, since only then will the options file have been fully parsed."""
1091
1091
1092 ip = ipapi.get()
1092 ip = ipapi.get()
1093 if ip.options.pylab_import_all:
1093 if ip.options.pylab_import_all:
1094 ip.ex("from matplotlib.pylab import *")
1094 ip.ex("from matplotlib.pylab import *")
1095 ip.IP.user_config_ns.update(ip.user_ns)
1095 ip.IP.user_config_ns.update(ip.user_ns)
1096
1096
1097
1097
1098 class IPShellMatplotlib(IPShell):
1098 class IPShellMatplotlib(IPShell):
1099 """Subclass IPShell with MatplotlibShell as the internal shell.
1099 """Subclass IPShell with MatplotlibShell as the internal shell.
1100
1100
1101 Single-threaded class, meant for the Tk* and FLTK* backends.
1101 Single-threaded class, meant for the Tk* and FLTK* backends.
1102
1102
1103 Having this on a separate class simplifies the external driver code."""
1103 Having this on a separate class simplifies the external driver code."""
1104
1104
1105 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1105 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1106 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1106 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1107 shell_class=MatplotlibShell)
1107 shell_class=MatplotlibShell)
1108 _load_pylab(self.IP.user_ns)
1108 _load_pylab(self.IP.user_ns)
1109
1109
1110 class IPShellMatplotlibGTK(IPShellGTK):
1110 class IPShellMatplotlibGTK(IPShellGTK):
1111 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1111 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1112
1112
1113 Multi-threaded class, meant for the GTK* backends."""
1113 Multi-threaded class, meant for the GTK* backends."""
1114
1114
1115 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1115 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1116 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1116 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1117 shell_class=MatplotlibMTShell)
1117 shell_class=MatplotlibMTShell)
1118 _load_pylab(self.IP.user_ns)
1118 _load_pylab(self.IP.user_ns)
1119
1119
1120 class IPShellMatplotlibWX(IPShellWX):
1120 class IPShellMatplotlibWX(IPShellWX):
1121 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1121 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1122
1122
1123 Multi-threaded class, meant for the WX* backends."""
1123 Multi-threaded class, meant for the WX* backends."""
1124
1124
1125 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1125 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1126 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1126 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1127 shell_class=MatplotlibMTShell)
1127 shell_class=MatplotlibMTShell)
1128 _load_pylab(self.IP.user_ns)
1128 _load_pylab(self.IP.user_ns)
1129
1129
1130 class IPShellMatplotlibQt(IPShellQt):
1130 class IPShellMatplotlibQt(IPShellQt):
1131 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1131 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1132
1132
1133 Multi-threaded class, meant for the Qt* backends."""
1133 Multi-threaded class, meant for the Qt* backends."""
1134
1134
1135 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1135 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1136 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1136 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1137 shell_class=MatplotlibMTShell)
1137 shell_class=MatplotlibMTShell)
1138 _load_pylab(self.IP.user_ns)
1138 _load_pylab(self.IP.user_ns)
1139
1139
1140 class IPShellMatplotlibQt4(IPShellQt4):
1140 class IPShellMatplotlibQt4(IPShellQt4):
1141 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1141 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1142
1142
1143 Multi-threaded class, meant for the Qt4* backends."""
1143 Multi-threaded class, meant for the Qt4* backends."""
1144
1144
1145 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1145 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1146 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1146 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1147 shell_class=MatplotlibMTShell)
1147 shell_class=MatplotlibMTShell)
1148 _load_pylab(self.IP.user_ns)
1148 _load_pylab(self.IP.user_ns)
1149
1149
1150 #-----------------------------------------------------------------------------
1150 #-----------------------------------------------------------------------------
1151 # Factory functions to actually start the proper thread-aware shell
1151 # Factory functions to actually start the proper thread-aware shell
1152
1152
1153 def _select_shell(argv):
1153 def _select_shell(argv):
1154 """Select a shell from the given argv vector.
1154 """Select a shell from the given argv vector.
1155
1155
1156 This function implements the threading selection policy, allowing runtime
1156 This function implements the threading selection policy, allowing runtime
1157 control of the threading mode, both for general users and for matplotlib.
1157 control of the threading mode, both for general users and for matplotlib.
1158
1158
1159 Return:
1159 Return:
1160 Shell class to be instantiated for runtime operation.
1160 Shell class to be instantiated for runtime operation.
1161 """
1161 """
1162
1162
1163 global USE_TK
1163 global USE_TK
1164
1164
1165 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1165 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1166 'wthread' : IPShellMatplotlibWX,
1166 'wthread' : IPShellMatplotlibWX,
1167 'qthread' : IPShellMatplotlibQt,
1167 'qthread' : IPShellMatplotlibQt,
1168 'q4thread' : IPShellMatplotlibQt4,
1168 'q4thread' : IPShellMatplotlibQt4,
1169 'tkthread' : IPShellMatplotlib, # Tk is built-in
1169 'tkthread' : IPShellMatplotlib, # Tk is built-in
1170 }
1170 }
1171
1171
1172 th_shell = {'gthread' : IPShellGTK,
1172 th_shell = {'gthread' : IPShellGTK,
1173 'wthread' : IPShellWX,
1173 'wthread' : IPShellWX,
1174 'qthread' : IPShellQt,
1174 'qthread' : IPShellQt,
1175 'q4thread' : IPShellQt4,
1175 'q4thread' : IPShellQt4,
1176 'tkthread' : IPShell, # Tk is built-in
1176 'tkthread' : IPShell, # Tk is built-in
1177 }
1177 }
1178
1178
1179 backends = {'gthread' : 'GTKAgg',
1179 backends = {'gthread' : 'GTKAgg',
1180 'wthread' : 'WXAgg',
1180 'wthread' : 'WXAgg',
1181 'qthread' : 'QtAgg',
1181 'qthread' : 'QtAgg',
1182 'q4thread' :'Qt4Agg',
1182 'q4thread' :'Qt4Agg',
1183 'tkthread' :'TkAgg',
1183 'tkthread' :'TkAgg',
1184 }
1184 }
1185
1185
1186 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1186 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1187 'tkthread'])
1187 'tkthread'])
1188 user_opts = set([s.replace('-','') for s in argv[:3]])
1188 user_opts = set([s.replace('-','') for s in argv[:3]])
1189 special_opts = user_opts & all_opts
1189 special_opts = user_opts & all_opts
1190
1190
1191 if 'tk' in special_opts:
1191 if 'tk' in special_opts:
1192 USE_TK = True
1192 USE_TK = True
1193 special_opts.remove('tk')
1193 special_opts.remove('tk')
1194
1194
1195 if 'pylab' in special_opts:
1195 if 'pylab' in special_opts:
1196
1196
1197 try:
1197 try:
1198 import matplotlib
1198 import matplotlib
1199 except ImportError:
1199 except ImportError:
1200 error('matplotlib could NOT be imported! Starting normal IPython.')
1200 error('matplotlib could NOT be imported! Starting normal IPython.')
1201 return IPShell
1201 return IPShell
1202
1202
1203 special_opts.remove('pylab')
1203 special_opts.remove('pylab')
1204 # If there's any option left, it means the user wants to force the
1204 # If there's any option left, it means the user wants to force the
1205 # threading backend, else it's auto-selected from the rc file
1205 # threading backend, else it's auto-selected from the rc file
1206 if special_opts:
1206 if special_opts:
1207 th_mode = special_opts.pop()
1207 th_mode = special_opts.pop()
1208 matplotlib.rcParams['backend'] = backends[th_mode]
1208 matplotlib.rcParams['backend'] = backends[th_mode]
1209 else:
1209 else:
1210 backend = matplotlib.rcParams['backend']
1210 backend = matplotlib.rcParams['backend']
1211 if backend.startswith('GTK'):
1211 if backend.startswith('GTK'):
1212 th_mode = 'gthread'
1212 th_mode = 'gthread'
1213 elif backend.startswith('WX'):
1213 elif backend.startswith('WX'):
1214 th_mode = 'wthread'
1214 th_mode = 'wthread'
1215 elif backend.startswith('Qt4'):
1215 elif backend.startswith('Qt4'):
1216 th_mode = 'q4thread'
1216 th_mode = 'q4thread'
1217 elif backend.startswith('Qt'):
1217 elif backend.startswith('Qt'):
1218 th_mode = 'qthread'
1218 th_mode = 'qthread'
1219 else:
1219 else:
1220 # Any other backend, use plain Tk
1220 # Any other backend, use plain Tk
1221 th_mode = 'tkthread'
1221 th_mode = 'tkthread'
1222
1222
1223 return mpl_shell[th_mode]
1223 return mpl_shell[th_mode]
1224 else:
1224 else:
1225 # No pylab requested, just plain threads
1225 # No pylab requested, just plain threads
1226 try:
1226 try:
1227 th_mode = special_opts.pop()
1227 th_mode = special_opts.pop()
1228 except KeyError:
1228 except KeyError:
1229 th_mode = 'tkthread'
1229 th_mode = 'tkthread'
1230 return th_shell[th_mode]
1230 return th_shell[th_mode]
1231
1231
1232
1232
1233 # This is the one which should be called by external code.
1233 # This is the one which should be called by external code.
1234 def start(user_ns = None):
1234 def start(user_ns = None):
1235 """Return a running shell instance, dealing with threading options.
1235 """Return a running shell instance, dealing with threading options.
1236
1236
1237 This is a factory function which will instantiate the proper IPython shell
1237 This is a factory function which will instantiate the proper IPython shell
1238 based on the user's threading choice. Such a selector is needed because
1238 based on the user's threading choice. Such a selector is needed because
1239 different GUI toolkits require different thread handling details."""
1239 different GUI toolkits require different thread handling details."""
1240
1240
1241 shell = _select_shell(sys.argv)
1241 shell = _select_shell(sys.argv)
1242 return shell(user_ns = user_ns)
1242 return shell(user_ns = user_ns)
1243
1243
1244 # Some aliases for backwards compatibility
1244 # Some aliases for backwards compatibility
1245 IPythonShell = IPShell
1245 IPythonShell = IPShell
1246 IPythonShellEmbed = IPShellEmbed
1246 IPythonShellEmbed = IPShellEmbed
1247 #************************ End of file <Shell.py> ***************************
1247 #************************ End of file <Shell.py> ***************************
1 NO CONTENT: file renamed from IPython/ipmaker.py to IPython/core/ipmaker.py
NO CONTENT: file renamed from IPython/ipmaker.py to IPython/core/ipmaker.py
@@ -1,33 +1,35 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3
3
4 def test_import_completer():
4 def test_import_completer():
5 from IPython.core import completer
5 from IPython.core import completer
6
6
7 def test_import_crashhandler():
7 def test_import_crashhandler():
8 from IPython.core import crashhandler
8 from IPython.core import crashhandler
9
9
10 def test_import_debugger():
10 def test_import_debugger():
11 from IPython.core import debugger
11 from IPython.core import debugger
12
12
13 def test_import_fakemodule():
13 def test_import_fakemodule():
14 from IPython.core import fakemodule
14 from IPython.core import fakemodule
15
15
16 def test_import_excolors():
16 def test_import_excolors():
17 from IPython.core import excolors
17 from IPython.core import excolors
18
18
19 def test_import_history():
19 def test_import_history():
20 from IPython.core import history
20 from IPython.core import history
21
21
22 def test_import_hooks():
22 def test_import_hooks():
23 from IPython.core import hooks
23 from IPython.core import hooks
24
24
25 def test_import_ipapi():
25 def test_import_ipapi():
26 from IPython.core import ipapi
26 from IPython.core import ipapi
27
27
28 def test_imort_iplib():
28 def test_imort_iplib():
29 from IPython.core import iplib
29 from IPython.core import iplib
30
30
31 def test_imort_ipmaker():
32 from IPython.core import ipmaker
31
33
32
34
33
35
@@ -1,282 +1,282 b''
1 """Twisted shell support.
1 """Twisted shell support.
2
2
3 XXX - This module is missing proper docs.
3 XXX - This module is missing proper docs.
4 """
4 """
5 import sys
5 import sys
6
6
7 from twisted.internet import reactor, threads
7 from twisted.internet import reactor, threads
8
8
9 from IPython.ipmaker import make_IPython
9 from IPython.core.ipmaker import make_IPython
10 from IPython.core.iplib import InteractiveShell
10 from IPython.core.iplib import InteractiveShell
11 from IPython.ipstruct import Struct
11 from IPython.ipstruct import Struct
12 import Queue,thread,threading,signal
12 import Queue,thread,threading,signal
13 from signal import signal, SIGINT
13 from signal import signal, SIGINT
14 from IPython.utils.genutils import Term,warn,error,flag_calls, ask_yes_no
14 from IPython.utils.genutils import Term,warn,error,flag_calls, ask_yes_no
15 import shellglobals
15 import shellglobals
16
16
17 def install_gtk2():
17 def install_gtk2():
18 """ Install gtk2 reactor, needs to be called bef """
18 """ Install gtk2 reactor, needs to be called bef """
19 from twisted.internet import gtk2reactor
19 from twisted.internet import gtk2reactor
20 gtk2reactor.install()
20 gtk2reactor.install()
21
21
22
22
23 def hijack_reactor():
23 def hijack_reactor():
24 """Modifies Twisted's reactor with a dummy so user code does
24 """Modifies Twisted's reactor with a dummy so user code does
25 not block IPython. This function returns the original
25 not block IPython. This function returns the original
26 'twisted.internet.reactor' that has been hijacked.
26 'twisted.internet.reactor' that has been hijacked.
27
27
28 NOTE: Make sure you call this *AFTER* you've installed
28 NOTE: Make sure you call this *AFTER* you've installed
29 the reactor of your choice.
29 the reactor of your choice.
30 """
30 """
31 from twisted import internet
31 from twisted import internet
32 orig_reactor = internet.reactor
32 orig_reactor = internet.reactor
33
33
34 class DummyReactor(object):
34 class DummyReactor(object):
35 def run(self):
35 def run(self):
36 pass
36 pass
37 def __getattr__(self, name):
37 def __getattr__(self, name):
38 return getattr(orig_reactor, name)
38 return getattr(orig_reactor, name)
39 def __setattr__(self, name, value):
39 def __setattr__(self, name, value):
40 return setattr(orig_reactor, name, value)
40 return setattr(orig_reactor, name, value)
41
41
42 internet.reactor = DummyReactor()
42 internet.reactor = DummyReactor()
43 return orig_reactor
43 return orig_reactor
44
44
45 class TwistedInteractiveShell(InteractiveShell):
45 class TwistedInteractiveShell(InteractiveShell):
46 """Simple multi-threaded shell."""
46 """Simple multi-threaded shell."""
47
47
48 # Threading strategy taken from:
48 # Threading strategy taken from:
49 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
49 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
50 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
50 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
51 # from the pygtk mailing list, to avoid lockups with system calls.
51 # from the pygtk mailing list, to avoid lockups with system calls.
52
52
53 # class attribute to indicate whether the class supports threads or not.
53 # class attribute to indicate whether the class supports threads or not.
54 # Subclasses with thread support should override this as needed.
54 # Subclasses with thread support should override this as needed.
55 isthreaded = True
55 isthreaded = True
56
56
57 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
57 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
58 user_ns=None,user_global_ns=None,banner2='',**kw):
58 user_ns=None,user_global_ns=None,banner2='',**kw):
59 """Similar to the normal InteractiveShell, but with threading control"""
59 """Similar to the normal InteractiveShell, but with threading control"""
60
60
61 InteractiveShell.__init__(self,name,usage,rc,user_ns,
61 InteractiveShell.__init__(self,name,usage,rc,user_ns,
62 user_global_ns,banner2)
62 user_global_ns,banner2)
63
63
64
64
65 # A queue to hold the code to be executed.
65 # A queue to hold the code to be executed.
66 self.code_queue = Queue.Queue()
66 self.code_queue = Queue.Queue()
67
67
68 # Stuff to do at closing time
68 # Stuff to do at closing time
69 self._kill = None
69 self._kill = None
70 on_kill = kw.get('on_kill', [])
70 on_kill = kw.get('on_kill', [])
71 # Check that all things to kill are callable:
71 # Check that all things to kill are callable:
72 for t in on_kill:
72 for t in on_kill:
73 if not callable(t):
73 if not callable(t):
74 raise TypeError,'on_kill must be a list of callables'
74 raise TypeError,'on_kill must be a list of callables'
75 self.on_kill = on_kill
75 self.on_kill = on_kill
76 # thread identity of the "worker thread" (that may execute code directly)
76 # thread identity of the "worker thread" (that may execute code directly)
77 self.worker_ident = None
77 self.worker_ident = None
78 self.reactor_started = False
78 self.reactor_started = False
79 self.first_run = True
79 self.first_run = True
80
80
81 def runsource(self, source, filename="<input>", symbol="single"):
81 def runsource(self, source, filename="<input>", symbol="single"):
82 """Compile and run some source in the interpreter.
82 """Compile and run some source in the interpreter.
83
83
84 Modified version of code.py's runsource(), to handle threading issues.
84 Modified version of code.py's runsource(), to handle threading issues.
85 See the original for full docstring details."""
85 See the original for full docstring details."""
86
86
87 # If Ctrl-C was typed, we reset the flag and return right away
87 # If Ctrl-C was typed, we reset the flag and return right away
88 if shellglobals.KBINT:
88 if shellglobals.KBINT:
89 shellglobals.KBINT = False
89 shellglobals.KBINT = False
90 return False
90 return False
91
91
92 if self._kill:
92 if self._kill:
93 # can't queue new code if we are being killed
93 # can't queue new code if we are being killed
94 return True
94 return True
95
95
96 try:
96 try:
97 code = self.compile(source, filename, symbol)
97 code = self.compile(source, filename, symbol)
98 except (OverflowError, SyntaxError, ValueError):
98 except (OverflowError, SyntaxError, ValueError):
99 # Case 1
99 # Case 1
100 self.showsyntaxerror(filename)
100 self.showsyntaxerror(filename)
101 return False
101 return False
102
102
103 if code is None:
103 if code is None:
104 # Case 2
104 # Case 2
105 return True
105 return True
106
106
107 # shortcut - if we are in worker thread, or the worker thread is not running,
107 # shortcut - if we are in worker thread, or the worker thread is not running,
108 # execute directly (to allow recursion and prevent deadlock if code is run early
108 # execute directly (to allow recursion and prevent deadlock if code is run early
109 # in IPython construction)
109 # in IPython construction)
110
110
111 if (not self.reactor_started or (self.worker_ident is None and not self.first_run)
111 if (not self.reactor_started or (self.worker_ident is None and not self.first_run)
112 or self.worker_ident == thread.get_ident() or shellglobals.run_in_frontend(source)):
112 or self.worker_ident == thread.get_ident() or shellglobals.run_in_frontend(source)):
113 InteractiveShell.runcode(self,code)
113 InteractiveShell.runcode(self,code)
114 return
114 return
115
115
116 # Case 3
116 # Case 3
117 # Store code in queue, so the execution thread can handle it.
117 # Store code in queue, so the execution thread can handle it.
118
118
119 self.first_run = False
119 self.first_run = False
120 completed_ev, received_ev = threading.Event(), threading.Event()
120 completed_ev, received_ev = threading.Event(), threading.Event()
121
121
122 self.code_queue.put((code,completed_ev, received_ev))
122 self.code_queue.put((code,completed_ev, received_ev))
123
123
124 reactor.callLater(0.0,self.runcode)
124 reactor.callLater(0.0,self.runcode)
125 received_ev.wait(5)
125 received_ev.wait(5)
126 if not received_ev.isSet():
126 if not received_ev.isSet():
127 # the mainloop is dead, start executing code directly
127 # the mainloop is dead, start executing code directly
128 print "Warning: Timeout for mainloop thread exceeded"
128 print "Warning: Timeout for mainloop thread exceeded"
129 print "switching to nonthreaded mode (until mainloop wakes up again)"
129 print "switching to nonthreaded mode (until mainloop wakes up again)"
130 self.worker_ident = None
130 self.worker_ident = None
131 else:
131 else:
132 completed_ev.wait()
132 completed_ev.wait()
133
133
134 return False
134 return False
135
135
136 def runcode(self):
136 def runcode(self):
137 """Execute a code object.
137 """Execute a code object.
138
138
139 Multithreaded wrapper around IPython's runcode()."""
139 Multithreaded wrapper around IPython's runcode()."""
140
140
141
141
142 # we are in worker thread, stash out the id for runsource()
142 # we are in worker thread, stash out the id for runsource()
143 self.worker_ident = thread.get_ident()
143 self.worker_ident = thread.get_ident()
144
144
145 if self._kill:
145 if self._kill:
146 print >>Term.cout, 'Closing threads...',
146 print >>Term.cout, 'Closing threads...',
147 Term.cout.flush()
147 Term.cout.flush()
148 for tokill in self.on_kill:
148 for tokill in self.on_kill:
149 tokill()
149 tokill()
150 print >>Term.cout, 'Done.'
150 print >>Term.cout, 'Done.'
151 # allow kill() to return
151 # allow kill() to return
152 self._kill.set()
152 self._kill.set()
153 return True
153 return True
154
154
155 # Install SIGINT handler. We do it every time to ensure that if user
155 # Install SIGINT handler. We do it every time to ensure that if user
156 # code modifies it, we restore our own handling.
156 # code modifies it, we restore our own handling.
157 try:
157 try:
158 pass
158 pass
159 signal(SIGINT,shellglobals.sigint_handler)
159 signal(SIGINT,shellglobals.sigint_handler)
160 except SystemError:
160 except SystemError:
161 # This happens under Windows, which seems to have all sorts
161 # This happens under Windows, which seems to have all sorts
162 # of problems with signal handling. Oh well...
162 # of problems with signal handling. Oh well...
163 pass
163 pass
164
164
165 # Flush queue of pending code by calling the run methood of the parent
165 # Flush queue of pending code by calling the run methood of the parent
166 # class with all items which may be in the queue.
166 # class with all items which may be in the queue.
167 code_to_run = None
167 code_to_run = None
168 while 1:
168 while 1:
169 try:
169 try:
170 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
170 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
171 except Queue.Empty:
171 except Queue.Empty:
172 break
172 break
173 received_ev.set()
173 received_ev.set()
174
174
175
175
176 # Exceptions need to be raised differently depending on which
176 # Exceptions need to be raised differently depending on which
177 # thread is active. This convoluted try/except is only there to
177 # thread is active. This convoluted try/except is only there to
178 # protect against asynchronous exceptions, to ensure that a shellglobals.KBINT
178 # protect against asynchronous exceptions, to ensure that a shellglobals.KBINT
179 # at the wrong time doesn't deadlock everything. The global
179 # at the wrong time doesn't deadlock everything. The global
180 # CODE_TO_RUN is set to true/false as close as possible to the
180 # CODE_TO_RUN is set to true/false as close as possible to the
181 # runcode() call, so that the KBINT handler is correctly informed.
181 # runcode() call, so that the KBINT handler is correctly informed.
182 try:
182 try:
183 try:
183 try:
184 shellglobals.CODE_RUN = True
184 shellglobals.CODE_RUN = True
185 InteractiveShell.runcode(self,code_to_run)
185 InteractiveShell.runcode(self,code_to_run)
186 except KeyboardInterrupt:
186 except KeyboardInterrupt:
187 print "Keyboard interrupted in mainloop"
187 print "Keyboard interrupted in mainloop"
188 while not self.code_queue.empty():
188 while not self.code_queue.empty():
189 code = self.code_queue.get_nowait()
189 code = self.code_queue.get_nowait()
190 break
190 break
191 finally:
191 finally:
192 shellglobals.CODE_RUN = False
192 shellglobals.CODE_RUN = False
193 # allow runsource() return from wait
193 # allow runsource() return from wait
194 completed_ev.set()
194 completed_ev.set()
195
195
196 # This MUST return true for gtk threading to work
196 # This MUST return true for gtk threading to work
197 return True
197 return True
198
198
199 def kill(self):
199 def kill(self):
200 """Kill the thread, returning when it has been shut down."""
200 """Kill the thread, returning when it has been shut down."""
201 self._kill = threading.Event()
201 self._kill = threading.Event()
202 reactor.callLater(0.0,self.runcode)
202 reactor.callLater(0.0,self.runcode)
203 self._kill.wait()
203 self._kill.wait()
204
204
205
205
206
206
207 class IPShellTwisted:
207 class IPShellTwisted:
208 """Run a Twisted reactor while in an IPython session.
208 """Run a Twisted reactor while in an IPython session.
209
209
210 Python commands can be passed to the thread where they will be
210 Python commands can be passed to the thread where they will be
211 executed. This is implemented by periodically checking for
211 executed. This is implemented by periodically checking for
212 passed code using a Twisted reactor callback.
212 passed code using a Twisted reactor callback.
213 """
213 """
214
214
215 TIMEOUT = 0.01 # Millisecond interval between reactor runs.
215 TIMEOUT = 0.01 # Millisecond interval between reactor runs.
216
216
217 def __init__(self, argv=None, user_ns=None, debug=1,
217 def __init__(self, argv=None, user_ns=None, debug=1,
218 shell_class=TwistedInteractiveShell):
218 shell_class=TwistedInteractiveShell):
219
219
220 from twisted.internet import reactor
220 from twisted.internet import reactor
221 self.reactor = hijack_reactor()
221 self.reactor = hijack_reactor()
222
222
223 mainquit = self.reactor.stop
223 mainquit = self.reactor.stop
224
224
225 # Make sure IPython keeps going after reactor stop.
225 # Make sure IPython keeps going after reactor stop.
226 def reactorstop():
226 def reactorstop():
227 pass
227 pass
228 self.reactor.stop = reactorstop
228 self.reactor.stop = reactorstop
229 reactorrun_orig = self.reactor.run
229 reactorrun_orig = self.reactor.run
230 self.quitting = False
230 self.quitting = False
231 def reactorrun():
231 def reactorrun():
232 while True and not self.quitting:
232 while True and not self.quitting:
233 reactorrun_orig()
233 reactorrun_orig()
234 self.reactor.run = reactorrun
234 self.reactor.run = reactorrun
235
235
236 self.IP = make_IPython(argv, user_ns=user_ns, debug=debug,
236 self.IP = make_IPython(argv, user_ns=user_ns, debug=debug,
237 shell_class=shell_class,
237 shell_class=shell_class,
238 on_kill=[mainquit])
238 on_kill=[mainquit])
239
239
240 # threading.Thread.__init__(self)
240 # threading.Thread.__init__(self)
241
241
242 def run(self):
242 def run(self):
243 self.IP.mainloop()
243 self.IP.mainloop()
244 self.quitting = True
244 self.quitting = True
245 self.IP.kill()
245 self.IP.kill()
246
246
247 def mainloop(self):
247 def mainloop(self):
248 def mainLoopThreadDeath(r):
248 def mainLoopThreadDeath(r):
249 print "mainLoopThreadDeath: ", str(r)
249 print "mainLoopThreadDeath: ", str(r)
250 def spawnMainloopThread():
250 def spawnMainloopThread():
251 d=threads.deferToThread(self.run)
251 d=threads.deferToThread(self.run)
252 d.addBoth(mainLoopThreadDeath)
252 d.addBoth(mainLoopThreadDeath)
253 reactor.callWhenRunning(spawnMainloopThread)
253 reactor.callWhenRunning(spawnMainloopThread)
254 self.IP.reactor_started = True
254 self.IP.reactor_started = True
255 self.reactor.run()
255 self.reactor.run()
256 print "mainloop ending...."
256 print "mainloop ending...."
257
257
258 exists = True
258 exists = True
259
259
260
260
261 if __name__ == '__main__':
261 if __name__ == '__main__':
262 # Sample usage.
262 # Sample usage.
263
263
264 # Create the shell object. This steals twisted.internet.reactor
264 # Create the shell object. This steals twisted.internet.reactor
265 # for its own purposes, to make sure you've already installed a
265 # for its own purposes, to make sure you've already installed a
266 # reactor of your choice.
266 # reactor of your choice.
267 shell = IPShellTwisted(
267 shell = IPShellTwisted(
268 argv=[],
268 argv=[],
269 user_ns={'__name__': '__example__',
269 user_ns={'__name__': '__example__',
270 'hello': 'world',
270 'hello': 'world',
271 },
271 },
272 )
272 )
273
273
274 # Run the mainloop. This runs the actual reactor.run() method.
274 # Run the mainloop. This runs the actual reactor.run() method.
275 # The twisted.internet.reactor object at this point is a dummy
275 # The twisted.internet.reactor object at this point is a dummy
276 # object that passes through to the actual reactor, but prevents
276 # object that passes through to the actual reactor, but prevents
277 # run() from being called on it again.
277 # run() from being called on it again.
278 shell.mainloop()
278 shell.mainloop()
279
279
280 # You must exit IPython to terminate your program.
280 # You must exit IPython to terminate your program.
281 print 'Goodbye!'
281 print 'Goodbye!'
282
282
@@ -1,285 +1,285 b''
1 """
1 """
2 Frontend class that uses IPython0 to prefilter the inputs.
2 Frontend class that uses IPython0 to prefilter the inputs.
3
3
4 Using the IPython0 mechanism gives us access to the magics.
4 Using the IPython0 mechanism gives us access to the magics.
5
5
6 This is a transitory class, used here to do the transition between
6 This is a transitory class, used here to do the transition between
7 ipython0 and ipython1. This class is meant to be short-lived as more
7 ipython0 and ipython1. This class is meant to be short-lived as more
8 functionnality is abstracted out of ipython0 in reusable functions and
8 functionnality is abstracted out of ipython0 in reusable functions and
9 is added on the interpreter. This class can be a used to guide this
9 is added on the interpreter. This class can be a used to guide this
10 refactoring.
10 refactoring.
11 """
11 """
12 __docformat__ = "restructuredtext en"
12 __docformat__ = "restructuredtext en"
13
13
14 #-------------------------------------------------------------------------------
14 #-------------------------------------------------------------------------------
15 # Copyright (C) 2008 The IPython Development Team
15 # Copyright (C) 2008 The IPython Development Team
16 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
19 #-------------------------------------------------------------------------------
19 #-------------------------------------------------------------------------------
20
20
21 #-------------------------------------------------------------------------------
21 #-------------------------------------------------------------------------------
22 # Imports
22 # Imports
23 #-------------------------------------------------------------------------------
23 #-------------------------------------------------------------------------------
24 import sys
24 import sys
25 import pydoc
25 import pydoc
26 import os
26 import os
27 import re
27 import re
28 import __builtin__
28 import __builtin__
29
29
30 from IPython.ipmaker import make_IPython
30 from IPython.core.ipmaker import make_IPython
31 from IPython.core.ipapi import IPApi
31 from IPython.core.ipapi import IPApi
32 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
32 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
33
33
34 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
34 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
35
35
36 from IPython.utils.genutils import Term
36 from IPython.utils.genutils import Term
37
37
38 from linefrontendbase import LineFrontEndBase, common_prefix
38 from linefrontendbase import LineFrontEndBase, common_prefix
39
39
40
40
41 def mk_system_call(system_call_function, command):
41 def mk_system_call(system_call_function, command):
42 """ given a os.system replacement, and a leading string command,
42 """ given a os.system replacement, and a leading string command,
43 returns a function that will execute the command with the given
43 returns a function that will execute the command with the given
44 argument string.
44 argument string.
45 """
45 """
46 def my_system_call(args):
46 def my_system_call(args):
47 system_call_function("%s %s" % (command, args))
47 system_call_function("%s %s" % (command, args))
48
48
49 my_system_call.__doc__ = "Calls %s" % command
49 my_system_call.__doc__ = "Calls %s" % command
50 return my_system_call
50 return my_system_call
51
51
52 #-------------------------------------------------------------------------------
52 #-------------------------------------------------------------------------------
53 # Frontend class using ipython0 to do the prefiltering.
53 # Frontend class using ipython0 to do the prefiltering.
54 #-------------------------------------------------------------------------------
54 #-------------------------------------------------------------------------------
55 class PrefilterFrontEnd(LineFrontEndBase):
55 class PrefilterFrontEnd(LineFrontEndBase):
56 """ Class that uses ipython0 to do prefilter the input, do the
56 """ Class that uses ipython0 to do prefilter the input, do the
57 completion and the magics.
57 completion and the magics.
58
58
59 The core trick is to use an ipython0 instance to prefilter the
59 The core trick is to use an ipython0 instance to prefilter the
60 input, and share the namespace between the interpreter instance used
60 input, and share the namespace between the interpreter instance used
61 to execute the statements and the ipython0 used for code
61 to execute the statements and the ipython0 used for code
62 completion...
62 completion...
63 """
63 """
64
64
65 debug = False
65 debug = False
66
66
67 def __init__(self, ipython0=None, argv=None, *args, **kwargs):
67 def __init__(self, ipython0=None, argv=None, *args, **kwargs):
68 """ Parameters:
68 """ Parameters:
69 -----------
69 -----------
70
70
71 ipython0: an optional ipython0 instance to use for command
71 ipython0: an optional ipython0 instance to use for command
72 prefiltering and completion.
72 prefiltering and completion.
73
73
74 argv : list, optional
74 argv : list, optional
75 Used as the instance's argv value. If not given, [] is used.
75 Used as the instance's argv value. If not given, [] is used.
76 """
76 """
77 if argv is None:
77 if argv is None:
78 argv = []
78 argv = []
79 # This is a hack to avoid the IPython exception hook to trigger
79 # This is a hack to avoid the IPython exception hook to trigger
80 # on exceptions (https://bugs.launchpad.net/bugs/337105)
80 # on exceptions (https://bugs.launchpad.net/bugs/337105)
81 # XXX: This is horrible: module-leve monkey patching -> side
81 # XXX: This is horrible: module-leve monkey patching -> side
82 # effects.
82 # effects.
83 from IPython.core import iplib
83 from IPython.core import iplib
84 iplib.InteractiveShell.isthreaded = True
84 iplib.InteractiveShell.isthreaded = True
85
85
86 LineFrontEndBase.__init__(self, *args, **kwargs)
86 LineFrontEndBase.__init__(self, *args, **kwargs)
87 self.shell.output_trap = RedirectorOutputTrap(
87 self.shell.output_trap = RedirectorOutputTrap(
88 out_callback=self.write,
88 out_callback=self.write,
89 err_callback=self.write,
89 err_callback=self.write,
90 )
90 )
91 self.shell.traceback_trap = SyncTracebackTrap(
91 self.shell.traceback_trap = SyncTracebackTrap(
92 formatters=self.shell.traceback_trap.formatters,
92 formatters=self.shell.traceback_trap.formatters,
93 )
93 )
94
94
95 # Start the ipython0 instance:
95 # Start the ipython0 instance:
96 self.save_output_hooks()
96 self.save_output_hooks()
97 if ipython0 is None:
97 if ipython0 is None:
98 # Instanciate an IPython0 interpreter to be able to use the
98 # Instanciate an IPython0 interpreter to be able to use the
99 # prefiltering.
99 # prefiltering.
100 # Suppress all key input, to avoid waiting
100 # Suppress all key input, to avoid waiting
101 def my_rawinput(x=None):
101 def my_rawinput(x=None):
102 return '\n'
102 return '\n'
103 old_rawinput = __builtin__.raw_input
103 old_rawinput = __builtin__.raw_input
104 __builtin__.raw_input = my_rawinput
104 __builtin__.raw_input = my_rawinput
105 # XXX: argv=[] is a bit bold.
105 # XXX: argv=[] is a bit bold.
106 ipython0 = make_IPython(argv=argv,
106 ipython0 = make_IPython(argv=argv,
107 user_ns=self.shell.user_ns,
107 user_ns=self.shell.user_ns,
108 user_global_ns=self.shell.user_global_ns)
108 user_global_ns=self.shell.user_global_ns)
109 __builtin__.raw_input = old_rawinput
109 __builtin__.raw_input = old_rawinput
110 self.ipython0 = ipython0
110 self.ipython0 = ipython0
111 # Set the pager:
111 # Set the pager:
112 self.ipython0.set_hook('show_in_pager',
112 self.ipython0.set_hook('show_in_pager',
113 lambda s, string: self.write("\n" + string))
113 lambda s, string: self.write("\n" + string))
114 self.ipython0.write = self.write
114 self.ipython0.write = self.write
115 self._ip = _ip = IPApi(self.ipython0)
115 self._ip = _ip = IPApi(self.ipython0)
116 # Make sure the raw system call doesn't get called, as we don't
116 # Make sure the raw system call doesn't get called, as we don't
117 # have a stdin accessible.
117 # have a stdin accessible.
118 self._ip.system = self.system_call
118 self._ip.system = self.system_call
119 # XXX: Muck around with magics so that they work better
119 # XXX: Muck around with magics so that they work better
120 # in our environment
120 # in our environment
121 if not sys.platform.startswith('win'):
121 if not sys.platform.startswith('win'):
122 self.ipython0.magic_ls = mk_system_call(self.system_call,
122 self.ipython0.magic_ls = mk_system_call(self.system_call,
123 'ls -CF')
123 'ls -CF')
124 # And now clean up the mess created by ipython0
124 # And now clean up the mess created by ipython0
125 self.release_output()
125 self.release_output()
126
126
127
127
128 if not 'banner' in kwargs and self.banner is None:
128 if not 'banner' in kwargs and self.banner is None:
129 self.banner = self.ipython0.BANNER
129 self.banner = self.ipython0.BANNER
130
130
131 # FIXME: __init__ and start should be two different steps
131 # FIXME: __init__ and start should be two different steps
132 self.start()
132 self.start()
133
133
134 #--------------------------------------------------------------------------
134 #--------------------------------------------------------------------------
135 # FrontEndBase interface
135 # FrontEndBase interface
136 #--------------------------------------------------------------------------
136 #--------------------------------------------------------------------------
137
137
138 def show_traceback(self):
138 def show_traceback(self):
139 """ Use ipython0 to capture the last traceback and display it.
139 """ Use ipython0 to capture the last traceback and display it.
140 """
140 """
141 # Don't do the capture; the except_hook has already done some
141 # Don't do the capture; the except_hook has already done some
142 # modifications to the IO streams, if we store them, we'll be
142 # modifications to the IO streams, if we store them, we'll be
143 # storing the wrong ones.
143 # storing the wrong ones.
144 #self.capture_output()
144 #self.capture_output()
145 self.ipython0.showtraceback(tb_offset=-1)
145 self.ipython0.showtraceback(tb_offset=-1)
146 self.release_output()
146 self.release_output()
147
147
148
148
149 def execute(self, python_string, raw_string=None):
149 def execute(self, python_string, raw_string=None):
150 if self.debug:
150 if self.debug:
151 print 'Executing Python code:', repr(python_string)
151 print 'Executing Python code:', repr(python_string)
152 self.capture_output()
152 self.capture_output()
153 LineFrontEndBase.execute(self, python_string,
153 LineFrontEndBase.execute(self, python_string,
154 raw_string=raw_string)
154 raw_string=raw_string)
155 self.release_output()
155 self.release_output()
156
156
157
157
158 def save_output_hooks(self):
158 def save_output_hooks(self):
159 """ Store all the output hooks we can think of, to be able to
159 """ Store all the output hooks we can think of, to be able to
160 restore them.
160 restore them.
161
161
162 We need to do this early, as starting the ipython0 instance will
162 We need to do this early, as starting the ipython0 instance will
163 screw ouput hooks.
163 screw ouput hooks.
164 """
164 """
165 self.__old_cout_write = Term.cout.write
165 self.__old_cout_write = Term.cout.write
166 self.__old_cerr_write = Term.cerr.write
166 self.__old_cerr_write = Term.cerr.write
167 self.__old_stdout = sys.stdout
167 self.__old_stdout = sys.stdout
168 self.__old_stderr= sys.stderr
168 self.__old_stderr= sys.stderr
169 self.__old_help_output = pydoc.help.output
169 self.__old_help_output = pydoc.help.output
170 self.__old_display_hook = sys.displayhook
170 self.__old_display_hook = sys.displayhook
171
171
172
172
173 def capture_output(self):
173 def capture_output(self):
174 """ Capture all the output mechanisms we can think of.
174 """ Capture all the output mechanisms we can think of.
175 """
175 """
176 self.save_output_hooks()
176 self.save_output_hooks()
177 Term.cout.write = self.write
177 Term.cout.write = self.write
178 Term.cerr.write = self.write
178 Term.cerr.write = self.write
179 sys.stdout = Term.cout
179 sys.stdout = Term.cout
180 sys.stderr = Term.cerr
180 sys.stderr = Term.cerr
181 pydoc.help.output = self.shell.output_trap.out
181 pydoc.help.output = self.shell.output_trap.out
182
182
183
183
184 def release_output(self):
184 def release_output(self):
185 """ Release all the different captures we have made.
185 """ Release all the different captures we have made.
186 """
186 """
187 Term.cout.write = self.__old_cout_write
187 Term.cout.write = self.__old_cout_write
188 Term.cerr.write = self.__old_cerr_write
188 Term.cerr.write = self.__old_cerr_write
189 sys.stdout = self.__old_stdout
189 sys.stdout = self.__old_stdout
190 sys.stderr = self.__old_stderr
190 sys.stderr = self.__old_stderr
191 pydoc.help.output = self.__old_help_output
191 pydoc.help.output = self.__old_help_output
192 sys.displayhook = self.__old_display_hook
192 sys.displayhook = self.__old_display_hook
193
193
194
194
195 def complete(self, line):
195 def complete(self, line):
196 # FIXME: This should be factored out in the linefrontendbase
196 # FIXME: This should be factored out in the linefrontendbase
197 # method.
197 # method.
198 word = self._get_completion_text(line)
198 word = self._get_completion_text(line)
199 completions = self.ipython0.complete(word)
199 completions = self.ipython0.complete(word)
200 # FIXME: The proper sort should be done in the complete method.
200 # FIXME: The proper sort should be done in the complete method.
201 key = lambda x: x.replace('_', '')
201 key = lambda x: x.replace('_', '')
202 completions.sort(key=key)
202 completions.sort(key=key)
203 if completions:
203 if completions:
204 prefix = common_prefix(completions)
204 prefix = common_prefix(completions)
205 line = line[:-len(word)] + prefix
205 line = line[:-len(word)] + prefix
206 return line, completions
206 return line, completions
207
207
208
208
209 #--------------------------------------------------------------------------
209 #--------------------------------------------------------------------------
210 # LineFrontEndBase interface
210 # LineFrontEndBase interface
211 #--------------------------------------------------------------------------
211 #--------------------------------------------------------------------------
212
212
213 def prefilter_input(self, input_string):
213 def prefilter_input(self, input_string):
214 """ Using IPython0 to prefilter the commands to turn them
214 """ Using IPython0 to prefilter the commands to turn them
215 in executable statements that are valid Python strings.
215 in executable statements that are valid Python strings.
216 """
216 """
217 input_string = LineFrontEndBase.prefilter_input(self, input_string)
217 input_string = LineFrontEndBase.prefilter_input(self, input_string)
218 filtered_lines = []
218 filtered_lines = []
219 # The IPython0 prefilters sometime produce output. We need to
219 # The IPython0 prefilters sometime produce output. We need to
220 # capture it.
220 # capture it.
221 self.capture_output()
221 self.capture_output()
222 self.last_result = dict(number=self.prompt_number)
222 self.last_result = dict(number=self.prompt_number)
223
223
224 ## try:
224 ## try:
225 ## for line in input_string.split('\n'):
225 ## for line in input_string.split('\n'):
226 ## filtered_lines.append(
226 ## filtered_lines.append(
227 ## self.ipython0.prefilter(line, False).rstrip())
227 ## self.ipython0.prefilter(line, False).rstrip())
228 ## except:
228 ## except:
229 ## # XXX: probably not the right thing to do.
229 ## # XXX: probably not the right thing to do.
230 ## self.ipython0.showsyntaxerror()
230 ## self.ipython0.showsyntaxerror()
231 ## self.after_execute()
231 ## self.after_execute()
232 ## finally:
232 ## finally:
233 ## self.release_output()
233 ## self.release_output()
234
234
235
235
236 try:
236 try:
237 try:
237 try:
238 for line in input_string.split('\n'):
238 for line in input_string.split('\n'):
239 filtered_lines.append(
239 filtered_lines.append(
240 self.ipython0.prefilter(line, False).rstrip())
240 self.ipython0.prefilter(line, False).rstrip())
241 except:
241 except:
242 # XXX: probably not the right thing to do.
242 # XXX: probably not the right thing to do.
243 self.ipython0.showsyntaxerror()
243 self.ipython0.showsyntaxerror()
244 self.after_execute()
244 self.after_execute()
245 finally:
245 finally:
246 self.release_output()
246 self.release_output()
247
247
248
248
249
249
250 # Clean up the trailing whitespace, to avoid indentation errors
250 # Clean up the trailing whitespace, to avoid indentation errors
251 filtered_string = '\n'.join(filtered_lines)
251 filtered_string = '\n'.join(filtered_lines)
252 return filtered_string
252 return filtered_string
253
253
254
254
255 #--------------------------------------------------------------------------
255 #--------------------------------------------------------------------------
256 # PrefilterFrontEnd interface
256 # PrefilterFrontEnd interface
257 #--------------------------------------------------------------------------
257 #--------------------------------------------------------------------------
258
258
259 def system_call(self, command_string):
259 def system_call(self, command_string):
260 """ Allows for frontend to define their own system call, to be
260 """ Allows for frontend to define their own system call, to be
261 able capture output and redirect input.
261 able capture output and redirect input.
262 """
262 """
263 return os.system(command_string)
263 return os.system(command_string)
264
264
265
265
266 def do_exit(self):
266 def do_exit(self):
267 """ Exit the shell, cleanup and save the history.
267 """ Exit the shell, cleanup and save the history.
268 """
268 """
269 self.ipython0.atexit_operations()
269 self.ipython0.atexit_operations()
270
270
271
271
272 def _get_completion_text(self, line):
272 def _get_completion_text(self, line):
273 """ Returns the text to be completed by breaking the line at specified
273 """ Returns the text to be completed by breaking the line at specified
274 delimiters.
274 delimiters.
275 """
275 """
276 # Break at: spaces, '=', all parentheses (except if balanced).
276 # Break at: spaces, '=', all parentheses (except if balanced).
277 # FIXME2: In the future, we need to make the implementation similar to
277 # FIXME2: In the future, we need to make the implementation similar to
278 # that in the 'pyreadline' module (modes/basemode.py) where we break at
278 # that in the 'pyreadline' module (modes/basemode.py) where we break at
279 # each delimiter and try to complete the residual line, until we get a
279 # each delimiter and try to complete the residual line, until we get a
280 # successful list of completions.
280 # successful list of completions.
281 expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
281 expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
282 complete_sep = re.compile(expression)
282 complete_sep = re.compile(expression)
283 text = complete_sep.split(line)[-1]
283 text = complete_sep.split(line)[-1]
284 return text
284 return text
285
285
General Comments 0
You need to be logged in to leave comments. Login now