##// END OF EJS Templates
Fix problem with rc_override....
Václav Šmilauer -
Show More
@@ -1,1246 +1,1261 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, ipapi
37 from IPython import ultraTB, ipapi
38 from IPython.Magic import Magic
38 from IPython.Magic import Magic
39 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
39 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
40 from IPython.iplib import InteractiveShell
40 from IPython.iplib import InteractiveShell
41 from IPython.ipmaker import make_IPython
41 from IPython.ipmaker import make_IPython
42 from IPython.ipstruct import Struct
42 from IPython.ipstruct import Struct
43 from IPython.testing import decorators as testdec
43 from IPython.testing import decorators as testdec
44
44
45 # Globals
45 # Globals
46 # global flag to pass around information about Ctrl-C without exceptions
46 # global flag to pass around information about Ctrl-C without exceptions
47 KBINT = False
47 KBINT = False
48
48
49 # global flag to turn on/off Tk support.
49 # global flag to turn on/off Tk support.
50 USE_TK = False
50 USE_TK = False
51
51
52 # ID for the main thread, used for cross-thread exceptions
52 # ID for the main thread, used for cross-thread exceptions
53 MAIN_THREAD_ID = thread.get_ident()
53 MAIN_THREAD_ID = thread.get_ident()
54
54
55 # Tag when runcode() is active, for exception handling
55 # Tag when runcode() is active, for exception handling
56 CODE_RUN = None
56 CODE_RUN = None
57
57
58 # Default timeout for waiting for multithreaded shells (in seconds)
58 # Default timeout for waiting for multithreaded shells (in seconds)
59 GUI_TIMEOUT = 10
59 GUI_TIMEOUT = 10
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # This class is trivial now, but I want to have it in to publish a clean
62 # This class is trivial now, but I want to have it in to publish a clean
63 # interface. Later when the internals are reorganized, code that uses this
63 # interface. Later when the internals are reorganized, code that uses this
64 # shouldn't have to change.
64 # shouldn't have to change.
65
65
66 class IPShell:
66 class IPShell:
67 """Create an IPython instance."""
67 """Create an IPython instance."""
68
68
69 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
69 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
70 debug=1,shell_class=InteractiveShell):
70 debug=1,shell_class=InteractiveShell):
71 self.IP = make_IPython(argv,user_ns=user_ns,
71 self.IP = make_IPython(argv,user_ns=user_ns,
72 user_global_ns=user_global_ns,
72 user_global_ns=user_global_ns,
73 debug=debug,shell_class=shell_class)
73 debug=debug,shell_class=shell_class)
74
74
75 def mainloop(self,sys_exit=0,banner=None):
75 def mainloop(self,sys_exit=0,banner=None):
76 self.IP.mainloop(banner)
76 self.IP.mainloop(banner)
77 if sys_exit:
77 if sys_exit:
78 sys.exit()
78 sys.exit()
79
79
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81 def kill_embedded(self,parameter_s=''):
81 def kill_embedded(self,parameter_s=''):
82 """%kill_embedded : deactivate for good the current embedded IPython.
82 """%kill_embedded : deactivate for good the current embedded IPython.
83
83
84 This function (after asking for confirmation) sets an internal flag so that
84 This function (after asking for confirmation) sets an internal flag so that
85 an embedded IPython will never activate again. This is useful to
85 an embedded IPython will never activate again. This is useful to
86 permanently disable a shell that is being called inside a loop: once you've
86 permanently disable a shell that is being called inside a loop: once you've
87 figured out what you needed from it, you may then kill it and the program
87 figured out what you needed from it, you may then kill it and the program
88 will then continue to run without the interactive shell interfering again.
88 will then continue to run without the interactive shell interfering again.
89 """
89 """
90
90
91 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
91 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
92 "(y/n)? [y/N] ",'n')
92 "(y/n)? [y/N] ",'n')
93 if kill:
93 if kill:
94 self.shell.embedded_active = False
94 self.shell.embedded_active = False
95 print "This embedded IPython will not reactivate anymore once you exit."
95 print "This embedded IPython will not reactivate anymore once you exit."
96
96
97 class IPShellEmbed:
97 class IPShellEmbed:
98 """Allow embedding an IPython shell into a running program.
98 """Allow embedding an IPython shell into a running program.
99
99
100 Instances of this class are callable, with the __call__ method being an
100 Instances of this class are callable, with the __call__ method being an
101 alias to the embed() method of an InteractiveShell instance.
101 alias to the embed() method of an InteractiveShell instance.
102
102
103 Usage (see also the example-embed.py file for a running example):
103 Usage (see also the example-embed.py file for a running example):
104
104
105 ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
105 ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
106
106
107 - argv: list containing valid command-line options for IPython, as they
107 - argv: list containing valid command-line options for IPython, as they
108 would appear in sys.argv[1:].
108 would appear in sys.argv[1:].
109
109
110 For example, the following command-line options:
110 For example, the following command-line options:
111
111
112 $ ipython -prompt_in1 'Input <\\#>' -colors LightBG
112 $ ipython -prompt_in1 'Input <\\#>' -colors LightBG
113
113
114 would be passed in the argv list as:
114 would be passed in the argv list as:
115
115
116 ['-prompt_in1','Input <\\#>','-colors','LightBG']
116 ['-prompt_in1','Input <\\#>','-colors','LightBG']
117
117
118 - banner: string which gets printed every time the interpreter starts.
118 - banner: string which gets printed every time the interpreter starts.
119
119
120 - exit_msg: string which gets printed every time the interpreter exits.
120 - exit_msg: string which gets printed every time the interpreter exits.
121
121
122 - rc_override: a dict or Struct of configuration options such as those
122 - rc_override: a dict or Struct of configuration options such as those
123 used by IPython. These options are read from your ~/.ipython/ipythonrc
123 used by IPython. These options are read from your ~/.ipython/ipythonrc
124 file when the Shell object is created. Passing an explicit rc_override
124 file when the Shell object is created. Passing an explicit rc_override
125 dict with any options you want allows you to override those values at
125 dict with any options you want allows you to override those values at
126 creation time without having to modify the file. This way you can create
126 creation time without having to modify the file. This way you can create
127 embeddable instances configured in any way you want without editing any
127 embeddable instances configured in any way you want without editing any
128 global files (thus keeping your interactive IPython configuration
128 global files (thus keeping your interactive IPython configuration
129 unchanged).
129 unchanged).
130
130
131 Then the ipshell instance can be called anywhere inside your code:
131 Then the ipshell instance can be called anywhere inside your code:
132
132
133 ipshell(header='') -> Opens up an IPython shell.
133 ipshell(header='') -> Opens up an IPython shell.
134
134
135 - header: string printed by the IPython shell upon startup. This can let
135 - header: string printed by the IPython shell upon startup. This can let
136 you know where in your code you are when dropping into the shell. Note
136 you know where in your code you are when dropping into the shell. Note
137 that 'banner' gets prepended to all calls, so header is used for
137 that 'banner' gets prepended to all calls, so header is used for
138 location-specific information.
138 location-specific information.
139
139
140 For more details, see the __call__ method below.
140 For more details, see the __call__ method below.
141
141
142 When the IPython shell is exited with Ctrl-D, normal program execution
142 When the IPython shell is exited with Ctrl-D, normal program execution
143 resumes.
143 resumes.
144
144
145 This functionality was inspired by a posting on comp.lang.python by cmkl
145 This functionality was inspired by a posting on comp.lang.python by cmkl
146 <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
146 <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
147 by the IDL stop/continue commands."""
147 by the IDL stop/continue commands."""
148
148
149 def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None,
149 def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None,
150 user_ns=None):
150 user_ns=None):
151 """Note that argv here is a string, NOT a list."""
151 """Note that argv here is a string, NOT a list."""
152 self.set_banner(banner)
152 self.set_banner(banner)
153 self.set_exit_msg(exit_msg)
153 self.set_exit_msg(exit_msg)
154 self.set_dummy_mode(0)
154 self.set_dummy_mode(0)
155
155
156 # sys.displayhook is a global, we need to save the user's original
156 # sys.displayhook is a global, we need to save the user's original
157 # Don't rely on __displayhook__, as the user may have changed that.
157 # Don't rely on __displayhook__, as the user may have changed that.
158 self.sys_displayhook_ori = sys.displayhook
158 self.sys_displayhook_ori = sys.displayhook
159
159
160 # save readline completer status
160 # save readline completer status
161 try:
161 try:
162 #print 'Save completer',sys.ipcompleter # dbg
162 #print 'Save completer',sys.ipcompleter # dbg
163 self.sys_ipcompleter_ori = sys.ipcompleter
163 self.sys_ipcompleter_ori = sys.ipcompleter
164 except:
164 except:
165 pass # not nested with IPython
165 pass # not nested with IPython
166
166
167 self.IP = make_IPython(argv,rc_override=rc_override,
167 self.IP = make_IPython(argv,rc_override=rc_override,
168 embedded=True,
168 embedded=True,
169 user_ns=user_ns)
169 user_ns=user_ns)
170
170
171 ip = ipapi.IPApi(self.IP)
171 ip = ipapi.IPApi(self.IP)
172 ip.expose_magic("kill_embedded",kill_embedded)
172 ip.expose_magic("kill_embedded",kill_embedded)
173
173
174 # copy our own displayhook also
174 # copy our own displayhook also
175 self.sys_displayhook_embed = sys.displayhook
175 self.sys_displayhook_embed = sys.displayhook
176 # and leave the system's display hook clean
176 # and leave the system's display hook clean
177 sys.displayhook = self.sys_displayhook_ori
177 sys.displayhook = self.sys_displayhook_ori
178 # don't use the ipython crash handler so that user exceptions aren't
178 # don't use the ipython crash handler so that user exceptions aren't
179 # trapped
179 # trapped
180 sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
180 sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
181 mode = self.IP.rc.xmode,
181 mode = self.IP.rc.xmode,
182 call_pdb = self.IP.rc.pdb)
182 call_pdb = self.IP.rc.pdb)
183 self.restore_system_completer()
183 self.restore_system_completer()
184
184
185 def restore_system_completer(self):
185 def restore_system_completer(self):
186 """Restores the readline completer which was in place.
186 """Restores the readline completer which was in place.
187
187
188 This allows embedded IPython within IPython not to disrupt the
188 This allows embedded IPython within IPython not to disrupt the
189 parent's completion.
189 parent's completion.
190 """
190 """
191
191
192 try:
192 try:
193 self.IP.readline.set_completer(self.sys_ipcompleter_ori)
193 self.IP.readline.set_completer(self.sys_ipcompleter_ori)
194 sys.ipcompleter = self.sys_ipcompleter_ori
194 sys.ipcompleter = self.sys_ipcompleter_ori
195 except:
195 except:
196 pass
196 pass
197
197
198 def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
198 def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
199 """Activate the interactive interpreter.
199 """Activate the interactive interpreter.
200
200
201 __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
201 __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
202 the interpreter shell with the given local and global namespaces, and
202 the interpreter shell with the given local and global namespaces, and
203 optionally print a header string at startup.
203 optionally print a header string at startup.
204
204
205 The shell can be globally activated/deactivated using the
205 The shell can be globally activated/deactivated using the
206 set/get_dummy_mode methods. This allows you to turn off a shell used
206 set/get_dummy_mode methods. This allows you to turn off a shell used
207 for debugging globally.
207 for debugging globally.
208
208
209 However, *each* time you call the shell you can override the current
209 However, *each* time you call the shell you can override the current
210 state of dummy_mode with the optional keyword parameter 'dummy'. For
210 state of dummy_mode with the optional keyword parameter 'dummy'. For
211 example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
211 example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
212 can still have a specific call work by making it as IPShell(dummy=0).
212 can still have a specific call work by making it as IPShell(dummy=0).
213
213
214 The optional keyword parameter dummy controls whether the call
214 The optional keyword parameter dummy controls whether the call
215 actually does anything. """
215 actually does anything. """
216
216
217 # If the user has turned it off, go away
217 # If the user has turned it off, go away
218 if not self.IP.embedded_active:
218 if not self.IP.embedded_active:
219 return
219 return
220
220
221 # Normal exits from interactive mode set this flag, so the shell can't
221 # Normal exits from interactive mode set this flag, so the shell can't
222 # re-enter (it checks this variable at the start of interactive mode).
222 # re-enter (it checks this variable at the start of interactive mode).
223 self.IP.exit_now = False
223 self.IP.exit_now = False
224
224
225 # Allow the dummy parameter to override the global __dummy_mode
225 # Allow the dummy parameter to override the global __dummy_mode
226 if dummy or (dummy != 0 and self.__dummy_mode):
226 if dummy or (dummy != 0 and self.__dummy_mode):
227 return
227 return
228
228
229 # Set global subsystems (display,completions) to our values
229 # Set global subsystems (display,completions) to our values
230 sys.displayhook = self.sys_displayhook_embed
230 sys.displayhook = self.sys_displayhook_embed
231 if self.IP.has_readline:
231 if self.IP.has_readline:
232 self.IP.set_completer()
232 self.IP.set_completer()
233
233
234 if self.banner and header:
234 if self.banner and header:
235 format = '%s\n%s\n'
235 format = '%s\n%s\n'
236 else:
236 else:
237 format = '%s%s\n'
237 format = '%s%s\n'
238 banner = format % (self.banner,header)
238 banner = format % (self.banner,header)
239
239
240 # Call the embedding code with a stack depth of 1 so it can skip over
240 # Call the embedding code with a stack depth of 1 so it can skip over
241 # our call and get the original caller's namespaces.
241 # our call and get the original caller's namespaces.
242 self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
242 self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
243
243
244 if self.exit_msg:
244 if self.exit_msg:
245 print self.exit_msg
245 print self.exit_msg
246
246
247 # Restore global systems (display, completion)
247 # Restore global systems (display, completion)
248 sys.displayhook = self.sys_displayhook_ori
248 sys.displayhook = self.sys_displayhook_ori
249 self.restore_system_completer()
249 self.restore_system_completer()
250
250
251 def set_dummy_mode(self,dummy):
251 def set_dummy_mode(self,dummy):
252 """Sets the embeddable shell's dummy mode parameter.
252 """Sets the embeddable shell's dummy mode parameter.
253
253
254 set_dummy_mode(dummy): dummy = 0 or 1.
254 set_dummy_mode(dummy): dummy = 0 or 1.
255
255
256 This parameter is persistent and makes calls to the embeddable shell
256 This parameter is persistent and makes calls to the embeddable shell
257 silently return without performing any action. This allows you to
257 silently return without performing any action. This allows you to
258 globally activate or deactivate a shell you're using with a single call.
258 globally activate or deactivate a shell you're using with a single call.
259
259
260 If you need to manually"""
260 If you need to manually"""
261
261
262 if dummy not in [0,1,False,True]:
262 if dummy not in [0,1,False,True]:
263 raise ValueError,'dummy parameter must be boolean'
263 raise ValueError,'dummy parameter must be boolean'
264 self.__dummy_mode = dummy
264 self.__dummy_mode = dummy
265
265
266 def get_dummy_mode(self):
266 def get_dummy_mode(self):
267 """Return the current value of the dummy mode parameter.
267 """Return the current value of the dummy mode parameter.
268 """
268 """
269 return self.__dummy_mode
269 return self.__dummy_mode
270
270
271 def set_banner(self,banner):
271 def set_banner(self,banner):
272 """Sets the global banner.
272 """Sets the global banner.
273
273
274 This banner gets prepended to every header printed when the shell
274 This banner gets prepended to every header printed when the shell
275 instance is called."""
275 instance is called."""
276
276
277 self.banner = banner
277 self.banner = banner
278
278
279 def set_exit_msg(self,exit_msg):
279 def set_exit_msg(self,exit_msg):
280 """Sets the global exit_msg.
280 """Sets the global exit_msg.
281
281
282 This exit message gets printed upon exiting every time the embedded
282 This exit message gets printed upon exiting every time the embedded
283 shell is called. It is None by default. """
283 shell is called. It is None by default. """
284
284
285 self.exit_msg = exit_msg
285 self.exit_msg = exit_msg
286
286
287 #-----------------------------------------------------------------------------
287 #-----------------------------------------------------------------------------
288 if HAS_CTYPES:
288 if HAS_CTYPES:
289 # Add async exception support. Trick taken from:
289 # Add async exception support. Trick taken from:
290 # http://sebulba.wikispaces.com/recipe+thread2
290 # http://sebulba.wikispaces.com/recipe+thread2
291 def _async_raise(tid, exctype):
291 def _async_raise(tid, exctype):
292 """raises the exception, performs cleanup if needed"""
292 """raises the exception, performs cleanup if needed"""
293 if not inspect.isclass(exctype):
293 if not inspect.isclass(exctype):
294 raise TypeError("Only types can be raised (not instances)")
294 raise TypeError("Only types can be raised (not instances)")
295 # Explicit cast to c_long is necessary for 64-bit support:
295 # Explicit cast to c_long is necessary for 64-bit support:
296 # See https://bugs.launchpad.net/ipython/+bug/237073
296 # See https://bugs.launchpad.net/ipython/+bug/237073
297 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid),
297 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid),
298 ctypes.py_object(exctype))
298 ctypes.py_object(exctype))
299 if res == 0:
299 if res == 0:
300 raise ValueError("invalid thread id")
300 raise ValueError("invalid thread id")
301 elif res != 1:
301 elif res != 1:
302 # If it returns a number greater than one, you're in trouble,
302 # If it returns a number greater than one, you're in trouble,
303 # and you should call it again with exc=NULL to revert the effect
303 # and you should call it again with exc=NULL to revert the effect
304 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
304 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
305 raise SystemError("PyThreadState_SetAsyncExc failed")
305 raise SystemError("PyThreadState_SetAsyncExc failed")
306
306
307 def sigint_handler(signum,stack_frame):
307 def sigint_handler(signum,stack_frame):
308 """Sigint handler for threaded apps.
308 """Sigint handler for threaded apps.
309
309
310 This is a horrible hack to pass information about SIGINT _without_
310 This is a horrible hack to pass information about SIGINT _without_
311 using exceptions, since I haven't been able to properly manage
311 using exceptions, since I haven't been able to properly manage
312 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
312 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
313 done (or at least that's my understanding from a c.l.py thread where
313 done (or at least that's my understanding from a c.l.py thread where
314 this was discussed)."""
314 this was discussed)."""
315
315
316 global KBINT
316 global KBINT
317
317
318 if CODE_RUN:
318 if CODE_RUN:
319 _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
319 _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
320 else:
320 else:
321 KBINT = True
321 KBINT = True
322 print '\nKeyboardInterrupt - Press <Enter> to continue.',
322 print '\nKeyboardInterrupt - Press <Enter> to continue.',
323 Term.cout.flush()
323 Term.cout.flush()
324
324
325 else:
325 else:
326 def sigint_handler(signum,stack_frame):
326 def sigint_handler(signum,stack_frame):
327 """Sigint handler for threaded apps.
327 """Sigint handler for threaded apps.
328
328
329 This is a horrible hack to pass information about SIGINT _without_
329 This is a horrible hack to pass information about SIGINT _without_
330 using exceptions, since I haven't been able to properly manage
330 using exceptions, since I haven't been able to properly manage
331 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
331 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
332 done (or at least that's my understanding from a c.l.py thread where
332 done (or at least that's my understanding from a c.l.py thread where
333 this was discussed)."""
333 this was discussed)."""
334
334
335 global KBINT
335 global KBINT
336
336
337 print '\nKeyboardInterrupt - Press <Enter> to continue.',
337 print '\nKeyboardInterrupt - Press <Enter> to continue.',
338 Term.cout.flush()
338 Term.cout.flush()
339 # Set global flag so that runsource can know that Ctrl-C was hit
339 # Set global flag so that runsource can know that Ctrl-C was hit
340 KBINT = True
340 KBINT = True
341
341
342
342
343 class MTInteractiveShell(InteractiveShell):
343 class MTInteractiveShell(InteractiveShell):
344 """Simple multi-threaded shell."""
344 """Simple multi-threaded shell."""
345
345
346 # Threading strategy taken from:
346 # Threading strategy taken from:
347 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
347 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
348 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
348 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
349 # from the pygtk mailing list, to avoid lockups with system calls.
349 # from the pygtk mailing list, to avoid lockups with system calls.
350
350
351 # class attribute to indicate whether the class supports threads or not.
351 # class attribute to indicate whether the class supports threads or not.
352 # Subclasses with thread support should override this as needed.
352 # Subclasses with thread support should override this as needed.
353 isthreaded = True
353 isthreaded = True
354
354
355 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
355 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
356 user_ns=None,user_global_ns=None,banner2='',
356 user_ns=None,user_global_ns=None,banner2='',
357 gui_timeout=GUI_TIMEOUT,**kw):
357 gui_timeout=GUI_TIMEOUT,**kw):
358 """Similar to the normal InteractiveShell, but with threading control"""
358 """Similar to the normal InteractiveShell, but with threading control"""
359
359
360 InteractiveShell.__init__(self,name,usage,rc,user_ns,
360 InteractiveShell.__init__(self,name,usage,rc,user_ns,
361 user_global_ns,banner2)
361 user_global_ns,banner2)
362
362
363 # Timeout we wait for GUI thread
363 # Timeout we wait for GUI thread
364 self.gui_timeout = gui_timeout
364 self.gui_timeout = gui_timeout
365
365
366 # A queue to hold the code to be executed.
366 # A queue to hold the code to be executed.
367 self.code_queue = Queue.Queue()
367 self.code_queue = Queue.Queue()
368
368
369 # Stuff to do at closing time
369 # Stuff to do at closing time
370 self._kill = None
370 self._kill = None
371 on_kill = kw.get('on_kill', [])
371 on_kill = kw.get('on_kill', [])
372 # Check that all things to kill are callable:
372 # Check that all things to kill are callable:
373 for t in on_kill:
373 for t in on_kill:
374 if not callable(t):
374 if not callable(t):
375 raise TypeError,'on_kill must be a list of callables'
375 raise TypeError,'on_kill must be a list of callables'
376 self.on_kill = on_kill
376 self.on_kill = on_kill
377 # thread identity of the "worker thread" (that may execute code directly)
377 # thread identity of the "worker thread" (that may execute code directly)
378 self.worker_ident = None
378 self.worker_ident = None
379
379
380 def runsource(self, source, filename="<input>", symbol="single"):
380 def runsource(self, source, filename="<input>", symbol="single"):
381 """Compile and run some source in the interpreter.
381 """Compile and run some source in the interpreter.
382
382
383 Modified version of code.py's runsource(), to handle threading issues.
383 Modified version of code.py's runsource(), to handle threading issues.
384 See the original for full docstring details."""
384 See the original for full docstring details."""
385
385
386 global KBINT
386 global KBINT
387
387
388 # If Ctrl-C was typed, we reset the flag and return right away
388 # If Ctrl-C was typed, we reset the flag and return right away
389 if KBINT:
389 if KBINT:
390 KBINT = False
390 KBINT = False
391 return False
391 return False
392
392
393 if self._kill:
393 if self._kill:
394 # can't queue new code if we are being killed
394 # can't queue new code if we are being killed
395 return True
395 return True
396
396
397 try:
397 try:
398 code = self.compile(source, filename, symbol)
398 code = self.compile(source, filename, symbol)
399 except (OverflowError, SyntaxError, ValueError):
399 except (OverflowError, SyntaxError, ValueError):
400 # Case 1
400 # Case 1
401 self.showsyntaxerror(filename)
401 self.showsyntaxerror(filename)
402 return False
402 return False
403
403
404 if code is None:
404 if code is None:
405 # Case 2
405 # Case 2
406 return True
406 return True
407
407
408 # shortcut - if we are in worker thread, or the worker thread is not
408 # shortcut - if we are in worker thread, or the worker thread is not
409 # running, execute directly (to allow recursion and prevent deadlock if
409 # running, execute directly (to allow recursion and prevent deadlock if
410 # code is run early in IPython construction)
410 # code is run early in IPython construction)
411
411
412 if (self.worker_ident is None
412 if (self.worker_ident is None
413 or self.worker_ident == thread.get_ident() ):
413 or self.worker_ident == thread.get_ident() ):
414 InteractiveShell.runcode(self,code)
414 InteractiveShell.runcode(self,code)
415 return False
415 return False
416
416
417 # Case 3
417 # Case 3
418 # Store code in queue, so the execution thread can handle it.
418 # Store code in queue, so the execution thread can handle it.
419
419
420 completed_ev, received_ev = threading.Event(), threading.Event()
420 completed_ev, received_ev = threading.Event(), threading.Event()
421
421
422 self.code_queue.put((code,completed_ev, received_ev))
422 self.code_queue.put((code,completed_ev, received_ev))
423 # first make sure the message was received, with timeout
423 # first make sure the message was received, with timeout
424 received_ev.wait(self.gui_timeout)
424 received_ev.wait(self.gui_timeout)
425 if not received_ev.isSet():
425 if not received_ev.isSet():
426 # the mainloop is dead, start executing code directly
426 # the mainloop is dead, start executing code directly
427 print "Warning: Timeout for mainloop thread exceeded"
427 print "Warning: Timeout for mainloop thread exceeded"
428 print "switching to nonthreaded mode (until mainloop wakes up again)"
428 print "switching to nonthreaded mode (until mainloop wakes up again)"
429 self.worker_ident = None
429 self.worker_ident = None
430 else:
430 else:
431 completed_ev.wait()
431 completed_ev.wait()
432 return False
432 return False
433
433
434 def runcode(self):
434 def runcode(self):
435 """Execute a code object.
435 """Execute a code object.
436
436
437 Multithreaded wrapper around IPython's runcode()."""
437 Multithreaded wrapper around IPython's runcode()."""
438
438
439 global CODE_RUN
439 global CODE_RUN
440
440
441 # we are in worker thread, stash out the id for runsource()
441 # we are in worker thread, stash out the id for runsource()
442 self.worker_ident = thread.get_ident()
442 self.worker_ident = thread.get_ident()
443
443
444 if self._kill:
444 if self._kill:
445 print >>Term.cout, 'Closing threads...',
445 print >>Term.cout, 'Closing threads...',
446 Term.cout.flush()
446 Term.cout.flush()
447 for tokill in self.on_kill:
447 for tokill in self.on_kill:
448 tokill()
448 tokill()
449 print >>Term.cout, 'Done.'
449 print >>Term.cout, 'Done.'
450 # allow kill() to return
450 # allow kill() to return
451 self._kill.set()
451 self._kill.set()
452 return True
452 return True
453
453
454 # Install sigint handler. We do it every time to ensure that if user
454 # Install sigint handler. We do it every time to ensure that if user
455 # code modifies it, we restore our own handling.
455 # code modifies it, we restore our own handling.
456 try:
456 try:
457 signal(SIGINT,sigint_handler)
457 signal(SIGINT,sigint_handler)
458 except SystemError:
458 except SystemError:
459 # This happens under Windows, which seems to have all sorts
459 # This happens under Windows, which seems to have all sorts
460 # of problems with signal handling. Oh well...
460 # of problems with signal handling. Oh well...
461 pass
461 pass
462
462
463 # Flush queue of pending code by calling the run methood of the parent
463 # Flush queue of pending code by calling the run methood of the parent
464 # class with all items which may be in the queue.
464 # class with all items which may be in the queue.
465 code_to_run = None
465 code_to_run = None
466 while 1:
466 while 1:
467 try:
467 try:
468 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
468 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
469 except Queue.Empty:
469 except Queue.Empty:
470 break
470 break
471 received_ev.set()
471 received_ev.set()
472
472
473 # Exceptions need to be raised differently depending on which
473 # Exceptions need to be raised differently depending on which
474 # thread is active. This convoluted try/except is only there to
474 # thread is active. This convoluted try/except is only there to
475 # protect against asynchronous exceptions, to ensure that a KBINT
475 # protect against asynchronous exceptions, to ensure that a KBINT
476 # at the wrong time doesn't deadlock everything. The global
476 # at the wrong time doesn't deadlock everything. The global
477 # CODE_TO_RUN is set to true/false as close as possible to the
477 # CODE_TO_RUN is set to true/false as close as possible to the
478 # runcode() call, so that the KBINT handler is correctly informed.
478 # runcode() call, so that the KBINT handler is correctly informed.
479 try:
479 try:
480 try:
480 try:
481 CODE_RUN = True
481 CODE_RUN = True
482 InteractiveShell.runcode(self,code_to_run)
482 InteractiveShell.runcode(self,code_to_run)
483 except KeyboardInterrupt:
483 except KeyboardInterrupt:
484 print "Keyboard interrupted in mainloop"
484 print "Keyboard interrupted in mainloop"
485 while not self.code_queue.empty():
485 while not self.code_queue.empty():
486 code, ev1,ev2 = self.code_queue.get_nowait()
486 code, ev1,ev2 = self.code_queue.get_nowait()
487 ev1.set()
487 ev1.set()
488 ev2.set()
488 ev2.set()
489 break
489 break
490 finally:
490 finally:
491 CODE_RUN = False
491 CODE_RUN = False
492 # allow runsource() return from wait
492 # allow runsource() return from wait
493 completed_ev.set()
493 completed_ev.set()
494
494
495
495
496 # This MUST return true for gtk threading to work
496 # This MUST return true for gtk threading to work
497 return True
497 return True
498
498
499 def kill(self):
499 def kill(self):
500 """Kill the thread, returning when it has been shut down."""
500 """Kill the thread, returning when it has been shut down."""
501 self._kill = threading.Event()
501 self._kill = threading.Event()
502 self._kill.wait()
502 self._kill.wait()
503
503
504 class MatplotlibShellBase:
504 class MatplotlibShellBase:
505 """Mixin class to provide the necessary modifications to regular IPython
505 """Mixin class to provide the necessary modifications to regular IPython
506 shell classes for matplotlib support.
506 shell classes for matplotlib support.
507
507
508 Given Python's MRO, this should be used as the FIRST class in the
508 Given Python's MRO, this should be used as the FIRST class in the
509 inheritance hierarchy, so that it overrides the relevant methods."""
509 inheritance hierarchy, so that it overrides the relevant methods."""
510
510
511 def _matplotlib_config(self,name,user_ns,user_global_ns=None):
511 def _matplotlib_config(self,name,user_ns,user_global_ns=None):
512 """Return items needed to setup the user's shell with matplotlib"""
512 """Return items needed to setup the user's shell with matplotlib"""
513
513
514 # Initialize matplotlib to interactive mode always
514 # Initialize matplotlib to interactive mode always
515 import matplotlib
515 import matplotlib
516 from matplotlib import backends
516 from matplotlib import backends
517 matplotlib.interactive(True)
517 matplotlib.interactive(True)
518
518
519 def use(arg):
519 def use(arg):
520 """IPython wrapper for matplotlib's backend switcher.
520 """IPython wrapper for matplotlib's backend switcher.
521
521
522 In interactive use, we can not allow switching to a different
522 In interactive use, we can not allow switching to a different
523 interactive backend, since thread conflicts will most likely crash
523 interactive backend, since thread conflicts will most likely crash
524 the python interpreter. This routine does a safety check first,
524 the python interpreter. This routine does a safety check first,
525 and refuses to perform a dangerous switch. It still allows
525 and refuses to perform a dangerous switch. It still allows
526 switching to non-interactive backends."""
526 switching to non-interactive backends."""
527
527
528 if arg in backends.interactive_bk and arg != self.mpl_backend:
528 if arg in backends.interactive_bk and arg != self.mpl_backend:
529 m=('invalid matplotlib backend switch.\n'
529 m=('invalid matplotlib backend switch.\n'
530 'This script attempted to switch to the interactive '
530 'This script attempted to switch to the interactive '
531 'backend: `%s`\n'
531 'backend: `%s`\n'
532 'Your current choice of interactive backend is: `%s`\n\n'
532 'Your current choice of interactive backend is: `%s`\n\n'
533 'Switching interactive matplotlib backends at runtime\n'
533 'Switching interactive matplotlib backends at runtime\n'
534 'would crash the python interpreter, '
534 'would crash the python interpreter, '
535 'and IPython has blocked it.\n\n'
535 'and IPython has blocked it.\n\n'
536 'You need to either change your choice of matplotlib backend\n'
536 'You need to either change your choice of matplotlib backend\n'
537 'by editing your .matplotlibrc file, or run this script as a \n'
537 'by editing your .matplotlibrc file, or run this script as a \n'
538 'standalone file from the command line, not using IPython.\n' %
538 'standalone file from the command line, not using IPython.\n' %
539 (arg,self.mpl_backend) )
539 (arg,self.mpl_backend) )
540 raise RuntimeError, m
540 raise RuntimeError, m
541 else:
541 else:
542 self.mpl_use(arg)
542 self.mpl_use(arg)
543 self.mpl_use._called = True
543 self.mpl_use._called = True
544
544
545 self.matplotlib = matplotlib
545 self.matplotlib = matplotlib
546 self.mpl_backend = matplotlib.rcParams['backend']
546 self.mpl_backend = matplotlib.rcParams['backend']
547
547
548 # we also need to block switching of interactive backends by use()
548 # we also need to block switching of interactive backends by use()
549 self.mpl_use = matplotlib.use
549 self.mpl_use = matplotlib.use
550 self.mpl_use._called = False
550 self.mpl_use._called = False
551 # overwrite the original matplotlib.use with our wrapper
551 # overwrite the original matplotlib.use with our wrapper
552 matplotlib.use = use
552 matplotlib.use = use
553
553
554 # This must be imported last in the matplotlib series, after
554 # This must be imported last in the matplotlib series, after
555 # backend/interactivity choices have been made
555 # backend/interactivity choices have been made
556 import matplotlib.pylab as pylab
556 import matplotlib.pylab as pylab
557 self.pylab = pylab
557 self.pylab = pylab
558
558
559 self.pylab.show._needmain = False
559 self.pylab.show._needmain = False
560 # We need to detect at runtime whether show() is called by the user.
560 # We need to detect at runtime whether show() is called by the user.
561 # For this, we wrap it into a decorator which adds a 'called' flag.
561 # For this, we wrap it into a decorator which adds a 'called' flag.
562 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
562 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
563
563
564 # Build a user namespace initialized with matplotlib/matlab features.
564 # Build a user namespace initialized with matplotlib/matlab features.
565 user_ns, user_global_ns = IPython.ipapi.make_user_namespaces(user_ns,
565 user_ns, user_global_ns = IPython.ipapi.make_user_namespaces(user_ns,
566 user_global_ns)
566 user_global_ns)
567
567
568 # Import numpy as np/pyplot as plt are conventions we're trying to
568 # Import numpy as np/pyplot as plt are conventions we're trying to
569 # somewhat standardize on. Making them available to users by default
569 # somewhat standardize on. Making them available to users by default
570 # will greatly help this.
570 # will greatly help this.
571 exec ("import numpy\n"
571 exec ("import numpy\n"
572 "import numpy as np\n"
572 "import numpy as np\n"
573 "import matplotlib\n"
573 "import matplotlib\n"
574 "import matplotlib.pylab as pylab\n"
574 "import matplotlib.pylab as pylab\n"
575 "try:\n"
575 "try:\n"
576 " import matplotlib.pyplot as plt\n"
576 " import matplotlib.pyplot as plt\n"
577 "except ImportError:\n"
577 "except ImportError:\n"
578 " pass\n"
578 " pass\n"
579 ) in user_ns
579 ) in user_ns
580
580
581 # Build matplotlib info banner
581 # Build matplotlib info banner
582 b="""
582 b="""
583 Welcome to pylab, a matplotlib-based Python environment.
583 Welcome to pylab, a matplotlib-based Python environment.
584 For more information, type 'help(pylab)'.
584 For more information, type 'help(pylab)'.
585 """
585 """
586 return user_ns,user_global_ns,b
586 return user_ns,user_global_ns,b
587
587
588 def mplot_exec(self,fname,*where,**kw):
588 def mplot_exec(self,fname,*where,**kw):
589 """Execute a matplotlib script.
589 """Execute a matplotlib script.
590
590
591 This is a call to execfile(), but wrapped in safeties to properly
591 This is a call to execfile(), but wrapped in safeties to properly
592 handle interactive rendering and backend switching."""
592 handle interactive rendering and backend switching."""
593
593
594 #print '*** Matplotlib runner ***' # dbg
594 #print '*** Matplotlib runner ***' # dbg
595 # turn off rendering until end of script
595 # turn off rendering until end of script
596 isInteractive = self.matplotlib.rcParams['interactive']
596 isInteractive = self.matplotlib.rcParams['interactive']
597 self.matplotlib.interactive(False)
597 self.matplotlib.interactive(False)
598 self.safe_execfile(fname,*where,**kw)
598 self.safe_execfile(fname,*where,**kw)
599 self.matplotlib.interactive(isInteractive)
599 self.matplotlib.interactive(isInteractive)
600 # make rendering call now, if the user tried to do it
600 # make rendering call now, if the user tried to do it
601 if self.pylab.draw_if_interactive.called:
601 if self.pylab.draw_if_interactive.called:
602 self.pylab.draw()
602 self.pylab.draw()
603 self.pylab.draw_if_interactive.called = False
603 self.pylab.draw_if_interactive.called = False
604
604
605 # if a backend switch was performed, reverse it now
605 # if a backend switch was performed, reverse it now
606 if self.mpl_use._called:
606 if self.mpl_use._called:
607 self.matplotlib.rcParams['backend'] = self.mpl_backend
607 self.matplotlib.rcParams['backend'] = self.mpl_backend
608
608
609 @testdec.skip_doctest
609 @testdec.skip_doctest
610 def magic_run(self,parameter_s=''):
610 def magic_run(self,parameter_s=''):
611 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
611 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
612
612
613 # Fix the docstring so users see the original as well
613 # Fix the docstring so users see the original as well
614 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
614 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
615 "\n *** Modified %run for Matplotlib,"
615 "\n *** Modified %run for Matplotlib,"
616 " with proper interactive handling ***")
616 " with proper interactive handling ***")
617
617
618 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
618 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
619 # and multithreaded. Note that these are meant for internal use, the IPShell*
619 # and multithreaded. Note that these are meant for internal use, the IPShell*
620 # classes below are the ones meant for public consumption.
620 # classes below are the ones meant for public consumption.
621
621
622 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
622 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
623 """Single-threaded shell with matplotlib support."""
623 """Single-threaded shell with matplotlib support."""
624
624
625 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
625 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
626 user_ns=None,user_global_ns=None,**kw):
626 user_ns=None,user_global_ns=None,**kw):
627 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
627 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
628 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
628 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
629 banner2=b2,**kw)
629 banner2=b2,**kw)
630
630
631 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
631 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
632 """Multi-threaded shell with matplotlib support."""
632 """Multi-threaded shell with matplotlib support."""
633
633
634 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
634 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
635 user_ns=None,user_global_ns=None, **kw):
635 user_ns=None,user_global_ns=None, **kw):
636 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
636 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
637 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
637 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
638 banner2=b2,**kw)
638 banner2=b2,**kw)
639
639
640 #-----------------------------------------------------------------------------
640 #-----------------------------------------------------------------------------
641 # Utility functions for the different GUI enabled IPShell* classes.
641 # Utility functions for the different GUI enabled IPShell* classes.
642
642
643 def get_tk():
643 def get_tk():
644 """Tries to import Tkinter and returns a withdrawn Tkinter root
644 """Tries to import Tkinter and returns a withdrawn Tkinter root
645 window. If Tkinter is already imported or not available, this
645 window. If Tkinter is already imported or not available, this
646 returns None. This function calls `hijack_tk` underneath.
646 returns None. This function calls `hijack_tk` underneath.
647 """
647 """
648 if not USE_TK or sys.modules.has_key('Tkinter'):
648 if not USE_TK or sys.modules.has_key('Tkinter'):
649 return None
649 return None
650 else:
650 else:
651 try:
651 try:
652 import Tkinter
652 import Tkinter
653 except ImportError:
653 except ImportError:
654 return None
654 return None
655 else:
655 else:
656 hijack_tk()
656 hijack_tk()
657 r = Tkinter.Tk()
657 r = Tkinter.Tk()
658 r.withdraw()
658 r.withdraw()
659 return r
659 return r
660
660
661 def hijack_tk():
661 def hijack_tk():
662 """Modifies Tkinter's mainloop with a dummy so when a module calls
662 """Modifies Tkinter's mainloop with a dummy so when a module calls
663 mainloop, it does not block.
663 mainloop, it does not block.
664
664
665 """
665 """
666 def misc_mainloop(self, n=0):
666 def misc_mainloop(self, n=0):
667 pass
667 pass
668 def tkinter_mainloop(n=0):
668 def tkinter_mainloop(n=0):
669 pass
669 pass
670
670
671 import Tkinter
671 import Tkinter
672 Tkinter.Misc.mainloop = misc_mainloop
672 Tkinter.Misc.mainloop = misc_mainloop
673 Tkinter.mainloop = tkinter_mainloop
673 Tkinter.mainloop = tkinter_mainloop
674
674
675 def update_tk(tk):
675 def update_tk(tk):
676 """Updates the Tkinter event loop. This is typically called from
676 """Updates the Tkinter event loop. This is typically called from
677 the respective WX or GTK mainloops.
677 the respective WX or GTK mainloops.
678 """
678 """
679 if tk:
679 if tk:
680 tk.update()
680 tk.update()
681
681
682 def hijack_wx():
682 def hijack_wx():
683 """Modifies wxPython's MainLoop with a dummy so user code does not
683 """Modifies wxPython's MainLoop with a dummy so user code does not
684 block IPython. The hijacked mainloop function is returned.
684 block IPython. The hijacked mainloop function is returned.
685 """
685 """
686 def dummy_mainloop(*args, **kw):
686 def dummy_mainloop(*args, **kw):
687 pass
687 pass
688
688
689 try:
689 try:
690 import wx
690 import wx
691 except ImportError:
691 except ImportError:
692 # For very old versions of WX
692 # For very old versions of WX
693 import wxPython as wx
693 import wxPython as wx
694
694
695 ver = wx.__version__
695 ver = wx.__version__
696 orig_mainloop = None
696 orig_mainloop = None
697 if ver[:3] >= '2.5':
697 if ver[:3] >= '2.5':
698 import wx
698 import wx
699 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
699 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
700 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
700 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
701 else: raise AttributeError('Could not find wx core module')
701 else: raise AttributeError('Could not find wx core module')
702 orig_mainloop = core.PyApp_MainLoop
702 orig_mainloop = core.PyApp_MainLoop
703 core.PyApp_MainLoop = dummy_mainloop
703 core.PyApp_MainLoop = dummy_mainloop
704 elif ver[:3] == '2.4':
704 elif ver[:3] == '2.4':
705 orig_mainloop = wx.wxc.wxPyApp_MainLoop
705 orig_mainloop = wx.wxc.wxPyApp_MainLoop
706 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
706 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
707 else:
707 else:
708 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
708 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
709 return orig_mainloop
709 return orig_mainloop
710
710
711 def hijack_gtk():
711 def hijack_gtk():
712 """Modifies pyGTK's mainloop with a dummy so user code does not
712 """Modifies pyGTK's mainloop with a dummy so user code does not
713 block IPython. This function returns the original `gtk.mainloop`
713 block IPython. This function returns the original `gtk.mainloop`
714 function that has been hijacked.
714 function that has been hijacked.
715 """
715 """
716 def dummy_mainloop(*args, **kw):
716 def dummy_mainloop(*args, **kw):
717 pass
717 pass
718 import gtk
718 import gtk
719 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
719 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
720 else: orig_mainloop = gtk.mainloop
720 else: orig_mainloop = gtk.mainloop
721 gtk.mainloop = dummy_mainloop
721 gtk.mainloop = dummy_mainloop
722 gtk.main = dummy_mainloop
722 gtk.main = dummy_mainloop
723 return orig_mainloop
723 return orig_mainloop
724
724
725 def hijack_qt():
725 def hijack_qt():
726 """Modifies PyQt's mainloop with a dummy so user code does not
726 """Modifies PyQt's mainloop with a dummy so user code does not
727 block IPython. This function returns the original
727 block IPython. This function returns the original
728 `qt.qApp.exec_loop` function that has been hijacked.
728 `qt.qApp.exec_loop` function that has been hijacked.
729 """
729 """
730 def dummy_mainloop(*args, **kw):
730 def dummy_mainloop(*args, **kw):
731 pass
731 pass
732 import qt
732 import qt
733 orig_mainloop = qt.qApp.exec_loop
733 orig_mainloop = qt.qApp.exec_loop
734 qt.qApp.exec_loop = dummy_mainloop
734 qt.qApp.exec_loop = dummy_mainloop
735 qt.QApplication.exec_loop = dummy_mainloop
735 qt.QApplication.exec_loop = dummy_mainloop
736 return orig_mainloop
736 return orig_mainloop
737
737
738 def hijack_qt4():
738 def hijack_qt4():
739 """Modifies PyQt4's mainloop with a dummy so user code does not
739 """Modifies PyQt4's mainloop with a dummy so user code does not
740 block IPython. This function returns the original
740 block IPython. This function returns the original
741 `QtGui.qApp.exec_` function that has been hijacked.
741 `QtGui.qApp.exec_` function that has been hijacked.
742 """
742 """
743 def dummy_mainloop(*args, **kw):
743 def dummy_mainloop(*args, **kw):
744 pass
744 pass
745 from PyQt4 import QtGui, QtCore
745 from PyQt4 import QtGui, QtCore
746 orig_mainloop = QtGui.qApp.exec_
746 orig_mainloop = QtGui.qApp.exec_
747 QtGui.qApp.exec_ = dummy_mainloop
747 QtGui.qApp.exec_ = dummy_mainloop
748 QtGui.QApplication.exec_ = dummy_mainloop
748 QtGui.QApplication.exec_ = dummy_mainloop
749 QtCore.QCoreApplication.exec_ = dummy_mainloop
749 QtCore.QCoreApplication.exec_ = dummy_mainloop
750 return orig_mainloop
750 return orig_mainloop
751
751
752 #-----------------------------------------------------------------------------
752 #-----------------------------------------------------------------------------
753 # The IPShell* classes below are the ones meant to be run by external code as
753 # The IPShell* classes below are the ones meant to be run by external code as
754 # IPython instances. Note that unless a specific threading strategy is
754 # IPython instances. Note that unless a specific threading strategy is
755 # desired, the factory function start() below should be used instead (it
755 # desired, the factory function start() below should be used instead (it
756 # selects the proper threaded class).
756 # selects the proper threaded class).
757
757
758 class IPThread(threading.Thread):
758 class IPThread(threading.Thread):
759 def run(self):
759 def run(self):
760 self.IP.mainloop(self._banner)
760 self.IP.mainloop(self._banner)
761 self.IP.kill()
761 self.IP.kill()
762
762
763 class IPShellGTK(IPThread):
763 class IPShellGTK(IPThread):
764 """Run a gtk mainloop() in a separate thread.
764 """Run a gtk mainloop() in a separate thread.
765
765
766 Python commands can be passed to the thread where they will be executed.
766 Python commands can be passed to the thread where they will be executed.
767 This is implemented by periodically checking for passed code using a
767 This is implemented by periodically checking for passed code using a
768 GTK timeout callback."""
768 GTK timeout callback."""
769
769
770 TIMEOUT = 100 # Millisecond interval between timeouts.
770 TIMEOUT = 100 # Millisecond interval between timeouts.
771
771
772 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
772 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
773 debug=1,shell_class=MTInteractiveShell):
773 debug=1,shell_class=MTInteractiveShell):
774
774
775 import gtk
775 import gtk
776 # Check for set_interactive, coming up in new pygtk.
776 ## # Check for set_interactive, coming up in new pygtk.
777 # Disable it so that this code works, but notify
777 ## # Disable it so that this code works, but notify
778 # the user that he has a better option as well.
778 ## # the user that he has a better option as well.
779 # XXX TODO better support when set_interactive is released
779 ## # XXX TODO better support when set_interactive is released
780 try:
780 ## try:
781 gtk.set_interactive(False)
781 ## gtk.set_interactive(False)
782 print "Your PyGtk has set_interactive(), so you can use the"
782 ## print "Your PyGtk has set_interactive(), so you can use the"
783 print "more stable single-threaded Gtk mode."
783 ## print "more stable single-threaded Gtk mode."
784 print "See https://bugs.launchpad.net/ipython/+bug/270856"
784 ## print "See https://bugs.launchpad.net/ipython/+bug/270856"
785 except AttributeError:
785 ## except AttributeError:
786 pass
786 ## pass
787
787
788 self.gtk = gtk
788 self.gtk = gtk
789 self.gtk_mainloop = hijack_gtk()
789 self.gtk_mainloop = hijack_gtk()
790
790
791 # Allows us to use both Tk and GTK.
791 # Allows us to use both Tk and GTK.
792 self.tk = get_tk()
792 self.tk = get_tk()
793
793
794 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
794 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
795 else: mainquit = self.gtk.mainquit
795 else: mainquit = self.gtk.mainquit
796
796
797 self.IP = make_IPython(argv,user_ns=user_ns,
797 self.IP = make_IPython(argv,user_ns=user_ns,
798 user_global_ns=user_global_ns,
798 user_global_ns=user_global_ns,
799 debug=debug,
799 debug=debug,
800 shell_class=shell_class,
800 shell_class=shell_class,
801 on_kill=[mainquit])
801 on_kill=[mainquit])
802
802
803 # HACK: slot for banner in self; it will be passed to the mainloop
803 # HACK: slot for banner in self; it will be passed to the mainloop
804 # method only and .run() needs it. The actual value will be set by
804 # method only and .run() needs it. The actual value will be set by
805 # .mainloop().
805 # .mainloop().
806 self._banner = None
806 self._banner = None
807
807
808 threading.Thread.__init__(self)
808 threading.Thread.__init__(self)
809
809
810 def mainloop(self,sys_exit=0,banner=None):
810 def mainloop(self,sys_exit=0,banner=None):
811
811
812 self._banner = banner
812 self._banner = banner
813
813
814 if self.gtk.pygtk_version >= (2,4,0):
814 if self.gtk.pygtk_version >= (2,4,0):
815 import gobject
815 import gobject
816 gobject.idle_add(self.on_timer)
816 gobject.idle_add(self.on_timer)
817 else:
817 else:
818 self.gtk.idle_add(self.on_timer)
818 self.gtk.idle_add(self.on_timer)
819
819
820 if sys.platform != 'win32':
820 if sys.platform != 'win32':
821 try:
821 try:
822 if self.gtk.gtk_version[0] >= 2:
822 if self.gtk.gtk_version[0] >= 2:
823 self.gtk.gdk.threads_init()
823 self.gtk.gdk.threads_init()
824 except AttributeError:
824 except AttributeError:
825 pass
825 pass
826 except RuntimeError:
826 except RuntimeError:
827 error('Your pyGTK likely has not been compiled with '
827 error('Your pyGTK likely has not been compiled with '
828 'threading support.\n'
828 'threading support.\n'
829 'The exception printout is below.\n'
829 'The exception printout is below.\n'
830 'You can either rebuild pyGTK with threads, or '
830 'You can either rebuild pyGTK with threads, or '
831 'try using \n'
831 'try using \n'
832 'matplotlib with a different backend (like Tk or WX).\n'
832 'matplotlib with a different backend (like Tk or WX).\n'
833 'Note that matplotlib will most likely not work in its '
833 'Note that matplotlib will most likely not work in its '
834 'current state!')
834 'current state!')
835 self.IP.InteractiveTB()
835 self.IP.InteractiveTB()
836
836
837 self.start()
837 self.start()
838 self.gtk.gdk.threads_enter()
838 self.gtk.gdk.threads_enter()
839 self.gtk_mainloop()
839 self.gtk_mainloop()
840 self.gtk.gdk.threads_leave()
840 self.gtk.gdk.threads_leave()
841 self.join()
841 self.join()
842
842
843 def on_timer(self):
843 def on_timer(self):
844 """Called when GTK is idle.
844 """Called when GTK is idle.
845
845
846 Must return True always, otherwise GTK stops calling it"""
846 Must return True always, otherwise GTK stops calling it"""
847
847
848 update_tk(self.tk)
848 update_tk(self.tk)
849 self.IP.runcode()
849 self.IP.runcode()
850 time.sleep(0.01)
850 time.sleep(0.01)
851 return True
851 return True
852
852
853
853
854 class IPShellWX(IPThread):
854 class IPShellWX(IPThread):
855 """Run a wx mainloop() in a separate thread.
855 """Run a wx mainloop() in a separate thread.
856
856
857 Python commands can be passed to the thread where they will be executed.
857 Python commands can be passed to the thread where they will be executed.
858 This is implemented by periodically checking for passed code using a
858 This is implemented by periodically checking for passed code using a
859 GTK timeout callback."""
859 GTK timeout callback."""
860
860
861 TIMEOUT = 100 # Millisecond interval between timeouts.
861 TIMEOUT = 100 # Millisecond interval between timeouts.
862
862
863 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
863 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
864 debug=1,shell_class=MTInteractiveShell):
864 debug=1,shell_class=MTInteractiveShell):
865
865
866 self.IP = make_IPython(argv,user_ns=user_ns,
866 self.IP = make_IPython(argv,user_ns=user_ns,
867 user_global_ns=user_global_ns,
867 user_global_ns=user_global_ns,
868 debug=debug,
868 debug=debug,
869 shell_class=shell_class,
869 shell_class=shell_class,
870 on_kill=[self.wxexit])
870 on_kill=[self.wxexit])
871
871
872 wantedwxversion=self.IP.rc.wxversion
872 wantedwxversion=self.IP.rc.wxversion
873 if wantedwxversion!="0":
873 if wantedwxversion!="0":
874 try:
874 try:
875 import wxversion
875 import wxversion
876 except ImportError:
876 except ImportError:
877 error('The wxversion module is needed for WX version selection')
877 error('The wxversion module is needed for WX version selection')
878 else:
878 else:
879 try:
879 try:
880 wxversion.select(wantedwxversion)
880 wxversion.select(wantedwxversion)
881 except:
881 except:
882 self.IP.InteractiveTB()
882 self.IP.InteractiveTB()
883 error('Requested wxPython version %s could not be loaded' %
883 error('Requested wxPython version %s could not be loaded' %
884 wantedwxversion)
884 wantedwxversion)
885
885
886 import wx
886 import wx
887
887
888 threading.Thread.__init__(self)
888 threading.Thread.__init__(self)
889 self.wx = wx
889 self.wx = wx
890 self.wx_mainloop = hijack_wx()
890 self.wx_mainloop = hijack_wx()
891
891
892 # Allows us to use both Tk and GTK.
892 # Allows us to use both Tk and GTK.
893 self.tk = get_tk()
893 self.tk = get_tk()
894
894
895 # HACK: slot for banner in self; it will be passed to the mainloop
895 # HACK: slot for banner in self; it will be passed to the mainloop
896 # method only and .run() needs it. The actual value will be set by
896 # method only and .run() needs it. The actual value will be set by
897 # .mainloop().
897 # .mainloop().
898 self._banner = None
898 self._banner = None
899
899
900 self.app = None
900 self.app = None
901
901
902 def wxexit(self, *args):
902 def wxexit(self, *args):
903 if self.app is not None:
903 if self.app is not None:
904 self.app.agent.timer.Stop()
904 self.app.agent.timer.Stop()
905 self.app.ExitMainLoop()
905 self.app.ExitMainLoop()
906
906
907 def mainloop(self,sys_exit=0,banner=None):
907 def mainloop(self,sys_exit=0,banner=None):
908
908
909 self._banner = banner
909 self._banner = banner
910
910
911 self.start()
911 self.start()
912
912
913 class TimerAgent(self.wx.MiniFrame):
913 class TimerAgent(self.wx.MiniFrame):
914 wx = self.wx
914 wx = self.wx
915 IP = self.IP
915 IP = self.IP
916 tk = self.tk
916 tk = self.tk
917 def __init__(self, parent, interval):
917 def __init__(self, parent, interval):
918 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
918 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
919 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
919 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
920 size=(100, 100),style=style)
920 size=(100, 100),style=style)
921 self.Show(False)
921 self.Show(False)
922 self.interval = interval
922 self.interval = interval
923 self.timerId = self.wx.NewId()
923 self.timerId = self.wx.NewId()
924
924
925 def StartWork(self):
925 def StartWork(self):
926 self.timer = self.wx.Timer(self, self.timerId)
926 self.timer = self.wx.Timer(self, self.timerId)
927 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
927 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
928 self.timer.Start(self.interval)
928 self.timer.Start(self.interval)
929
929
930 def OnTimer(self, event):
930 def OnTimer(self, event):
931 update_tk(self.tk)
931 update_tk(self.tk)
932 self.IP.runcode()
932 self.IP.runcode()
933
933
934 class App(self.wx.App):
934 class App(self.wx.App):
935 wx = self.wx
935 wx = self.wx
936 TIMEOUT = self.TIMEOUT
936 TIMEOUT = self.TIMEOUT
937 def OnInit(self):
937 def OnInit(self):
938 'Create the main window and insert the custom frame'
938 'Create the main window and insert the custom frame'
939 self.agent = TimerAgent(None, self.TIMEOUT)
939 self.agent = TimerAgent(None, self.TIMEOUT)
940 self.agent.Show(False)
940 self.agent.Show(False)
941 self.agent.StartWork()
941 self.agent.StartWork()
942 return True
942 return True
943
943
944 self.app = App(redirect=False)
944 self.app = App(redirect=False)
945 self.wx_mainloop(self.app)
945 self.wx_mainloop(self.app)
946 self.join()
946 self.join()
947
947
948
948
949 class IPShellQt(IPThread):
949 class IPShellQt(IPThread):
950 """Run a Qt event loop in a separate thread.
950 """Run a Qt event loop in a separate thread.
951
951
952 Python commands can be passed to the thread where they will be executed.
952 Python commands can be passed to the thread where they will be executed.
953 This is implemented by periodically checking for passed code using a
953 This is implemented by periodically checking for passed code using a
954 Qt timer / slot."""
954 Qt timer / slot."""
955
955
956 TIMEOUT = 100 # Millisecond interval between timeouts.
956 TIMEOUT = 100 # Millisecond interval between timeouts.
957
957
958 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
958 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
959 debug=0, shell_class=MTInteractiveShell):
959 debug=0, shell_class=MTInteractiveShell):
960
960
961 import qt
961 import qt
962
962
963 self.exec_loop = hijack_qt()
963 self.exec_loop = hijack_qt()
964
964
965 # Allows us to use both Tk and QT.
965 # Allows us to use both Tk and QT.
966 self.tk = get_tk()
966 self.tk = get_tk()
967
967
968 self.IP = make_IPython(argv,
968 self.IP = make_IPython(argv,
969 user_ns=user_ns,
969 user_ns=user_ns,
970 user_global_ns=user_global_ns,
970 user_global_ns=user_global_ns,
971 debug=debug,
971 debug=debug,
972 shell_class=shell_class,
972 shell_class=shell_class,
973 on_kill=[qt.qApp.exit])
973 on_kill=[qt.qApp.exit])
974
974
975 # HACK: slot for banner in self; it will be passed to the mainloop
975 # HACK: slot for banner in self; it will be passed to the mainloop
976 # method only and .run() needs it. The actual value will be set by
976 # method only and .run() needs it. The actual value will be set by
977 # .mainloop().
977 # .mainloop().
978 self._banner = None
978 self._banner = None
979
979
980 threading.Thread.__init__(self)
980 threading.Thread.__init__(self)
981
981
982 def mainloop(self, sys_exit=0, banner=None):
982 def mainloop(self, sys_exit=0, banner=None):
983
983
984 import qt
984 import qt
985
985
986 self._banner = banner
986 self._banner = banner
987
987
988 if qt.QApplication.startingUp():
988 if qt.QApplication.startingUp():
989 a = qt.QApplication(sys.argv)
989 a = qt.QApplication(sys.argv)
990
990
991 self.timer = qt.QTimer()
991 self.timer = qt.QTimer()
992 qt.QObject.connect(self.timer,
992 qt.QObject.connect(self.timer,
993 qt.SIGNAL('timeout()'),
993 qt.SIGNAL('timeout()'),
994 self.on_timer)
994 self.on_timer)
995
995
996 self.start()
996 self.start()
997 self.timer.start(self.TIMEOUT, True)
997 self.timer.start(self.TIMEOUT, True)
998 while True:
998 while True:
999 if self.IP._kill: break
999 if self.IP._kill: break
1000 self.exec_loop()
1000 self.exec_loop()
1001 self.join()
1001 self.join()
1002
1002
1003 def on_timer(self):
1003 def on_timer(self):
1004 update_tk(self.tk)
1004 update_tk(self.tk)
1005 result = self.IP.runcode()
1005 result = self.IP.runcode()
1006 self.timer.start(self.TIMEOUT, True)
1006 self.timer.start(self.TIMEOUT, True)
1007 return result
1007 return result
1008
1008
1009
1009
1010 class IPShellQt4(IPThread):
1010 class IPShellQt4(IPThread):
1011 """Run a Qt event loop in a separate thread.
1011 """Run a Qt event loop in a separate thread.
1012
1012
1013 Python commands can be passed to the thread where they will be executed.
1013 Python commands can be passed to the thread where they will be executed.
1014 This is implemented by periodically checking for passed code using a
1014 This is implemented by periodically checking for passed code using a
1015 Qt timer / slot."""
1015 Qt timer / slot."""
1016
1016
1017 TIMEOUT = 100 # Millisecond interval between timeouts.
1017 TIMEOUT = 100 # Millisecond interval between timeouts.
1018
1018
1019 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
1019 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
1020 debug=0, shell_class=MTInteractiveShell):
1020 debug=0, shell_class=MTInteractiveShell):
1021
1021
1022 from PyQt4 import QtCore, QtGui
1022 from PyQt4 import QtCore, QtGui
1023
1023
1024 try:
1024 try:
1025 # present in PyQt4-4.2.1 or later
1025 # present in PyQt4-4.2.1 or later
1026 QtCore.pyqtRemoveInputHook()
1026 QtCore.pyqtRemoveInputHook()
1027 except AttributeError:
1027 except AttributeError:
1028 pass
1028 pass
1029
1029
1030 if QtCore.PYQT_VERSION_STR == '4.3':
1030 if QtCore.PYQT_VERSION_STR == '4.3':
1031 warn('''PyQt4 version 4.3 detected.
1031 warn('''PyQt4 version 4.3 detected.
1032 If you experience repeated threading warnings, please update PyQt4.
1032 If you experience repeated threading warnings, please update PyQt4.
1033 ''')
1033 ''')
1034
1034
1035 self.exec_ = hijack_qt4()
1035 self.exec_ = hijack_qt4()
1036
1036
1037 # Allows us to use both Tk and QT.
1037 # Allows us to use both Tk and QT.
1038 self.tk = get_tk()
1038 self.tk = get_tk()
1039
1039
1040 self.IP = make_IPython(argv,
1040 self.IP = make_IPython(argv,
1041 user_ns=user_ns,
1041 user_ns=user_ns,
1042 user_global_ns=user_global_ns,
1042 user_global_ns=user_global_ns,
1043 debug=debug,
1043 debug=debug,
1044 shell_class=shell_class,
1044 shell_class=shell_class,
1045 on_kill=[QtGui.qApp.exit])
1045 on_kill=[QtGui.qApp.exit])
1046
1046
1047 # HACK: slot for banner in self; it will be passed to the mainloop
1047 # HACK: slot for banner in self; it will be passed to the mainloop
1048 # method only and .run() needs it. The actual value will be set by
1048 # method only and .run() needs it. The actual value will be set by
1049 # .mainloop().
1049 # .mainloop().
1050 self._banner = None
1050 self._banner = None
1051
1051
1052 threading.Thread.__init__(self)
1052 threading.Thread.__init__(self)
1053
1053
1054 def mainloop(self, sys_exit=0, banner=None):
1054 def mainloop(self, sys_exit=0, banner=None):
1055
1055
1056 from PyQt4 import QtCore, QtGui
1056 from PyQt4 import QtCore, QtGui
1057
1057
1058 self._banner = banner
1058 self._banner = banner
1059
1059
1060 if QtGui.QApplication.startingUp():
1060 if QtGui.QApplication.startingUp():
1061 a = QtGui.QApplication(sys.argv)
1061 a = QtGui.QApplication(sys.argv)
1062
1062
1063 self.timer = QtCore.QTimer()
1063 self.timer = QtCore.QTimer()
1064 QtCore.QObject.connect(self.timer,
1064 QtCore.QObject.connect(self.timer,
1065 QtCore.SIGNAL('timeout()'),
1065 QtCore.SIGNAL('timeout()'),
1066 self.on_timer)
1066 self.on_timer)
1067
1067
1068 self.start()
1068 self.start()
1069 self.timer.start(self.TIMEOUT)
1069 self.timer.start(self.TIMEOUT)
1070 while True:
1070 while True:
1071 if self.IP._kill: break
1071 if self.IP._kill: break
1072 self.exec_()
1072 self.exec_()
1073 self.join()
1073 self.join()
1074
1074
1075 def on_timer(self):
1075 def on_timer(self):
1076 update_tk(self.tk)
1076 update_tk(self.tk)
1077 result = self.IP.runcode()
1077 result = self.IP.runcode()
1078 self.timer.start(self.TIMEOUT)
1078 self.timer.start(self.TIMEOUT)
1079 return result
1079 return result
1080
1080
1081
1081
1082 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1082 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1083 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1083 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1084 def _load_pylab(user_ns):
1084 def _load_pylab(user_ns):
1085 """Allow users to disable pulling all of pylab into the top-level
1085 """Allow users to disable pulling all of pylab into the top-level
1086 namespace.
1086 namespace.
1087
1087
1088 This little utility must be called AFTER the actual ipython instance is
1088 This little utility must be called AFTER the actual ipython instance is
1089 running, since only then will the options file have been fully parsed."""
1089 running, since only then will the options file have been fully parsed."""
1090
1090
1091 ip = IPython.ipapi.get()
1091 ip = IPython.ipapi.get()
1092 if ip.options.pylab_import_all:
1092 if ip.options.pylab_import_all:
1093 ip.ex("from matplotlib.pylab import *")
1093 ip.ex("from matplotlib.pylab import *")
1094 ip.IP.user_config_ns.update(ip.user_ns)
1094 ip.IP.user_config_ns.update(ip.user_ns)
1095
1095
1096
1096
1097 class IPShellMatplotlib(IPShell):
1097 class IPShellMatplotlib(IPShell):
1098 """Subclass IPShell with MatplotlibShell as the internal shell.
1098 """Subclass IPShell with MatplotlibShell as the internal shell.
1099
1099
1100 Single-threaded class, meant for the Tk* and FLTK* backends.
1100 Single-threaded class, meant for the Tk* and FLTK* backends.
1101
1101
1102 Having this on a separate class simplifies the external driver code."""
1102 Having this on a separate class simplifies the external driver code."""
1103
1103
1104 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1104 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1105 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1105 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1106 shell_class=MatplotlibShell)
1106 shell_class=MatplotlibShell)
1107 _load_pylab(self.IP.user_ns)
1107 _load_pylab(self.IP.user_ns)
1108
1108
1109 class IPShellMatplotlibGTK(IPShellGTK):
1109 class IPShellMatplotlibGTK(IPShellGTK):
1110 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1110 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1111
1111
1112 Multi-threaded class, meant for the GTK* backends."""
1112 Multi-threaded class, meant for the GTK* backends."""
1113
1113
1114 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1114 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1115 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1115 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1116 shell_class=MatplotlibMTShell)
1116 shell_class=MatplotlibMTShell)
1117 _load_pylab(self.IP.user_ns)
1117 _load_pylab(self.IP.user_ns)
1118
1118
1119 class IPShellMatplotlibWX(IPShellWX):
1119 class IPShellMatplotlibWX(IPShellWX):
1120 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1120 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1121
1121
1122 Multi-threaded class, meant for the WX* backends."""
1122 Multi-threaded class, meant for the WX* backends."""
1123
1123
1124 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1124 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1125 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1125 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1126 shell_class=MatplotlibMTShell)
1126 shell_class=MatplotlibMTShell)
1127 _load_pylab(self.IP.user_ns)
1127 _load_pylab(self.IP.user_ns)
1128
1128
1129 class IPShellMatplotlibQt(IPShellQt):
1129 class IPShellMatplotlibQt(IPShellQt):
1130 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1130 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1131
1131
1132 Multi-threaded class, meant for the Qt* backends."""
1132 Multi-threaded class, meant for the Qt* backends."""
1133
1133
1134 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1134 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1135 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1135 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1136 shell_class=MatplotlibMTShell)
1136 shell_class=MatplotlibMTShell)
1137 _load_pylab(self.IP.user_ns)
1137 _load_pylab(self.IP.user_ns)
1138
1138
1139 class IPShellMatplotlibQt4(IPShellQt4):
1139 class IPShellMatplotlibQt4(IPShellQt4):
1140 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1140 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1141
1141
1142 Multi-threaded class, meant for the Qt4* backends."""
1142 Multi-threaded class, meant for the Qt4* backends."""
1143
1143
1144 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1144 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1145 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1145 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1146 shell_class=MatplotlibMTShell)
1146 shell_class=MatplotlibMTShell)
1147 _load_pylab(self.IP.user_ns)
1147 _load_pylab(self.IP.user_ns)
1148
1148
1149 #-----------------------------------------------------------------------------
1149 #-----------------------------------------------------------------------------
1150 # Factory functions to actually start the proper thread-aware shell
1150 # Factory functions to actually start the proper thread-aware shell
1151
1151
1152 def check_gtk(mode):
1153 import gtk
1154 if hasattr(gtk,'set_interactive'):
1155 gtk.set_interactive(False)
1156 return 'tkthread'
1157 else:
1158 return mode
1159
1160
1152 def _select_shell(argv):
1161 def _select_shell(argv):
1153 """Select a shell from the given argv vector.
1162 """Select a shell from the given argv vector.
1154
1163
1155 This function implements the threading selection policy, allowing runtime
1164 This function implements the threading selection policy, allowing runtime
1156 control of the threading mode, both for general users and for matplotlib.
1165 control of the threading mode, both for general users and for matplotlib.
1157
1166
1158 Return:
1167 Return:
1159 Shell class to be instantiated for runtime operation.
1168 Shell class to be instantiated for runtime operation.
1160 """
1169 """
1161
1170
1162 global USE_TK
1171 global USE_TK
1163
1172
1164 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1173 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1165 'wthread' : IPShellMatplotlibWX,
1174 'wthread' : IPShellMatplotlibWX,
1166 'qthread' : IPShellMatplotlibQt,
1175 'qthread' : IPShellMatplotlibQt,
1167 'q4thread' : IPShellMatplotlibQt4,
1176 'q4thread' : IPShellMatplotlibQt4,
1168 'tkthread' : IPShellMatplotlib, # Tk is built-in
1177 'tkthread' : IPShellMatplotlib, # Tk is built-in
1169 }
1178 }
1170
1179
1171 th_shell = {'gthread' : IPShellGTK,
1180 th_shell = {'gthread' : IPShellGTK,
1172 'wthread' : IPShellWX,
1181 'wthread' : IPShellWX,
1173 'qthread' : IPShellQt,
1182 'qthread' : IPShellQt,
1174 'q4thread' : IPShellQt4,
1183 'q4thread' : IPShellQt4,
1175 'tkthread' : IPShell, # Tk is built-in
1184 'tkthread' : IPShell, # Tk is built-in
1176 }
1185 }
1177
1186
1178 backends = {'gthread' : 'GTKAgg',
1187 backends = {'gthread' : 'GTKAgg',
1179 'wthread' : 'WXAgg',
1188 'wthread' : 'WXAgg',
1180 'qthread' : 'QtAgg',
1189 'qthread' : 'QtAgg',
1181 'q4thread' :'Qt4Agg',
1190 'q4thread' :'Qt4Agg',
1182 'tkthread' :'TkAgg',
1191 'tkthread' :'TkAgg',
1183 }
1192 }
1184
1193
1185 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1194 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1186 'tkthread'])
1195 'tkthread'])
1187 user_opts = set([s.replace('-','') for s in argv[:3]])
1196 user_opts = set([s.replace('-','') for s in argv[:3]])
1188 special_opts = user_opts & all_opts
1197 special_opts = user_opts & all_opts
1189
1198
1190 if 'tk' in special_opts:
1199 if 'tk' in special_opts:
1191 USE_TK = True
1200 USE_TK = True
1192 special_opts.remove('tk')
1201 special_opts.remove('tk')
1193
1202
1194 if 'pylab' in special_opts:
1203 if 'pylab' in special_opts:
1195
1204
1196 try:
1205 try:
1197 import matplotlib
1206 import matplotlib
1198 except ImportError:
1207 except ImportError:
1199 error('matplotlib could NOT be imported! Starting normal IPython.')
1208 error('matplotlib could NOT be imported! Starting normal IPython.')
1200 return IPShell
1209 return IPShell
1201
1210
1202 special_opts.remove('pylab')
1211 special_opts.remove('pylab')
1203 # If there's any option left, it means the user wants to force the
1212 # If there's any option left, it means the user wants to force the
1204 # threading backend, else it's auto-selected from the rc file
1213 # threading backend, else it's auto-selected from the rc file
1205 if special_opts:
1214 if special_opts:
1206 th_mode = special_opts.pop()
1215 th_mode = special_opts.pop()
1207 matplotlib.rcParams['backend'] = backends[th_mode]
1216 matplotlib.rcParams['backend'] = backends[th_mode]
1208 else:
1217 else:
1209 backend = matplotlib.rcParams['backend']
1218 backend = matplotlib.rcParams['backend']
1210 if backend.startswith('GTK'):
1219 if backend.startswith('GTK'):
1211 th_mode = 'gthread'
1220 th_mode = 'gthread'
1212 elif backend.startswith('WX'):
1221 elif backend.startswith('WX'):
1213 th_mode = 'wthread'
1222 th_mode = 'wthread'
1214 elif backend.startswith('Qt4'):
1223 elif backend.startswith('Qt4'):
1215 th_mode = 'q4thread'
1224 th_mode = 'q4thread'
1216 elif backend.startswith('Qt'):
1225 elif backend.startswith('Qt'):
1217 th_mode = 'qthread'
1226 th_mode = 'qthread'
1218 else:
1227 else:
1219 # Any other backend, use plain Tk
1228 # Any other backend, use plain Tk
1220 th_mode = 'tkthread'
1229 th_mode = 'tkthread'
1230
1231 # New versions of pygtk don't need the brittle threaded support.
1232 th_mode = check_gtk(th_mode)
1221
1233
1222 return mpl_shell[th_mode]
1234 return mpl_shell[th_mode]
1223 else:
1235 else:
1224 # No pylab requested, just plain threads
1236 # No pylab requested, just plain threads
1225 try:
1237 try:
1226 th_mode = special_opts.pop()
1238 th_mode = special_opts.pop()
1227 except KeyError:
1239 except KeyError:
1228 th_mode = 'tkthread'
1240 th_mode = 'tkthread'
1241
1242 # New versions of pygtk don't need the brittle threaded support.
1243 th_mode = check_gtk(th_mode)
1229 return th_shell[th_mode]
1244 return th_shell[th_mode]
1230
1245
1231
1246
1232 # This is the one which should be called by external code.
1247 # This is the one which should be called by external code.
1233 def start(user_ns = None):
1248 def start(user_ns = None):
1234 """Return a running shell instance, dealing with threading options.
1249 """Return a running shell instance, dealing with threading options.
1235
1250
1236 This is a factory function which will instantiate the proper IPython shell
1251 This is a factory function which will instantiate the proper IPython shell
1237 based on the user's threading choice. Such a selector is needed because
1252 based on the user's threading choice. Such a selector is needed because
1238 different GUI toolkits require different thread handling details."""
1253 different GUI toolkits require different thread handling details."""
1239
1254
1240 shell = _select_shell(sys.argv)
1255 shell = _select_shell(sys.argv)
1241 return shell(user_ns = user_ns)
1256 return shell(user_ns = user_ns)
1242
1257
1243 # Some aliases for backwards compatibility
1258 # Some aliases for backwards compatibility
1244 IPythonShell = IPShell
1259 IPythonShell = IPShell
1245 IPythonShellEmbed = IPShellEmbed
1260 IPythonShellEmbed = IPShellEmbed
1246 #************************ End of file <Shell.py> ***************************
1261 #************************ End of file <Shell.py> ***************************
@@ -1,605 +1,613 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Sphinx directive to support embedded IPython code.
2 """Sphinx directive to support embedded IPython code.
3
3
4 This directive allows pasting of entire interactive IPython sessions, prompts
4 This directive allows pasting of entire interactive IPython sessions, prompts
5 and all, and their code will actually get re-executed at doc build time, with
5 and all, and their code will actually get re-executed at doc build time, with
6 all prompts renumbered sequentially.
6 all prompts renumbered sequentially.
7
7
8 To enable this directive, simply list it in your Sphinx ``conf.py`` file
8 To enable this directive, simply list it in your Sphinx ``conf.py`` file
9 (making sure the directory where you placed it is visible to sphinx, as is
9 (making sure the directory where you placed it is visible to sphinx, as is
10 needed for all Sphinx directives).
10 needed for all Sphinx directives).
11
11
12 By default this directive assumes that your prompts are unchanged IPython ones,
12 By default this directive assumes that your prompts are unchanged IPython ones,
13 but this can be customized. For example, the following code in your Sphinx
13 but this can be customized. For example, the following code in your Sphinx
14 config file will configure this directive for the following input/output
14 config file will configure this directive for the following input/output
15 prompts ``Yade [1]:`` and ``-> [1]:``::
15 prompts ``Yade [1]:`` and ``-> [1]:``::
16
16
17 import ipython_directive as id
17 import ipython_directive as id
18 id.rgxin =re.compile(r'(?:In |Yade )\[(\d+)\]:\s?(.*)\s*')
18 id.rgxin =re.compile(r'(?:In |Yade )\[(\d+)\]:\s?(.*)\s*')
19 id.rgxout=re.compile(r'(?:Out| -> )\[(\d+)\]:\s?(.*)\s*')
19 id.rgxout=re.compile(r'(?:Out| -> )\[(\d+)\]:\s?(.*)\s*')
20 id.fmtin ='Yade [%d]:'
20 id.fmtin ='Yade [%d]:'
21 id.fmtout=' -> [%d]:'
21 id.fmtout=' -> [%d]:'
22
22
23 id.rc_override=dict(
23 id.rc_override=dict(
24 prompt_in1="Yade [\#]:",
24 prompt_in1="Yade [\#]:",
25 prompt_in2=" .\D..",
25 prompt_in2=" .\D..",
26 prompt_out=" -> [\#]:"
26 prompt_out=" -> [\#]:"
27 )
27 )
28 id.reconfig_shell()
28
29
29 import ipython_console_highlighting as ich
30 import ipython_console_highlighting as ich
30 ich.IPythonConsoleLexer.input_prompt=
31 ich.IPythonConsoleLexer.input_prompt=
31 re.compile("(Yade \[[0-9]+\]: )|( \.\.\.+:)")
32 re.compile("(Yade \[[0-9]+\]: )|( \.\.\.+:)")
32 ich.IPythonConsoleLexer.output_prompt=
33 ich.IPythonConsoleLexer.output_prompt=
33 re.compile("(( -> )|(Out)\[[0-9]+\]: )|( \.\.\.+:)")
34 re.compile("(( -> )|(Out)\[[0-9]+\]: )|( \.\.\.+:)")
34 ich.IPythonConsoleLexer.continue_prompt=re.compile(" \.\.\.+:")
35 ich.IPythonConsoleLexer.continue_prompt=re.compile(" \.\.\.+:")
35
36
36
37
37 ToDo
38 ToDo
38 ----
39 ----
39
40
40 - Turn the ad-hoc test() function into a real test suite.
41 - Turn the ad-hoc test() function into a real test suite.
41 - Break up ipython-specific functionality from matplotlib stuff into better
42 - Break up ipython-specific functionality from matplotlib stuff into better
42 separated code.
43 separated code.
43 - Make sure %bookmarks used internally are removed on exit.
44 - Make sure %bookmarks used internally are removed on exit.
44
45
45
46
46 Authors
47 Authors
47 -------
48 -------
48
49
49 - John D Hunter: orignal author.
50 - John D Hunter: orignal author.
50 - Fernando Perez: refactoring, documentation, cleanups.
51 - Fernando Perez: refactoring, documentation, cleanups.
51 - VáclavŠmilauer <eudoxos-AT-arcig.cz>: Prompt generatlizations.
52 - VáclavŠmilauer <eudoxos-AT-arcig.cz>: Prompt generatlizations.
52 """
53 """
53
54
54 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
55 # Imports
56 # Imports
56 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
57
58
58 # Stdlib
59 # Stdlib
59 import cStringIO
60 import cStringIO
60 import imp
61 import imp
61 import os
62 import os
62 import re
63 import re
63 import shutil
64 import shutil
64 import sys
65 import sys
65 import warnings
66 import warnings
66
67
67 # To keep compatibility with various python versions
68 # To keep compatibility with various python versions
68 try:
69 try:
69 from hashlib import md5
70 from hashlib import md5
70 except ImportError:
71 except ImportError:
71 from md5 import md5
72 from md5 import md5
72
73
73 # Third-party
74 # Third-party
74 import matplotlib
75 import matplotlib
75 import sphinx
76 import sphinx
76 from docutils.parsers.rst import directives
77 from docutils.parsers.rst import directives
77
78
78 matplotlib.use('Agg')
79 matplotlib.use('Agg')
79
80
80 # Our own
81 # Our own
81 import IPython
82 import IPython
82 from IPython.Shell import MatplotlibShell
83 from IPython.Shell import MatplotlibShell
83
84
84 #-----------------------------------------------------------------------------
85 #-----------------------------------------------------------------------------
85 # Globals
86 # Globals
86 #-----------------------------------------------------------------------------
87 #-----------------------------------------------------------------------------
87
88
88 sphinx_version = sphinx.__version__.split(".")
89 sphinx_version = sphinx.__version__.split(".")
89 # The split is necessary for sphinx beta versions where the string is
90 # The split is necessary for sphinx beta versions where the string is
90 # '6b1'
91 # '6b1'
91 sphinx_version = tuple([int(re.split('[a-z]', x)[0])
92 sphinx_version = tuple([int(re.split('[a-z]', x)[0])
92 for x in sphinx_version[:2]])
93 for x in sphinx_version[:2]])
93
94
94 COMMENT, INPUT, OUTPUT = range(3)
95 COMMENT, INPUT, OUTPUT = range(3)
95 rc_override = {}
96 rc_override = {}
96 rgxin = re.compile('In \[(\d+)\]:\s?(.*)\s*')
97 rgxin = re.compile('In \[(\d+)\]:\s?(.*)\s*')
97 rgxout = re.compile('Out\[(\d+)\]:\s?(.*)\s*')
98 rgxout = re.compile('Out\[(\d+)\]:\s?(.*)\s*')
98 fmtin = 'In [%d]:'
99 fmtin = 'In [%d]:'
99 fmtout = 'Out[%d]:'
100 fmtout = 'Out[%d]:'
100
101
101 #-----------------------------------------------------------------------------
102 #-----------------------------------------------------------------------------
102 # Functions and class declarations
103 # Functions and class declarations
103 #-----------------------------------------------------------------------------
104 #-----------------------------------------------------------------------------
104 def block_parser(part):
105 def block_parser(part):
105 """
106 """
106 part is a string of ipython text, comprised of at most one
107 part is a string of ipython text, comprised of at most one
107 input, one ouput, comments, and blank lines. The block parser
108 input, one ouput, comments, and blank lines. The block parser
108 parses the text into a list of::
109 parses the text into a list of::
109
110
110 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
111 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
111
112
112 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
113 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
113 data is, depending on the type of token::
114 data is, depending on the type of token::
114
115
115 COMMENT : the comment string
116 COMMENT : the comment string
116
117
117 INPUT: the (DECORATOR, INPUT_LINE, REST) where
118 INPUT: the (DECORATOR, INPUT_LINE, REST) where
118 DECORATOR: the input decorator (or None)
119 DECORATOR: the input decorator (or None)
119 INPUT_LINE: the input as string (possibly multi-line)
120 INPUT_LINE: the input as string (possibly multi-line)
120 REST : any stdout generated by the input line (not OUTPUT)
121 REST : any stdout generated by the input line (not OUTPUT)
121
122
122
123
123 OUTPUT: the output string, possibly multi-line
124 OUTPUT: the output string, possibly multi-line
124 """
125 """
125
126
126 block = []
127 block = []
127 lines = part.split('\n')
128 lines = part.split('\n')
128 N = len(lines)
129 N = len(lines)
129 i = 0
130 i = 0
130 decorator = None
131 decorator = None
131 while 1:
132 while 1:
132
133
133 if i==N:
134 if i==N:
134 # nothing left to parse -- the last line
135 # nothing left to parse -- the last line
135 break
136 break
136
137
137 line = lines[i]
138 line = lines[i]
138 i += 1
139 i += 1
139 line_stripped = line.strip()
140 line_stripped = line.strip()
140 if line_stripped.startswith('#'):
141 if line_stripped.startswith('#'):
141 block.append((COMMENT, line))
142 block.append((COMMENT, line))
142 continue
143 continue
143
144
144 if line_stripped.startswith('@'):
145 if line_stripped.startswith('@'):
145 # we're assuming at most one decorator -- may need to
146 # we're assuming at most one decorator -- may need to
146 # rethink
147 # rethink
147 decorator = line_stripped
148 decorator = line_stripped
148 continue
149 continue
149
150
150 # does this look like an input line?
151 # does this look like an input line?
151 matchin = rgxin.match(line)
152 matchin = rgxin.match(line)
152 if matchin:
153 if matchin:
153 lineno, inputline = int(matchin.group(1)), matchin.group(2)
154 lineno, inputline = int(matchin.group(1)), matchin.group(2)
154
155
155 # the ....: continuation string
156 # the ....: continuation string
156 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
157 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
157 Nc = len(continuation)
158 Nc = len(continuation)
158 # input lines can continue on for more than one line, if
159 # input lines can continue on for more than one line, if
159 # we have a '\' line continuation char or a function call
160 # we have a '\' line continuation char or a function call
160 # echo line 'print'. The input line can only be
161 # echo line 'print'. The input line can only be
161 # terminated by the end of the block or an output line, so
162 # terminated by the end of the block or an output line, so
162 # we parse out the rest of the input line if it is
163 # we parse out the rest of the input line if it is
163 # multiline as well as any echo text
164 # multiline as well as any echo text
164
165
165 rest = []
166 rest = []
166 while i<N:
167 while i<N:
167
168
168 # look ahead; if the next line is blank, or a comment, or
169 # look ahead; if the next line is blank, or a comment, or
169 # an output line, we're done
170 # an output line, we're done
170
171
171 nextline = lines[i]
172 nextline = lines[i]
172 matchout = rgxout.match(nextline)
173 matchout = rgxout.match(nextline)
173 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
174 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
174 if matchout or nextline.startswith('#'):
175 if matchout or nextline.startswith('#'):
175 break
176 break
176 elif nextline.startswith(continuation):
177 elif nextline.startswith(continuation):
177 inputline += '\n' + nextline[Nc:]
178 inputline += '\n' + nextline[Nc:]
178 else:
179 else:
179 rest.append(nextline)
180 rest.append(nextline)
180 i+= 1
181 i+= 1
181
182
182 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
183 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
183 continue
184 continue
184
185
185 # if it looks like an output line grab all the text to the end
186 # if it looks like an output line grab all the text to the end
186 # of the block
187 # of the block
187 matchout = rgxout.match(line)
188 matchout = rgxout.match(line)
188 if matchout:
189 if matchout:
189 lineno, output = int(matchout.group(1)), matchout.group(2)
190 lineno, output = int(matchout.group(1)), matchout.group(2)
190 if i<N-1:
191 if i<N-1:
191 output = '\n'.join([output] + lines[i:])
192 output = '\n'.join([output] + lines[i:])
192
193
193 block.append((OUTPUT, output))
194 block.append((OUTPUT, output))
194 break
195 break
195
196
196 return block
197 return block
197
198
198
199
199 class EmbeddedSphinxShell(object):
200 class EmbeddedSphinxShell(object):
200 """An embedded IPython instance to run inside Sphinx"""
201 """An embedded IPython instance to run inside Sphinx"""
201
202
202 def __init__(self):
203 def __init__(self):
203
204
204 self.cout = cStringIO.StringIO()
205 self.cout = cStringIO.StringIO()
205
206
206 IPython.Shell.Term.cout = self.cout
207 IPython.Shell.Term.cout = self.cout
207 IPython.Shell.Term.cerr = self.cout
208 IPython.Shell.Term.cerr = self.cout
208 argv = ['-autocall', '0']
209 argv = ['-autocall', '0']
209 self.user_ns = {}
210 self.user_ns = {}
210 self.user_glocal_ns = {}
211 self.user_glocal_ns = {}
211
212
212 self.IP = IPython.ipmaker.make_IPython(
213 self.IP = IPython.ipmaker.make_IPython(
213 argv, self.user_ns, self.user_glocal_ns, embedded=True,
214 argv, self.user_ns, self.user_glocal_ns, embedded=True,
214 #shell_class=IPython.Shell.InteractiveShell,
215 #shell_class=IPython.Shell.InteractiveShell,
215 shell_class=MatplotlibShell,
216 shell_class=MatplotlibShell,
216 rc_override = dict(colors = 'NoColor'), **rc_override)
217 rc_override = dict(colors = 'NoColor', **rc_override))
217
218
218 self.input = ''
219 self.input = ''
219 self.output = ''
220 self.output = ''
220
221
221 self.is_verbatim = False
222 self.is_verbatim = False
222 self.is_doctest = False
223 self.is_doctest = False
223 self.is_suppress = False
224 self.is_suppress = False
224
225
225 # on the first call to the savefig decorator, we'll import
226 # on the first call to the savefig decorator, we'll import
226 # pyplot as plt so we can make a call to the plt.gcf().savefig
227 # pyplot as plt so we can make a call to the plt.gcf().savefig
227 self._pyplot_imported = False
228 self._pyplot_imported = False
228
229
229 # we need bookmark the current dir first so we can save
230 # we need bookmark the current dir first so we can save
230 # relative to it
231 # relative to it
231 self.process_input_line('bookmark ipy_basedir')
232 self.process_input_line('bookmark ipy_basedir')
232 self.cout.seek(0)
233 self.cout.seek(0)
233 self.cout.truncate(0)
234 self.cout.truncate(0)
234
235
235 def process_input_line(self, line):
236 def process_input_line(self, line):
236 """process the input, capturing stdout"""
237 """process the input, capturing stdout"""
237 #print "input='%s'"%self.input
238 #print "input='%s'"%self.input
238 stdout = sys.stdout
239 stdout = sys.stdout
239 sys.stdout = self.cout
240 sys.stdout = self.cout
240 #self.IP.resetbuffer()
241 #self.IP.resetbuffer()
241 self.IP.push(self.IP.prefilter(line, 0))
242 self.IP.push(self.IP.prefilter(line, 0))
242 #self.IP.runlines(line)
243 #self.IP.runlines(line)
243 sys.stdout = stdout
244 sys.stdout = stdout
244
245
245 # Callbacks for each type of token
246 # Callbacks for each type of token
246 def process_input(self, data, input_prompt, lineno):
247 def process_input(self, data, input_prompt, lineno):
247 """Process data block for INPUT token."""
248 """Process data block for INPUT token."""
248 decorator, input, rest = data
249 decorator, input, rest = data
249 image_file = None
250 image_file = None
250 #print 'INPUT:', data
251 #print 'INPUT:', data
251 is_verbatim = decorator=='@verbatim' or self.is_verbatim
252 is_verbatim = decorator=='@verbatim' or self.is_verbatim
252 is_doctest = decorator=='@doctest' or self.is_doctest
253 is_doctest = decorator=='@doctest' or self.is_doctest
253 is_suppress = decorator=='@suppress' or self.is_suppress
254 is_suppress = decorator=='@suppress' or self.is_suppress
254 is_savefig = decorator is not None and \
255 is_savefig = decorator is not None and \
255 decorator.startswith('@savefig')
256 decorator.startswith('@savefig')
256
257
257 input_lines = input.split('\n')
258 input_lines = input.split('\n')
258
259
259 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
260 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
260 Nc = len(continuation)
261 Nc = len(continuation)
261
262
262 if is_savefig:
263 if is_savefig:
263 saveargs = decorator.split(' ')
264 saveargs = decorator.split(' ')
264 filename = saveargs[1]
265 filename = saveargs[1]
265 outfile = os.path.join('_static/%s'%filename)
266 outfile = os.path.join('_static/%s'%filename)
266 # build out an image directive like
267 # build out an image directive like
267 # .. image:: somefile.png
268 # .. image:: somefile.png
268 # :width 4in
269 # :width 4in
269 #
270 #
270 # from an input like
271 # from an input like
271 # savefig somefile.png width=4in
272 # savefig somefile.png width=4in
272 imagerows = ['.. image:: %s'%outfile]
273 imagerows = ['.. image:: %s'%outfile]
273
274
274 for kwarg in saveargs[2:]:
275 for kwarg in saveargs[2:]:
275 arg, val = kwarg.split('=')
276 arg, val = kwarg.split('=')
276 arg = arg.strip()
277 arg = arg.strip()
277 val = val.strip()
278 val = val.strip()
278 imagerows.append(' :%s: %s'%(arg, val))
279 imagerows.append(' :%s: %s'%(arg, val))
279
280
280 image_file = outfile
281 image_file = outfile
281 image_directive = '\n'.join(imagerows)
282 image_directive = '\n'.join(imagerows)
282
283
283 # TODO: can we get "rest" from ipython
284 # TODO: can we get "rest" from ipython
284 #self.process_input_line('\n'.join(input_lines))
285 #self.process_input_line('\n'.join(input_lines))
285
286
286 ret = []
287 ret = []
287 is_semicolon = False
288 is_semicolon = False
288
289
289 for i, line in enumerate(input_lines):
290 for i, line in enumerate(input_lines):
290 if line.endswith(';'):
291 if line.endswith(';'):
291 is_semicolon = True
292 is_semicolon = True
292
293
293 if i==0:
294 if i==0:
294 # process the first input line
295 # process the first input line
295 if is_verbatim:
296 if is_verbatim:
296 self.process_input_line('')
297 self.process_input_line('')
297 else:
298 else:
298 # only submit the line in non-verbatim mode
299 # only submit the line in non-verbatim mode
299 self.process_input_line(line)
300 self.process_input_line(line)
300 formatted_line = '%s %s'%(input_prompt, line)
301 formatted_line = '%s %s'%(input_prompt, line)
301 else:
302 else:
302 # process a continuation line
303 # process a continuation line
303 if not is_verbatim:
304 if not is_verbatim:
304 self.process_input_line(line)
305 self.process_input_line(line)
305
306
306 formatted_line = '%s %s'%(continuation, line)
307 formatted_line = '%s %s'%(continuation, line)
307
308
308 if not is_suppress:
309 if not is_suppress:
309 ret.append(formatted_line)
310 ret.append(formatted_line)
310
311
311 if not is_suppress:
312 if not is_suppress:
312 if len(rest.strip()):
313 if len(rest.strip()):
313 if is_verbatim:
314 if is_verbatim:
314 # the "rest" is the standard output of the
315 # the "rest" is the standard output of the
315 # input, which needs to be added in
316 # input, which needs to be added in
316 # verbatim mode
317 # verbatim mode
317 ret.append(rest)
318 ret.append(rest)
318
319
319 self.cout.seek(0)
320 self.cout.seek(0)
320 output = self.cout.read()
321 output = self.cout.read()
321 if not is_suppress and not is_semicolon:
322 if not is_suppress and not is_semicolon:
322 ret.append(output)
323 ret.append(output)
323
324
324 self.cout.truncate(0)
325 self.cout.truncate(0)
325 return ret, input_lines, output, is_doctest, image_file
326 return ret, input_lines, output, is_doctest, image_file
326 #print 'OUTPUT', output # dbg
327 #print 'OUTPUT', output # dbg
327
328
328 def process_output(self, data, output_prompt,
329 def process_output(self, data, output_prompt,
329 input_lines, output, is_doctest, image_file):
330 input_lines, output, is_doctest, image_file):
330 """Process data block for OUTPUT token."""
331 """Process data block for OUTPUT token."""
331 if is_doctest:
332 if is_doctest:
332 submitted = data.strip()
333 submitted = data.strip()
333 found = output
334 found = output
334 if found is not None:
335 if found is not None:
335 ind = found.find(output_prompt)
336 ind = found.find(output_prompt)
336 if ind<0:
337 if ind<0:
337 raise RuntimeError('output prompt="%s" does not match out line=%s'%(output_prompt, found))
338 raise RuntimeError('output prompt="%s" does not match out line=%s'%(output_prompt, found))
338 found = found[len(output_prompt):].strip()
339 found = found[len(output_prompt):].strip()
339
340
340 if found!=submitted:
341 if found!=submitted:
341 raise RuntimeError('doctest failure for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted))
342 raise RuntimeError('doctest failure for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted))
342 #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted)
343 #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted)
343
344
344 def process_comment(self, data):
345 def process_comment(self, data):
345 """Process data block for COMMENT token."""
346 """Process data block for COMMENT token."""
346 if not self.is_suppress:
347 if not self.is_suppress:
347 return [data]
348 return [data]
348
349
349 def process_block(self, block):
350 def process_block(self, block):
350 """
351 """
351 process block from the block_parser and return a list of processed lines
352 process block from the block_parser and return a list of processed lines
352 """
353 """
353
354
354 ret = []
355 ret = []
355 output = None
356 output = None
356 input_lines = None
357 input_lines = None
357
358
358 m = rgxin.match(str(self.IP.outputcache.prompt1).strip())
359 m = rgxin.match(str(self.IP.outputcache.prompt1).strip())
359 lineno = int(m.group(1))
360 lineno = int(m.group(1))
360
361
361 input_prompt = fmtin%lineno
362 input_prompt = fmtin%lineno
362 output_prompt = fmtout%lineno
363 output_prompt = fmtout%lineno
363 image_file = None
364 image_file = None
364 image_directive = None
365 image_directive = None
365 # XXX - This needs a second refactor. There's too much state being
366 # XXX - This needs a second refactor. There's too much state being
366 # held globally, which makes for a very awkward interface and large,
367 # held globally, which makes for a very awkward interface and large,
367 # hard to test functions. I've already broken this up at least into
368 # hard to test functions. I've already broken this up at least into
368 # three separate processors to isolate the logic better, but this only
369 # three separate processors to isolate the logic better, but this only
369 # serves to highlight the coupling. Next we need to clean it up...
370 # serves to highlight the coupling. Next we need to clean it up...
370 for token, data in block:
371 for token, data in block:
371 if token==COMMENT:
372 if token==COMMENT:
372 out_data = self.process_comment(data)
373 out_data = self.process_comment(data)
373 elif token==INPUT:
374 elif token==INPUT:
374 out_data, input_lines, output, is_doctest, image_file= \
375 out_data, input_lines, output, is_doctest, image_file= \
375 self.process_input(data, input_prompt, lineno)
376 self.process_input(data, input_prompt, lineno)
376 elif token==OUTPUT:
377 elif token==OUTPUT:
377 out_data = \
378 out_data = \
378 self.process_output(data, output_prompt,
379 self.process_output(data, output_prompt,
379 input_lines, output, is_doctest,
380 input_lines, output, is_doctest,
380 image_file)
381 image_file)
381 if out_data:
382 if out_data:
382 ret.extend(out_data)
383 ret.extend(out_data)
383
384
384 if image_file is not None:
385 if image_file is not None:
385 self.ensure_pyplot()
386 self.ensure_pyplot()
386 command = 'plt.gcf().savefig("%s")'%image_file
387 command = 'plt.gcf().savefig("%s")'%image_file
387 #print 'SAVEFIG', command # dbg
388 #print 'SAVEFIG', command # dbg
388 self.process_input_line('bookmark ipy_thisdir')
389 self.process_input_line('bookmark ipy_thisdir')
389 self.process_input_line('cd -b ipy_basedir')
390 self.process_input_line('cd -b ipy_basedir')
390 self.process_input_line(command)
391 self.process_input_line(command)
391 self.process_input_line('cd -b ipy_thisdir')
392 self.process_input_line('cd -b ipy_thisdir')
392 self.cout.seek(0)
393 self.cout.seek(0)
393 self.cout.truncate(0)
394 self.cout.truncate(0)
394 return ret, image_directive
395 return ret, image_directive
395
396
396 def ensure_pyplot(self):
397 def ensure_pyplot(self):
397 if self._pyplot_imported:
398 if self._pyplot_imported:
398 return
399 return
399 self.process_input_line('import matplotlib.pyplot as plt')
400 self.process_input_line('import matplotlib.pyplot as plt')
400
401
401 # A global instance used below. XXX: not sure why this can't be created inside
402 # A global instance used below. XXX: not sure why this can't be created inside
402 # ipython_directive itself.
403 # ipython_directive itself.
403 shell = EmbeddedSphinxShell()
404 shell = EmbeddedSphinxShell()
404
405
406 def reconfig_shell():
407 """Called after setting module-level variables to re-instantiate
408 with the set values (since shell is instantiated first at import-time
409 when module variables have default values)"""
410 global shell
411 shell = EmbeddedSphinxShell()
412
405
413
406 def ipython_directive(name, arguments, options, content, lineno,
414 def ipython_directive(name, arguments, options, content, lineno,
407 content_offset, block_text, state, state_machine,
415 content_offset, block_text, state, state_machine,
408 ):
416 ):
409
417
410 debug = ipython_directive.DEBUG
418 debug = ipython_directive.DEBUG
411 shell.is_suppress = options.has_key('suppress')
419 shell.is_suppress = options.has_key('suppress')
412 shell.is_doctest = options.has_key('doctest')
420 shell.is_doctest = options.has_key('doctest')
413 shell.is_verbatim = options.has_key('verbatim')
421 shell.is_verbatim = options.has_key('verbatim')
414
422
415 #print 'ipy', shell.is_suppress, options
423 #print 'ipy', shell.is_suppress, options
416 parts = '\n'.join(content).split('\n\n')
424 parts = '\n'.join(content).split('\n\n')
417 lines = ['.. sourcecode:: ipython', '']
425 lines = ['.. sourcecode:: ipython', '']
418
426
419 figures = []
427 figures = []
420 for part in parts:
428 for part in parts:
421 block = block_parser(part)
429 block = block_parser(part)
422
430
423 if len(block):
431 if len(block):
424 rows, figure = shell.process_block(block)
432 rows, figure = shell.process_block(block)
425 for row in rows:
433 for row in rows:
426 lines.extend([' %s'%line for line in row.split('\n')])
434 lines.extend([' %s'%line for line in row.split('\n')])
427
435
428 if figure is not None:
436 if figure is not None:
429 figures.append(figure)
437 figures.append(figure)
430
438
431 for figure in figures:
439 for figure in figures:
432 lines.append('')
440 lines.append('')
433 lines.extend(figure.split('\n'))
441 lines.extend(figure.split('\n'))
434 lines.append('')
442 lines.append('')
435
443
436 #print lines
444 #print lines
437 if len(lines)>2:
445 if len(lines)>2:
438 if debug:
446 if debug:
439 print '\n'.join(lines)
447 print '\n'.join(lines)
440 else:
448 else:
441 #print 'INSERTING %d lines'%len(lines)
449 #print 'INSERTING %d lines'%len(lines)
442 state_machine.insert_input(
450 state_machine.insert_input(
443 lines, state_machine.input_lines.source(0))
451 lines, state_machine.input_lines.source(0))
444
452
445 return []
453 return []
446
454
447 ipython_directive.DEBUG = False
455 ipython_directive.DEBUG = False
448
456
449 # Enable as a proper Sphinx directive
457 # Enable as a proper Sphinx directive
450 def setup(app):
458 def setup(app):
451 setup.app = app
459 setup.app = app
452 options = {'suppress': directives.flag,
460 options = {'suppress': directives.flag,
453 'doctest': directives.flag,
461 'doctest': directives.flag,
454 'verbatim': directives.flag,
462 'verbatim': directives.flag,
455 }
463 }
456
464
457 app.add_directive('ipython', ipython_directive, True, (0, 2, 0), **options)
465 app.add_directive('ipython', ipython_directive, True, (0, 2, 0), **options)
458
466
459
467
460 # Simple smoke test, needs to be converted to a proper automatic test.
468 # Simple smoke test, needs to be converted to a proper automatic test.
461 def test():
469 def test():
462
470
463 examples = [
471 examples = [
464 r"""
472 r"""
465 In [9]: pwd
473 In [9]: pwd
466 Out[9]: '/home/jdhunter/py4science/book'
474 Out[9]: '/home/jdhunter/py4science/book'
467
475
468 In [10]: cd bookdata/
476 In [10]: cd bookdata/
469 /home/jdhunter/py4science/book/bookdata
477 /home/jdhunter/py4science/book/bookdata
470
478
471 In [2]: from pylab import *
479 In [2]: from pylab import *
472
480
473 In [2]: ion()
481 In [2]: ion()
474
482
475 In [3]: im = imread('stinkbug.png')
483 In [3]: im = imread('stinkbug.png')
476
484
477 @savefig mystinkbug.png width=4in
485 @savefig mystinkbug.png width=4in
478 In [4]: imshow(im)
486 In [4]: imshow(im)
479 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
487 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
480
488
481 """,
489 """,
482 r"""
490 r"""
483
491
484 In [1]: x = 'hello world'
492 In [1]: x = 'hello world'
485
493
486 # string methods can be
494 # string methods can be
487 # used to alter the string
495 # used to alter the string
488 @doctest
496 @doctest
489 In [2]: x.upper()
497 In [2]: x.upper()
490 Out[2]: 'HELLO WORLD'
498 Out[2]: 'HELLO WORLD'
491
499
492 @verbatim
500 @verbatim
493 In [3]: x.st<TAB>
501 In [3]: x.st<TAB>
494 x.startswith x.strip
502 x.startswith x.strip
495 """,
503 """,
496 r"""
504 r"""
497
505
498 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
506 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
499 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
507 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
500
508
501 In [131]: print url.split('&')
509 In [131]: print url.split('&')
502 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
510 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
503
511
504 In [60]: import urllib
512 In [60]: import urllib
505
513
506 """,
514 """,
507 r"""\
515 r"""\
508
516
509 In [133]: import numpy.random
517 In [133]: import numpy.random
510
518
511 @suppress
519 @suppress
512 In [134]: numpy.random.seed(2358)
520 In [134]: numpy.random.seed(2358)
513
521
514 @doctest
522 @doctest
515 In [135]: np.random.rand(10,2)
523 In [135]: np.random.rand(10,2)
516 Out[135]:
524 Out[135]:
517 array([[ 0.64524308, 0.59943846],
525 array([[ 0.64524308, 0.59943846],
518 [ 0.47102322, 0.8715456 ],
526 [ 0.47102322, 0.8715456 ],
519 [ 0.29370834, 0.74776844],
527 [ 0.29370834, 0.74776844],
520 [ 0.99539577, 0.1313423 ],
528 [ 0.99539577, 0.1313423 ],
521 [ 0.16250302, 0.21103583],
529 [ 0.16250302, 0.21103583],
522 [ 0.81626524, 0.1312433 ],
530 [ 0.81626524, 0.1312433 ],
523 [ 0.67338089, 0.72302393],
531 [ 0.67338089, 0.72302393],
524 [ 0.7566368 , 0.07033696],
532 [ 0.7566368 , 0.07033696],
525 [ 0.22591016, 0.77731835],
533 [ 0.22591016, 0.77731835],
526 [ 0.0072729 , 0.34273127]])
534 [ 0.0072729 , 0.34273127]])
527
535
528 """,
536 """,
529
537
530 r"""
538 r"""
531 In [106]: print x
539 In [106]: print x
532 jdh
540 jdh
533
541
534 In [109]: for i in range(10):
542 In [109]: for i in range(10):
535 .....: print i
543 .....: print i
536 .....:
544 .....:
537 .....:
545 .....:
538 0
546 0
539 1
547 1
540 2
548 2
541 3
549 3
542 4
550 4
543 5
551 5
544 6
552 6
545 7
553 7
546 8
554 8
547 9
555 9
548
556
549
557
550 """,
558 """,
551
559
552 r"""
560 r"""
553
561
554 In [144]: from pylab import *
562 In [144]: from pylab import *
555
563
556 In [145]: ion()
564 In [145]: ion()
557
565
558 # use a semicolon to suppress the output
566 # use a semicolon to suppress the output
559 @savefig test_hist.png width=4in
567 @savefig test_hist.png width=4in
560 In [151]: hist(np.random.randn(10000), 100);
568 In [151]: hist(np.random.randn(10000), 100);
561
569
562
570
563 @savefig test_plot.png width=4in
571 @savefig test_plot.png width=4in
564 In [151]: plot(np.random.randn(10000), 'o');
572 In [151]: plot(np.random.randn(10000), 'o');
565 """,
573 """,
566
574
567 r"""
575 r"""
568 # use a semicolon to suppress the output
576 # use a semicolon to suppress the output
569 In [151]: plt.clf()
577 In [151]: plt.clf()
570
578
571 @savefig plot_simple.png width=4in
579 @savefig plot_simple.png width=4in
572 In [151]: plot([1,2,3])
580 In [151]: plot([1,2,3])
573
581
574 @savefig hist_simple.png width=4in
582 @savefig hist_simple.png width=4in
575 In [151]: hist(np.random.randn(10000), 100);
583 In [151]: hist(np.random.randn(10000), 100);
576
584
577 """,
585 """,
578 r"""
586 r"""
579 # update the current fig
587 # update the current fig
580 In [151]: ylabel('number')
588 In [151]: ylabel('number')
581
589
582 In [152]: title('normal distribution')
590 In [152]: title('normal distribution')
583
591
584
592
585 @savefig hist_with_text.png
593 @savefig hist_with_text.png
586 In [153]: grid(True)
594 In [153]: grid(True)
587
595
588 """,
596 """,
589 ]
597 ]
590
598
591
599
592 ipython_directive.DEBUG = True
600 ipython_directive.DEBUG = True
593 #options = dict(suppress=True)
601 #options = dict(suppress=True)
594 options = dict()
602 options = dict()
595 for example in examples:
603 for example in examples:
596 content = example.split('\n')
604 content = example.split('\n')
597 ipython_directive('debug', arguments=None, options=options,
605 ipython_directive('debug', arguments=None, options=options,
598 content=content, lineno=0,
606 content=content, lineno=0,
599 content_offset=None, block_text=None,
607 content_offset=None, block_text=None,
600 state=None, state_machine=None,
608 state=None, state_machine=None,
601 )
609 )
602
610
603 # Run test suite as a script
611 # Run test suite as a script
604 if __name__=='__main__':
612 if __name__=='__main__':
605 test()
613 test()
General Comments 0
You need to be logged in to leave comments. Login now