##// END OF EJS Templates
Checkpoint before merging with upstream
Fernando Perez -
Show More
@@ -1,1236 +1,1238 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Shell classes.
2 """IPython Shell classes.
3
3
4 All the matplotlib support code was co-developed with John Hunter,
4 All the matplotlib support code was co-developed with John Hunter,
5 matplotlib's author.
5 matplotlib's author.
6
6
7 $Id: Shell.py 3024 2008-02-07 15:34:42Z darren.dale $"""
7 $Id: Shell.py 3024 2008-02-07 15:34:42Z darren.dale $"""
8
8
9 #*****************************************************************************
9 #*****************************************************************************
10 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
10 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #*****************************************************************************
14 #*****************************************************************************
15
15
16 from IPython import Release
16 from IPython import Release
17 __author__ = '%s <%s>' % Release.authors['Fernando']
17 __author__ = '%s <%s>' % Release.authors['Fernando']
18 __license__ = Release.license
18 __license__ = Release.license
19
19
20 # Code begins
20 # Code begins
21 # Stdlib imports
21 # Stdlib imports
22 import __builtin__
22 import __builtin__
23 import __main__
23 import __main__
24 import Queue
24 import Queue
25 import inspect
25 import inspect
26 import os
26 import os
27 import sys
27 import sys
28 import thread
28 import thread
29 import threading
29 import threading
30 import time
30 import time
31
31
32 from signal import signal, SIGINT
32 from signal import signal, SIGINT
33
33
34 try:
34 try:
35 import ctypes
35 import ctypes
36 HAS_CTYPES = True
36 HAS_CTYPES = True
37 except ImportError:
37 except ImportError:
38 HAS_CTYPES = False
38 HAS_CTYPES = False
39
39
40 # IPython imports
40 # IPython imports
41 import IPython
41 import IPython
42 from IPython import ultraTB, ipapi
42 from IPython import ultraTB, ipapi
43 from IPython.Magic import Magic
43 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
44 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
44 from IPython.iplib import InteractiveShell
45 from IPython.iplib import InteractiveShell
45 from IPython.ipmaker import make_IPython
46 from IPython.ipmaker import make_IPython
46 from IPython.Magic import Magic
47 from IPython.ipstruct import Struct
47 from IPython.ipstruct import Struct
48 from IPython.testing import decorators as testdec
48
49
49 # Globals
50 # Globals
50 # global flag to pass around information about Ctrl-C without exceptions
51 # global flag to pass around information about Ctrl-C without exceptions
51 KBINT = False
52 KBINT = False
52
53
53 # global flag to turn on/off Tk support.
54 # global flag to turn on/off Tk support.
54 USE_TK = False
55 USE_TK = False
55
56
56 # ID for the main thread, used for cross-thread exceptions
57 # ID for the main thread, used for cross-thread exceptions
57 MAIN_THREAD_ID = thread.get_ident()
58 MAIN_THREAD_ID = thread.get_ident()
58
59
59 # Tag when runcode() is active, for exception handling
60 # Tag when runcode() is active, for exception handling
60 CODE_RUN = None
61 CODE_RUN = None
61
62
62 # Default timeout for waiting for multithreaded shells (in seconds)
63 # Default timeout for waiting for multithreaded shells (in seconds)
63 GUI_TIMEOUT = 10
64 GUI_TIMEOUT = 10
64
65
65 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
66 # This class is trivial now, but I want to have it in to publish a clean
67 # This class is trivial now, but I want to have it in to publish a clean
67 # interface. Later when the internals are reorganized, code that uses this
68 # interface. Later when the internals are reorganized, code that uses this
68 # shouldn't have to change.
69 # shouldn't have to change.
69
70
70 class IPShell:
71 class IPShell:
71 """Create an IPython instance."""
72 """Create an IPython instance."""
72
73
73 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
74 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
74 debug=1,shell_class=InteractiveShell):
75 debug=1,shell_class=InteractiveShell):
75 self.IP = make_IPython(argv,user_ns=user_ns,
76 self.IP = make_IPython(argv,user_ns=user_ns,
76 user_global_ns=user_global_ns,
77 user_global_ns=user_global_ns,
77 debug=debug,shell_class=shell_class)
78 debug=debug,shell_class=shell_class)
78
79
79 def mainloop(self,sys_exit=0,banner=None):
80 def mainloop(self,sys_exit=0,banner=None):
80 self.IP.mainloop(banner)
81 self.IP.mainloop(banner)
81 if sys_exit:
82 if sys_exit:
82 sys.exit()
83 sys.exit()
83
84
84 #-----------------------------------------------------------------------------
85 #-----------------------------------------------------------------------------
85 def kill_embedded(self,parameter_s=''):
86 def kill_embedded(self,parameter_s=''):
86 """%kill_embedded : deactivate for good the current embedded IPython.
87 """%kill_embedded : deactivate for good the current embedded IPython.
87
88
88 This function (after asking for confirmation) sets an internal flag so that
89 This function (after asking for confirmation) sets an internal flag so that
89 an embedded IPython will never activate again. This is useful to
90 an embedded IPython will never activate again. This is useful to
90 permanently disable a shell that is being called inside a loop: once you've
91 permanently disable a shell that is being called inside a loop: once you've
91 figured out what you needed from it, you may then kill it and the program
92 figured out what you needed from it, you may then kill it and the program
92 will then continue to run without the interactive shell interfering again.
93 will then continue to run without the interactive shell interfering again.
93 """
94 """
94
95
95 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
96 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
96 "(y/n)? [y/N] ",'n')
97 "(y/n)? [y/N] ",'n')
97 if kill:
98 if kill:
98 self.shell.embedded_active = False
99 self.shell.embedded_active = False
99 print "This embedded IPython will not reactivate anymore once you exit."
100 print "This embedded IPython will not reactivate anymore once you exit."
100
101
101 class IPShellEmbed:
102 class IPShellEmbed:
102 """Allow embedding an IPython shell into a running program.
103 """Allow embedding an IPython shell into a running program.
103
104
104 Instances of this class are callable, with the __call__ method being an
105 Instances of this class are callable, with the __call__ method being an
105 alias to the embed() method of an InteractiveShell instance.
106 alias to the embed() method of an InteractiveShell instance.
106
107
107 Usage (see also the example-embed.py file for a running example):
108 Usage (see also the example-embed.py file for a running example):
108
109
109 ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
110 ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
110
111
111 - argv: list containing valid command-line options for IPython, as they
112 - argv: list containing valid command-line options for IPython, as they
112 would appear in sys.argv[1:].
113 would appear in sys.argv[1:].
113
114
114 For example, the following command-line options:
115 For example, the following command-line options:
115
116
116 $ ipython -prompt_in1 'Input <\\#>' -colors LightBG
117 $ ipython -prompt_in1 'Input <\\#>' -colors LightBG
117
118
118 would be passed in the argv list as:
119 would be passed in the argv list as:
119
120
120 ['-prompt_in1','Input <\\#>','-colors','LightBG']
121 ['-prompt_in1','Input <\\#>','-colors','LightBG']
121
122
122 - banner: string which gets printed every time the interpreter starts.
123 - banner: string which gets printed every time the interpreter starts.
123
124
124 - exit_msg: string which gets printed every time the interpreter exits.
125 - exit_msg: string which gets printed every time the interpreter exits.
125
126
126 - rc_override: a dict or Struct of configuration options such as those
127 - rc_override: a dict or Struct of configuration options such as those
127 used by IPython. These options are read from your ~/.ipython/ipythonrc
128 used by IPython. These options are read from your ~/.ipython/ipythonrc
128 file when the Shell object is created. Passing an explicit rc_override
129 file when the Shell object is created. Passing an explicit rc_override
129 dict with any options you want allows you to override those values at
130 dict with any options you want allows you to override those values at
130 creation time without having to modify the file. This way you can create
131 creation time without having to modify the file. This way you can create
131 embeddable instances configured in any way you want without editing any
132 embeddable instances configured in any way you want without editing any
132 global files (thus keeping your interactive IPython configuration
133 global files (thus keeping your interactive IPython configuration
133 unchanged).
134 unchanged).
134
135
135 Then the ipshell instance can be called anywhere inside your code:
136 Then the ipshell instance can be called anywhere inside your code:
136
137
137 ipshell(header='') -> Opens up an IPython shell.
138 ipshell(header='') -> Opens up an IPython shell.
138
139
139 - header: string printed by the IPython shell upon startup. This can let
140 - header: string printed by the IPython shell upon startup. This can let
140 you know where in your code you are when dropping into the shell. Note
141 you know where in your code you are when dropping into the shell. Note
141 that 'banner' gets prepended to all calls, so header is used for
142 that 'banner' gets prepended to all calls, so header is used for
142 location-specific information.
143 location-specific information.
143
144
144 For more details, see the __call__ method below.
145 For more details, see the __call__ method below.
145
146
146 When the IPython shell is exited with Ctrl-D, normal program execution
147 When the IPython shell is exited with Ctrl-D, normal program execution
147 resumes.
148 resumes.
148
149
149 This functionality was inspired by a posting on comp.lang.python by cmkl
150 This functionality was inspired by a posting on comp.lang.python by cmkl
150 <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
151 <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
151 by the IDL stop/continue commands."""
152 by the IDL stop/continue commands."""
152
153
153 def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None,
154 def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None,
154 user_ns=None):
155 user_ns=None):
155 """Note that argv here is a string, NOT a list."""
156 """Note that argv here is a string, NOT a list."""
156 self.set_banner(banner)
157 self.set_banner(banner)
157 self.set_exit_msg(exit_msg)
158 self.set_exit_msg(exit_msg)
158 self.set_dummy_mode(0)
159 self.set_dummy_mode(0)
159
160
160 # sys.displayhook is a global, we need to save the user's original
161 # sys.displayhook is a global, we need to save the user's original
161 # Don't rely on __displayhook__, as the user may have changed that.
162 # Don't rely on __displayhook__, as the user may have changed that.
162 self.sys_displayhook_ori = sys.displayhook
163 self.sys_displayhook_ori = sys.displayhook
163
164
164 # save readline completer status
165 # save readline completer status
165 try:
166 try:
166 #print 'Save completer',sys.ipcompleter # dbg
167 #print 'Save completer',sys.ipcompleter # dbg
167 self.sys_ipcompleter_ori = sys.ipcompleter
168 self.sys_ipcompleter_ori = sys.ipcompleter
168 except:
169 except:
169 pass # not nested with IPython
170 pass # not nested with IPython
170
171
171 self.IP = make_IPython(argv,rc_override=rc_override,
172 self.IP = make_IPython(argv,rc_override=rc_override,
172 embedded=True,
173 embedded=True,
173 user_ns=user_ns)
174 user_ns=user_ns)
174
175
175 ip = ipapi.IPApi(self.IP)
176 ip = ipapi.IPApi(self.IP)
176 ip.expose_magic("kill_embedded",kill_embedded)
177 ip.expose_magic("kill_embedded",kill_embedded)
177
178
178 # copy our own displayhook also
179 # copy our own displayhook also
179 self.sys_displayhook_embed = sys.displayhook
180 self.sys_displayhook_embed = sys.displayhook
180 # and leave the system's display hook clean
181 # and leave the system's display hook clean
181 sys.displayhook = self.sys_displayhook_ori
182 sys.displayhook = self.sys_displayhook_ori
182 # don't use the ipython crash handler so that user exceptions aren't
183 # don't use the ipython crash handler so that user exceptions aren't
183 # trapped
184 # trapped
184 sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
185 sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
185 mode = self.IP.rc.xmode,
186 mode = self.IP.rc.xmode,
186 call_pdb = self.IP.rc.pdb)
187 call_pdb = self.IP.rc.pdb)
187 self.restore_system_completer()
188 self.restore_system_completer()
188
189
189 def restore_system_completer(self):
190 def restore_system_completer(self):
190 """Restores the readline completer which was in place.
191 """Restores the readline completer which was in place.
191
192
192 This allows embedded IPython within IPython not to disrupt the
193 This allows embedded IPython within IPython not to disrupt the
193 parent's completion.
194 parent's completion.
194 """
195 """
195
196
196 try:
197 try:
197 self.IP.readline.set_completer(self.sys_ipcompleter_ori)
198 self.IP.readline.set_completer(self.sys_ipcompleter_ori)
198 sys.ipcompleter = self.sys_ipcompleter_ori
199 sys.ipcompleter = self.sys_ipcompleter_ori
199 except:
200 except:
200 pass
201 pass
201
202
202 def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
203 def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
203 """Activate the interactive interpreter.
204 """Activate the interactive interpreter.
204
205
205 __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
206 __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
206 the interpreter shell with the given local and global namespaces, and
207 the interpreter shell with the given local and global namespaces, and
207 optionally print a header string at startup.
208 optionally print a header string at startup.
208
209
209 The shell can be globally activated/deactivated using the
210 The shell can be globally activated/deactivated using the
210 set/get_dummy_mode methods. This allows you to turn off a shell used
211 set/get_dummy_mode methods. This allows you to turn off a shell used
211 for debugging globally.
212 for debugging globally.
212
213
213 However, *each* time you call the shell you can override the current
214 However, *each* time you call the shell you can override the current
214 state of dummy_mode with the optional keyword parameter 'dummy'. For
215 state of dummy_mode with the optional keyword parameter 'dummy'. For
215 example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
216 example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
216 can still have a specific call work by making it as IPShell(dummy=0).
217 can still have a specific call work by making it as IPShell(dummy=0).
217
218
218 The optional keyword parameter dummy controls whether the call
219 The optional keyword parameter dummy controls whether the call
219 actually does anything. """
220 actually does anything. """
220
221
221 # If the user has turned it off, go away
222 # If the user has turned it off, go away
222 if not self.IP.embedded_active:
223 if not self.IP.embedded_active:
223 return
224 return
224
225
225 # Normal exits from interactive mode set this flag, so the shell can't
226 # Normal exits from interactive mode set this flag, so the shell can't
226 # re-enter (it checks this variable at the start of interactive mode).
227 # re-enter (it checks this variable at the start of interactive mode).
227 self.IP.exit_now = False
228 self.IP.exit_now = False
228
229
229 # Allow the dummy parameter to override the global __dummy_mode
230 # Allow the dummy parameter to override the global __dummy_mode
230 if dummy or (dummy != 0 and self.__dummy_mode):
231 if dummy or (dummy != 0 and self.__dummy_mode):
231 return
232 return
232
233
233 # Set global subsystems (display,completions) to our values
234 # Set global subsystems (display,completions) to our values
234 sys.displayhook = self.sys_displayhook_embed
235 sys.displayhook = self.sys_displayhook_embed
235 if self.IP.has_readline:
236 if self.IP.has_readline:
236 self.IP.set_completer()
237 self.IP.set_completer()
237
238
238 if self.banner and header:
239 if self.banner and header:
239 format = '%s\n%s\n'
240 format = '%s\n%s\n'
240 else:
241 else:
241 format = '%s%s\n'
242 format = '%s%s\n'
242 banner = format % (self.banner,header)
243 banner = format % (self.banner,header)
243
244
244 # Call the embedding code with a stack depth of 1 so it can skip over
245 # Call the embedding code with a stack depth of 1 so it can skip over
245 # our call and get the original caller's namespaces.
246 # our call and get the original caller's namespaces.
246 self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
247 self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
247
248
248 if self.exit_msg:
249 if self.exit_msg:
249 print self.exit_msg
250 print self.exit_msg
250
251
251 # Restore global systems (display, completion)
252 # Restore global systems (display, completion)
252 sys.displayhook = self.sys_displayhook_ori
253 sys.displayhook = self.sys_displayhook_ori
253 self.restore_system_completer()
254 self.restore_system_completer()
254
255
255 def set_dummy_mode(self,dummy):
256 def set_dummy_mode(self,dummy):
256 """Sets the embeddable shell's dummy mode parameter.
257 """Sets the embeddable shell's dummy mode parameter.
257
258
258 set_dummy_mode(dummy): dummy = 0 or 1.
259 set_dummy_mode(dummy): dummy = 0 or 1.
259
260
260 This parameter is persistent and makes calls to the embeddable shell
261 This parameter is persistent and makes calls to the embeddable shell
261 silently return without performing any action. This allows you to
262 silently return without performing any action. This allows you to
262 globally activate or deactivate a shell you're using with a single call.
263 globally activate or deactivate a shell you're using with a single call.
263
264
264 If you need to manually"""
265 If you need to manually"""
265
266
266 if dummy not in [0,1,False,True]:
267 if dummy not in [0,1,False,True]:
267 raise ValueError,'dummy parameter must be boolean'
268 raise ValueError,'dummy parameter must be boolean'
268 self.__dummy_mode = dummy
269 self.__dummy_mode = dummy
269
270
270 def get_dummy_mode(self):
271 def get_dummy_mode(self):
271 """Return the current value of the dummy mode parameter.
272 """Return the current value of the dummy mode parameter.
272 """
273 """
273 return self.__dummy_mode
274 return self.__dummy_mode
274
275
275 def set_banner(self,banner):
276 def set_banner(self,banner):
276 """Sets the global banner.
277 """Sets the global banner.
277
278
278 This banner gets prepended to every header printed when the shell
279 This banner gets prepended to every header printed when the shell
279 instance is called."""
280 instance is called."""
280
281
281 self.banner = banner
282 self.banner = banner
282
283
283 def set_exit_msg(self,exit_msg):
284 def set_exit_msg(self,exit_msg):
284 """Sets the global exit_msg.
285 """Sets the global exit_msg.
285
286
286 This exit message gets printed upon exiting every time the embedded
287 This exit message gets printed upon exiting every time the embedded
287 shell is called. It is None by default. """
288 shell is called. It is None by default. """
288
289
289 self.exit_msg = exit_msg
290 self.exit_msg = exit_msg
290
291
291 #-----------------------------------------------------------------------------
292 #-----------------------------------------------------------------------------
292 if HAS_CTYPES:
293 if HAS_CTYPES:
293 # Add async exception support. Trick taken from:
294 # Add async exception support. Trick taken from:
294 # http://sebulba.wikispaces.com/recipe+thread2
295 # http://sebulba.wikispaces.com/recipe+thread2
295 def _async_raise(tid, exctype):
296 def _async_raise(tid, exctype):
296 """raises the exception, performs cleanup if needed"""
297 """raises the exception, performs cleanup if needed"""
297 if not inspect.isclass(exctype):
298 if not inspect.isclass(exctype):
298 raise TypeError("Only types can be raised (not instances)")
299 raise TypeError("Only types can be raised (not instances)")
299 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
300 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
300 ctypes.py_object(exctype))
301 ctypes.py_object(exctype))
301 if res == 0:
302 if res == 0:
302 raise ValueError("invalid thread id")
303 raise ValueError("invalid thread id")
303 elif res != 1:
304 elif res != 1:
304 # """if it returns a number greater than one, you're in trouble,
305 # """if it returns a number greater than one, you're in trouble,
305 # and you should call it again with exc=NULL to revert the effect"""
306 # and you should call it again with exc=NULL to revert the effect"""
306 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
307 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
307 raise SystemError("PyThreadState_SetAsyncExc failed")
308 raise SystemError("PyThreadState_SetAsyncExc failed")
308
309
309 def sigint_handler (signum,stack_frame):
310 def sigint_handler (signum,stack_frame):
310 """Sigint handler for threaded apps.
311 """Sigint handler for threaded apps.
311
312
312 This is a horrible hack to pass information about SIGINT _without_
313 This is a horrible hack to pass information about SIGINT _without_
313 using exceptions, since I haven't been able to properly manage
314 using exceptions, since I haven't been able to properly manage
314 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
315 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
315 done (or at least that's my understanding from a c.l.py thread where
316 done (or at least that's my understanding from a c.l.py thread where
316 this was discussed)."""
317 this was discussed)."""
317
318
318 global KBINT
319 global KBINT
319
320
320 if CODE_RUN:
321 if CODE_RUN:
321 _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
322 _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
322 else:
323 else:
323 KBINT = True
324 KBINT = True
324 print '\nKeyboardInterrupt - Press <Enter> to continue.',
325 print '\nKeyboardInterrupt - Press <Enter> to continue.',
325 Term.cout.flush()
326 Term.cout.flush()
326
327
327 else:
328 else:
328 def sigint_handler (signum,stack_frame):
329 def sigint_handler (signum,stack_frame):
329 """Sigint handler for threaded apps.
330 """Sigint handler for threaded apps.
330
331
331 This is a horrible hack to pass information about SIGINT _without_
332 This is a horrible hack to pass information about SIGINT _without_
332 using exceptions, since I haven't been able to properly manage
333 using exceptions, since I haven't been able to properly manage
333 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
334 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
334 done (or at least that's my understanding from a c.l.py thread where
335 done (or at least that's my understanding from a c.l.py thread where
335 this was discussed)."""
336 this was discussed)."""
336
337
337 global KBINT
338 global KBINT
338
339
339 print '\nKeyboardInterrupt - Press <Enter> to continue.',
340 print '\nKeyboardInterrupt - Press <Enter> to continue.',
340 Term.cout.flush()
341 Term.cout.flush()
341 # Set global flag so that runsource can know that Ctrl-C was hit
342 # Set global flag so that runsource can know that Ctrl-C was hit
342 KBINT = True
343 KBINT = True
343
344
344
345
345 class MTInteractiveShell(InteractiveShell):
346 class MTInteractiveShell(InteractiveShell):
346 """Simple multi-threaded shell."""
347 """Simple multi-threaded shell."""
347
348
348 # Threading strategy taken from:
349 # Threading strategy taken from:
349 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
350 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
350 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
351 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
351 # from the pygtk mailing list, to avoid lockups with system calls.
352 # from the pygtk mailing list, to avoid lockups with system calls.
352
353
353 # class attribute to indicate whether the class supports threads or not.
354 # class attribute to indicate whether the class supports threads or not.
354 # Subclasses with thread support should override this as needed.
355 # Subclasses with thread support should override this as needed.
355 isthreaded = True
356 isthreaded = True
356
357
357 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
358 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
358 user_ns=None,user_global_ns=None,banner2='',
359 user_ns=None,user_global_ns=None,banner2='',
359 gui_timeout=GUI_TIMEOUT,**kw):
360 gui_timeout=GUI_TIMEOUT,**kw):
360 """Similar to the normal InteractiveShell, but with threading control"""
361 """Similar to the normal InteractiveShell, but with threading control"""
361
362
362 InteractiveShell.__init__(self,name,usage,rc,user_ns,
363 InteractiveShell.__init__(self,name,usage,rc,user_ns,
363 user_global_ns,banner2)
364 user_global_ns,banner2)
364
365
365 # Timeout we wait for GUI thread
366 # Timeout we wait for GUI thread
366 self.gui_timeout = gui_timeout
367 self.gui_timeout = gui_timeout
367
368
368 # A queue to hold the code to be executed.
369 # A queue to hold the code to be executed.
369 self.code_queue = Queue.Queue()
370 self.code_queue = Queue.Queue()
370
371
371 # Stuff to do at closing time
372 # Stuff to do at closing time
372 self._kill = None
373 self._kill = None
373 on_kill = kw.get('on_kill', [])
374 on_kill = kw.get('on_kill', [])
374 # Check that all things to kill are callable:
375 # Check that all things to kill are callable:
375 for t in on_kill:
376 for t in on_kill:
376 if not callable(t):
377 if not callable(t):
377 raise TypeError,'on_kill must be a list of callables'
378 raise TypeError,'on_kill must be a list of callables'
378 self.on_kill = on_kill
379 self.on_kill = on_kill
379 # thread identity of the "worker thread" (that may execute code directly)
380 # thread identity of the "worker thread" (that may execute code directly)
380 self.worker_ident = None
381 self.worker_ident = None
381
382
382 def runsource(self, source, filename="<input>", symbol="single"):
383 def runsource(self, source, filename="<input>", symbol="single"):
383 """Compile and run some source in the interpreter.
384 """Compile and run some source in the interpreter.
384
385
385 Modified version of code.py's runsource(), to handle threading issues.
386 Modified version of code.py's runsource(), to handle threading issues.
386 See the original for full docstring details."""
387 See the original for full docstring details."""
387
388
388 global KBINT
389 global KBINT
389
390
390 # If Ctrl-C was typed, we reset the flag and return right away
391 # If Ctrl-C was typed, we reset the flag and return right away
391 if KBINT:
392 if KBINT:
392 KBINT = False
393 KBINT = False
393 return False
394 return False
394
395
395 if self._kill:
396 if self._kill:
396 # can't queue new code if we are being killed
397 # can't queue new code if we are being killed
397 return True
398 return True
398
399
399 try:
400 try:
400 code = self.compile(source, filename, symbol)
401 code = self.compile(source, filename, symbol)
401 except (OverflowError, SyntaxError, ValueError):
402 except (OverflowError, SyntaxError, ValueError):
402 # Case 1
403 # Case 1
403 self.showsyntaxerror(filename)
404 self.showsyntaxerror(filename)
404 return False
405 return False
405
406
406 if code is None:
407 if code is None:
407 # Case 2
408 # Case 2
408 return True
409 return True
409
410
410 # shortcut - if we are in worker thread, or the worker thread is not
411 # shortcut - if we are in worker thread, or the worker thread is not
411 # running, execute directly (to allow recursion and prevent deadlock if
412 # running, execute directly (to allow recursion and prevent deadlock if
412 # code is run early in IPython construction)
413 # code is run early in IPython construction)
413
414
414 if (self.worker_ident is None
415 if (self.worker_ident is None
415 or self.worker_ident == thread.get_ident() ):
416 or self.worker_ident == thread.get_ident() ):
416 InteractiveShell.runcode(self,code)
417 InteractiveShell.runcode(self,code)
417 return
418 return
418
419
419 # Case 3
420 # Case 3
420 # Store code in queue, so the execution thread can handle it.
421 # Store code in queue, so the execution thread can handle it.
421
422
422 completed_ev, received_ev = threading.Event(), threading.Event()
423 completed_ev, received_ev = threading.Event(), threading.Event()
423
424
424 self.code_queue.put((code,completed_ev, received_ev))
425 self.code_queue.put((code,completed_ev, received_ev))
425 # first make sure the message was received, with timeout
426 # first make sure the message was received, with timeout
426 received_ev.wait(self.gui_timeout)
427 received_ev.wait(self.gui_timeout)
427 if not received_ev.isSet():
428 if not received_ev.isSet():
428 # the mainloop is dead, start executing code directly
429 # the mainloop is dead, start executing code directly
429 print "Warning: Timeout for mainloop thread exceeded"
430 print "Warning: Timeout for mainloop thread exceeded"
430 print "switching to nonthreaded mode (until mainloop wakes up again)"
431 print "switching to nonthreaded mode (until mainloop wakes up again)"
431 self.worker_ident = None
432 self.worker_ident = None
432 else:
433 else:
433 completed_ev.wait()
434 completed_ev.wait()
434 return False
435 return False
435
436
436 def runcode(self):
437 def runcode(self):
437 """Execute a code object.
438 """Execute a code object.
438
439
439 Multithreaded wrapper around IPython's runcode()."""
440 Multithreaded wrapper around IPython's runcode()."""
440
441
441 global CODE_RUN
442 global CODE_RUN
442
443
443 # we are in worker thread, stash out the id for runsource()
444 # we are in worker thread, stash out the id for runsource()
444 self.worker_ident = thread.get_ident()
445 self.worker_ident = thread.get_ident()
445
446
446 if self._kill:
447 if self._kill:
447 print >>Term.cout, 'Closing threads...',
448 print >>Term.cout, 'Closing threads...',
448 Term.cout.flush()
449 Term.cout.flush()
449 for tokill in self.on_kill:
450 for tokill in self.on_kill:
450 tokill()
451 tokill()
451 print >>Term.cout, 'Done.'
452 print >>Term.cout, 'Done.'
452 # allow kill() to return
453 # allow kill() to return
453 self._kill.set()
454 self._kill.set()
454 return True
455 return True
455
456
456 # Install sigint handler. We do it every time to ensure that if user
457 # Install sigint handler. We do it every time to ensure that if user
457 # code modifies it, we restore our own handling.
458 # code modifies it, we restore our own handling.
458 try:
459 try:
459 signal(SIGINT,sigint_handler)
460 signal(SIGINT,sigint_handler)
460 except SystemError:
461 except SystemError:
461 # This happens under Windows, which seems to have all sorts
462 # This happens under Windows, which seems to have all sorts
462 # of problems with signal handling. Oh well...
463 # of problems with signal handling. Oh well...
463 pass
464 pass
464
465
465 # Flush queue of pending code by calling the run methood of the parent
466 # Flush queue of pending code by calling the run methood of the parent
466 # class with all items which may be in the queue.
467 # class with all items which may be in the queue.
467 code_to_run = None
468 code_to_run = None
468 while 1:
469 while 1:
469 try:
470 try:
470 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
471 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
471 except Queue.Empty:
472 except Queue.Empty:
472 break
473 break
473 received_ev.set()
474 received_ev.set()
474
475
475 # Exceptions need to be raised differently depending on which
476 # Exceptions need to be raised differently depending on which
476 # thread is active. This convoluted try/except is only there to
477 # thread is active. This convoluted try/except is only there to
477 # protect against asynchronous exceptions, to ensure that a KBINT
478 # protect against asynchronous exceptions, to ensure that a KBINT
478 # at the wrong time doesn't deadlock everything. The global
479 # at the wrong time doesn't deadlock everything. The global
479 # CODE_TO_RUN is set to true/false as close as possible to the
480 # CODE_TO_RUN is set to true/false as close as possible to the
480 # runcode() call, so that the KBINT handler is correctly informed.
481 # runcode() call, so that the KBINT handler is correctly informed.
481 try:
482 try:
482 try:
483 try:
483 CODE_RUN = True
484 CODE_RUN = True
484 InteractiveShell.runcode(self,code_to_run)
485 InteractiveShell.runcode(self,code_to_run)
485 except KeyboardInterrupt:
486 except KeyboardInterrupt:
486 print "Keyboard interrupted in mainloop"
487 print "Keyboard interrupted in mainloop"
487 while not self.code_queue.empty():
488 while not self.code_queue.empty():
488 code, ev1,ev2 = self.code_queue.get_nowait()
489 code, ev1,ev2 = self.code_queue.get_nowait()
489 ev1.set()
490 ev1.set()
490 ev2.set()
491 ev2.set()
491 break
492 break
492 finally:
493 finally:
493 CODE_RUN = False
494 CODE_RUN = False
494 # allow runsource() return from wait
495 # allow runsource() return from wait
495 completed_ev.set()
496 completed_ev.set()
496
497
497
498
498 # This MUST return true for gtk threading to work
499 # This MUST return true for gtk threading to work
499 return True
500 return True
500
501
501 def kill(self):
502 def kill(self):
502 """Kill the thread, returning when it has been shut down."""
503 """Kill the thread, returning when it has been shut down."""
503 self._kill = threading.Event()
504 self._kill = threading.Event()
504 self._kill.wait()
505 self._kill.wait()
505
506
506 class MatplotlibShellBase:
507 class MatplotlibShellBase:
507 """Mixin class to provide the necessary modifications to regular IPython
508 """Mixin class to provide the necessary modifications to regular IPython
508 shell classes for matplotlib support.
509 shell classes for matplotlib support.
509
510
510 Given Python's MRO, this should be used as the FIRST class in the
511 Given Python's MRO, this should be used as the FIRST class in the
511 inheritance hierarchy, so that it overrides the relevant methods."""
512 inheritance hierarchy, so that it overrides the relevant methods."""
512
513
513 def _matplotlib_config(self,name,user_ns,user_global_ns=None):
514 def _matplotlib_config(self,name,user_ns,user_global_ns=None):
514 """Return items needed to setup the user's shell with matplotlib"""
515 """Return items needed to setup the user's shell with matplotlib"""
515
516
516 # Initialize matplotlib to interactive mode always
517 # Initialize matplotlib to interactive mode always
517 import matplotlib
518 import matplotlib
518 from matplotlib import backends
519 from matplotlib import backends
519 matplotlib.interactive(True)
520 matplotlib.interactive(True)
520
521
521 def use(arg):
522 def use(arg):
522 """IPython wrapper for matplotlib's backend switcher.
523 """IPython wrapper for matplotlib's backend switcher.
523
524
524 In interactive use, we can not allow switching to a different
525 In interactive use, we can not allow switching to a different
525 interactive backend, since thread conflicts will most likely crash
526 interactive backend, since thread conflicts will most likely crash
526 the python interpreter. This routine does a safety check first,
527 the python interpreter. This routine does a safety check first,
527 and refuses to perform a dangerous switch. It still allows
528 and refuses to perform a dangerous switch. It still allows
528 switching to non-interactive backends."""
529 switching to non-interactive backends."""
529
530
530 if arg in backends.interactive_bk and arg != self.mpl_backend:
531 if arg in backends.interactive_bk and arg != self.mpl_backend:
531 m=('invalid matplotlib backend switch.\n'
532 m=('invalid matplotlib backend switch.\n'
532 'This script attempted to switch to the interactive '
533 'This script attempted to switch to the interactive '
533 'backend: `%s`\n'
534 'backend: `%s`\n'
534 'Your current choice of interactive backend is: `%s`\n\n'
535 'Your current choice of interactive backend is: `%s`\n\n'
535 'Switching interactive matplotlib backends at runtime\n'
536 'Switching interactive matplotlib backends at runtime\n'
536 'would crash the python interpreter, '
537 'would crash the python interpreter, '
537 'and IPython has blocked it.\n\n'
538 'and IPython has blocked it.\n\n'
538 'You need to either change your choice of matplotlib backend\n'
539 'You need to either change your choice of matplotlib backend\n'
539 'by editing your .matplotlibrc file, or run this script as a \n'
540 'by editing your .matplotlibrc file, or run this script as a \n'
540 'standalone file from the command line, not using IPython.\n' %
541 'standalone file from the command line, not using IPython.\n' %
541 (arg,self.mpl_backend) )
542 (arg,self.mpl_backend) )
542 raise RuntimeError, m
543 raise RuntimeError, m
543 else:
544 else:
544 self.mpl_use(arg)
545 self.mpl_use(arg)
545 self.mpl_use._called = True
546 self.mpl_use._called = True
546
547
547 self.matplotlib = matplotlib
548 self.matplotlib = matplotlib
548 self.mpl_backend = matplotlib.rcParams['backend']
549 self.mpl_backend = matplotlib.rcParams['backend']
549
550
550 # we also need to block switching of interactive backends by use()
551 # we also need to block switching of interactive backends by use()
551 self.mpl_use = matplotlib.use
552 self.mpl_use = matplotlib.use
552 self.mpl_use._called = False
553 self.mpl_use._called = False
553 # overwrite the original matplotlib.use with our wrapper
554 # overwrite the original matplotlib.use with our wrapper
554 matplotlib.use = use
555 matplotlib.use = use
555
556
556 # This must be imported last in the matplotlib series, after
557 # This must be imported last in the matplotlib series, after
557 # backend/interactivity choices have been made
558 # backend/interactivity choices have been made
558 import matplotlib.pylab as pylab
559 import matplotlib.pylab as pylab
559 self.pylab = pylab
560 self.pylab = pylab
560
561
561 self.pylab.show._needmain = False
562 self.pylab.show._needmain = False
562 # We need to detect at runtime whether show() is called by the user.
563 # We need to detect at runtime whether show() is called by the user.
563 # For this, we wrap it into a decorator which adds a 'called' flag.
564 # For this, we wrap it into a decorator which adds a 'called' flag.
564 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
565 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
565
566
566 # Build a user namespace initialized with matplotlib/matlab features.
567 # Build a user namespace initialized with matplotlib/matlab features.
567 user_ns, user_global_ns = IPython.ipapi.make_user_namespaces(user_ns,
568 user_ns, user_global_ns = IPython.ipapi.make_user_namespaces(user_ns,
568 user_global_ns)
569 user_global_ns)
569
570
570 # Import numpy as np/pyplot as plt are conventions we're trying to
571 # Import numpy as np/pyplot as plt are conventions we're trying to
571 # somewhat standardize on. Making them available to users by default
572 # somewhat standardize on. Making them available to users by default
572 # will greatly help this.
573 # will greatly help this.
573 exec ("import numpy\n"
574 exec ("import numpy\n"
574 "import numpy as np\n"
575 "import numpy as np\n"
575 "import matplotlib\n"
576 "import matplotlib\n"
576 "import matplotlib.pylab as pylab\n"
577 "import matplotlib.pylab as pylab\n"
577 "try:\n"
578 "try:\n"
578 " import matplotlib.pyplot as plt\n"
579 " import matplotlib.pyplot as plt\n"
579 "except ImportError:\n"
580 "except ImportError:\n"
580 " pass\n"
581 " pass\n"
581 ) in user_ns
582 ) in user_ns
582
583
583 # Build matplotlib info banner
584 # Build matplotlib info banner
584 b="""
585 b="""
585 Welcome to pylab, a matplotlib-based Python environment.
586 Welcome to pylab, a matplotlib-based Python environment.
586 For more information, type 'help(pylab)'.
587 For more information, type 'help(pylab)'.
587 """
588 """
588 return user_ns,user_global_ns,b
589 return user_ns,user_global_ns,b
589
590
590 def mplot_exec(self,fname,*where,**kw):
591 def mplot_exec(self,fname,*where,**kw):
591 """Execute a matplotlib script.
592 """Execute a matplotlib script.
592
593
593 This is a call to execfile(), but wrapped in safeties to properly
594 This is a call to execfile(), but wrapped in safeties to properly
594 handle interactive rendering and backend switching."""
595 handle interactive rendering and backend switching."""
595
596
596 #print '*** Matplotlib runner ***' # dbg
597 #print '*** Matplotlib runner ***' # dbg
597 # turn off rendering until end of script
598 # turn off rendering until end of script
598 isInteractive = self.matplotlib.rcParams['interactive']
599 isInteractive = self.matplotlib.rcParams['interactive']
599 self.matplotlib.interactive(False)
600 self.matplotlib.interactive(False)
600 self.safe_execfile(fname,*where,**kw)
601 self.safe_execfile(fname,*where,**kw)
601 self.matplotlib.interactive(isInteractive)
602 self.matplotlib.interactive(isInteractive)
602 # make rendering call now, if the user tried to do it
603 # make rendering call now, if the user tried to do it
603 if self.pylab.draw_if_interactive.called:
604 if self.pylab.draw_if_interactive.called:
604 self.pylab.draw()
605 self.pylab.draw()
605 self.pylab.draw_if_interactive.called = False
606 self.pylab.draw_if_interactive.called = False
606
607
607 # if a backend switch was performed, reverse it now
608 # if a backend switch was performed, reverse it now
608 if self.mpl_use._called:
609 if self.mpl_use._called:
609 self.matplotlib.rcParams['backend'] = self.mpl_backend
610 self.matplotlib.rcParams['backend'] = self.mpl_backend
610
611
612 @testdec.skip_doctest
611 def magic_run(self,parameter_s=''):
613 def magic_run(self,parameter_s=''):
612 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
614 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
613
615
614 # Fix the docstring so users see the original as well
616 # Fix the docstring so users see the original as well
615 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
617 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
616 "\n *** Modified %run for Matplotlib,"
618 "\n *** Modified %run for Matplotlib,"
617 " with proper interactive handling ***")
619 " with proper interactive handling ***")
618
620
619 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
621 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
620 # and multithreaded. Note that these are meant for internal use, the IPShell*
622 # and multithreaded. Note that these are meant for internal use, the IPShell*
621 # classes below are the ones meant for public consumption.
623 # classes below are the ones meant for public consumption.
622
624
623 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
625 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
624 """Single-threaded shell with matplotlib support."""
626 """Single-threaded shell with matplotlib support."""
625
627
626 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
628 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
627 user_ns=None,user_global_ns=None,**kw):
629 user_ns=None,user_global_ns=None,**kw):
628 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
630 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
629 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
631 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
630 banner2=b2,**kw)
632 banner2=b2,**kw)
631
633
632 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
634 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
633 """Multi-threaded shell with matplotlib support."""
635 """Multi-threaded shell with matplotlib support."""
634
636
635 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
637 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
636 user_ns=None,user_global_ns=None, **kw):
638 user_ns=None,user_global_ns=None, **kw):
637 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
639 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
638 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
640 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
639 banner2=b2,**kw)
641 banner2=b2,**kw)
640
642
641 #-----------------------------------------------------------------------------
643 #-----------------------------------------------------------------------------
642 # Utility functions for the different GUI enabled IPShell* classes.
644 # Utility functions for the different GUI enabled IPShell* classes.
643
645
644 def get_tk():
646 def get_tk():
645 """Tries to import Tkinter and returns a withdrawn Tkinter root
647 """Tries to import Tkinter and returns a withdrawn Tkinter root
646 window. If Tkinter is already imported or not available, this
648 window. If Tkinter is already imported or not available, this
647 returns None. This function calls `hijack_tk` underneath.
649 returns None. This function calls `hijack_tk` underneath.
648 """
650 """
649 if not USE_TK or sys.modules.has_key('Tkinter'):
651 if not USE_TK or sys.modules.has_key('Tkinter'):
650 return None
652 return None
651 else:
653 else:
652 try:
654 try:
653 import Tkinter
655 import Tkinter
654 except ImportError:
656 except ImportError:
655 return None
657 return None
656 else:
658 else:
657 hijack_tk()
659 hijack_tk()
658 r = Tkinter.Tk()
660 r = Tkinter.Tk()
659 r.withdraw()
661 r.withdraw()
660 return r
662 return r
661
663
662 def hijack_tk():
664 def hijack_tk():
663 """Modifies Tkinter's mainloop with a dummy so when a module calls
665 """Modifies Tkinter's mainloop with a dummy so when a module calls
664 mainloop, it does not block.
666 mainloop, it does not block.
665
667
666 """
668 """
667 def misc_mainloop(self, n=0):
669 def misc_mainloop(self, n=0):
668 pass
670 pass
669 def tkinter_mainloop(n=0):
671 def tkinter_mainloop(n=0):
670 pass
672 pass
671
673
672 import Tkinter
674 import Tkinter
673 Tkinter.Misc.mainloop = misc_mainloop
675 Tkinter.Misc.mainloop = misc_mainloop
674 Tkinter.mainloop = tkinter_mainloop
676 Tkinter.mainloop = tkinter_mainloop
675
677
676 def update_tk(tk):
678 def update_tk(tk):
677 """Updates the Tkinter event loop. This is typically called from
679 """Updates the Tkinter event loop. This is typically called from
678 the respective WX or GTK mainloops.
680 the respective WX or GTK mainloops.
679 """
681 """
680 if tk:
682 if tk:
681 tk.update()
683 tk.update()
682
684
683 def hijack_wx():
685 def hijack_wx():
684 """Modifies wxPython's MainLoop with a dummy so user code does not
686 """Modifies wxPython's MainLoop with a dummy so user code does not
685 block IPython. The hijacked mainloop function is returned.
687 block IPython. The hijacked mainloop function is returned.
686 """
688 """
687 def dummy_mainloop(*args, **kw):
689 def dummy_mainloop(*args, **kw):
688 pass
690 pass
689
691
690 try:
692 try:
691 import wx
693 import wx
692 except ImportError:
694 except ImportError:
693 # For very old versions of WX
695 # For very old versions of WX
694 import wxPython as wx
696 import wxPython as wx
695
697
696 ver = wx.__version__
698 ver = wx.__version__
697 orig_mainloop = None
699 orig_mainloop = None
698 if ver[:3] >= '2.5':
700 if ver[:3] >= '2.5':
699 import wx
701 import wx
700 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
702 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
701 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
703 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
702 else: raise AttributeError('Could not find wx core module')
704 else: raise AttributeError('Could not find wx core module')
703 orig_mainloop = core.PyApp_MainLoop
705 orig_mainloop = core.PyApp_MainLoop
704 core.PyApp_MainLoop = dummy_mainloop
706 core.PyApp_MainLoop = dummy_mainloop
705 elif ver[:3] == '2.4':
707 elif ver[:3] == '2.4':
706 orig_mainloop = wx.wxc.wxPyApp_MainLoop
708 orig_mainloop = wx.wxc.wxPyApp_MainLoop
707 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
709 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
708 else:
710 else:
709 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
711 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
710 return orig_mainloop
712 return orig_mainloop
711
713
712 def hijack_gtk():
714 def hijack_gtk():
713 """Modifies pyGTK's mainloop with a dummy so user code does not
715 """Modifies pyGTK's mainloop with a dummy so user code does not
714 block IPython. This function returns the original `gtk.mainloop`
716 block IPython. This function returns the original `gtk.mainloop`
715 function that has been hijacked.
717 function that has been hijacked.
716 """
718 """
717 def dummy_mainloop(*args, **kw):
719 def dummy_mainloop(*args, **kw):
718 pass
720 pass
719 import gtk
721 import gtk
720 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
722 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
721 else: orig_mainloop = gtk.mainloop
723 else: orig_mainloop = gtk.mainloop
722 gtk.mainloop = dummy_mainloop
724 gtk.mainloop = dummy_mainloop
723 gtk.main = dummy_mainloop
725 gtk.main = dummy_mainloop
724 return orig_mainloop
726 return orig_mainloop
725
727
726 def hijack_qt():
728 def hijack_qt():
727 """Modifies PyQt's mainloop with a dummy so user code does not
729 """Modifies PyQt's mainloop with a dummy so user code does not
728 block IPython. This function returns the original
730 block IPython. This function returns the original
729 `qt.qApp.exec_loop` function that has been hijacked.
731 `qt.qApp.exec_loop` function that has been hijacked.
730 """
732 """
731 def dummy_mainloop(*args, **kw):
733 def dummy_mainloop(*args, **kw):
732 pass
734 pass
733 import qt
735 import qt
734 orig_mainloop = qt.qApp.exec_loop
736 orig_mainloop = qt.qApp.exec_loop
735 qt.qApp.exec_loop = dummy_mainloop
737 qt.qApp.exec_loop = dummy_mainloop
736 qt.QApplication.exec_loop = dummy_mainloop
738 qt.QApplication.exec_loop = dummy_mainloop
737 return orig_mainloop
739 return orig_mainloop
738
740
739 def hijack_qt4():
741 def hijack_qt4():
740 """Modifies PyQt4's mainloop with a dummy so user code does not
742 """Modifies PyQt4's mainloop with a dummy so user code does not
741 block IPython. This function returns the original
743 block IPython. This function returns the original
742 `QtGui.qApp.exec_` function that has been hijacked.
744 `QtGui.qApp.exec_` function that has been hijacked.
743 """
745 """
744 def dummy_mainloop(*args, **kw):
746 def dummy_mainloop(*args, **kw):
745 pass
747 pass
746 from PyQt4 import QtGui, QtCore
748 from PyQt4 import QtGui, QtCore
747 orig_mainloop = QtGui.qApp.exec_
749 orig_mainloop = QtGui.qApp.exec_
748 QtGui.qApp.exec_ = dummy_mainloop
750 QtGui.qApp.exec_ = dummy_mainloop
749 QtGui.QApplication.exec_ = dummy_mainloop
751 QtGui.QApplication.exec_ = dummy_mainloop
750 QtCore.QCoreApplication.exec_ = dummy_mainloop
752 QtCore.QCoreApplication.exec_ = dummy_mainloop
751 return orig_mainloop
753 return orig_mainloop
752
754
753 #-----------------------------------------------------------------------------
755 #-----------------------------------------------------------------------------
754 # The IPShell* classes below are the ones meant to be run by external code as
756 # The IPShell* classes below are the ones meant to be run by external code as
755 # IPython instances. Note that unless a specific threading strategy is
757 # IPython instances. Note that unless a specific threading strategy is
756 # desired, the factory function start() below should be used instead (it
758 # desired, the factory function start() below should be used instead (it
757 # selects the proper threaded class).
759 # selects the proper threaded class).
758
760
759 class IPThread(threading.Thread):
761 class IPThread(threading.Thread):
760 def run(self):
762 def run(self):
761 self.IP.mainloop(self._banner)
763 self.IP.mainloop(self._banner)
762 self.IP.kill()
764 self.IP.kill()
763
765
764 class IPShellGTK(IPThread):
766 class IPShellGTK(IPThread):
765 """Run a gtk mainloop() in a separate thread.
767 """Run a gtk mainloop() in a separate thread.
766
768
767 Python commands can be passed to the thread where they will be executed.
769 Python commands can be passed to the thread where they will be executed.
768 This is implemented by periodically checking for passed code using a
770 This is implemented by periodically checking for passed code using a
769 GTK timeout callback."""
771 GTK timeout callback."""
770
772
771 TIMEOUT = 100 # Millisecond interval between timeouts.
773 TIMEOUT = 100 # Millisecond interval between timeouts.
772
774
773 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
775 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
774 debug=1,shell_class=MTInteractiveShell):
776 debug=1,shell_class=MTInteractiveShell):
775
777
776 import gtk
778 import gtk
777
779
778 self.gtk = gtk
780 self.gtk = gtk
779 self.gtk_mainloop = hijack_gtk()
781 self.gtk_mainloop = hijack_gtk()
780
782
781 # Allows us to use both Tk and GTK.
783 # Allows us to use both Tk and GTK.
782 self.tk = get_tk()
784 self.tk = get_tk()
783
785
784 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
786 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
785 else: mainquit = self.gtk.mainquit
787 else: mainquit = self.gtk.mainquit
786
788
787 self.IP = make_IPython(argv,user_ns=user_ns,
789 self.IP = make_IPython(argv,user_ns=user_ns,
788 user_global_ns=user_global_ns,
790 user_global_ns=user_global_ns,
789 debug=debug,
791 debug=debug,
790 shell_class=shell_class,
792 shell_class=shell_class,
791 on_kill=[mainquit])
793 on_kill=[mainquit])
792
794
793 # HACK: slot for banner in self; it will be passed to the mainloop
795 # HACK: slot for banner in self; it will be passed to the mainloop
794 # method only and .run() needs it. The actual value will be set by
796 # method only and .run() needs it. The actual value will be set by
795 # .mainloop().
797 # .mainloop().
796 self._banner = None
798 self._banner = None
797
799
798 threading.Thread.__init__(self)
800 threading.Thread.__init__(self)
799
801
800 def mainloop(self,sys_exit=0,banner=None):
802 def mainloop(self,sys_exit=0,banner=None):
801
803
802 self._banner = banner
804 self._banner = banner
803
805
804 if self.gtk.pygtk_version >= (2,4,0):
806 if self.gtk.pygtk_version >= (2,4,0):
805 import gobject
807 import gobject
806 gobject.idle_add(self.on_timer)
808 gobject.idle_add(self.on_timer)
807 else:
809 else:
808 self.gtk.idle_add(self.on_timer)
810 self.gtk.idle_add(self.on_timer)
809
811
810 if sys.platform != 'win32':
812 if sys.platform != 'win32':
811 try:
813 try:
812 if self.gtk.gtk_version[0] >= 2:
814 if self.gtk.gtk_version[0] >= 2:
813 self.gtk.gdk.threads_init()
815 self.gtk.gdk.threads_init()
814 except AttributeError:
816 except AttributeError:
815 pass
817 pass
816 except RuntimeError:
818 except RuntimeError:
817 error('Your pyGTK likely has not been compiled with '
819 error('Your pyGTK likely has not been compiled with '
818 'threading support.\n'
820 'threading support.\n'
819 'The exception printout is below.\n'
821 'The exception printout is below.\n'
820 'You can either rebuild pyGTK with threads, or '
822 'You can either rebuild pyGTK with threads, or '
821 'try using \n'
823 'try using \n'
822 'matplotlib with a different backend (like Tk or WX).\n'
824 'matplotlib with a different backend (like Tk or WX).\n'
823 'Note that matplotlib will most likely not work in its '
825 'Note that matplotlib will most likely not work in its '
824 'current state!')
826 'current state!')
825 self.IP.InteractiveTB()
827 self.IP.InteractiveTB()
826
828
827 self.start()
829 self.start()
828 self.gtk.gdk.threads_enter()
830 self.gtk.gdk.threads_enter()
829 self.gtk_mainloop()
831 self.gtk_mainloop()
830 self.gtk.gdk.threads_leave()
832 self.gtk.gdk.threads_leave()
831 self.join()
833 self.join()
832
834
833 def on_timer(self):
835 def on_timer(self):
834 """Called when GTK is idle.
836 """Called when GTK is idle.
835
837
836 Must return True always, otherwise GTK stops calling it"""
838 Must return True always, otherwise GTK stops calling it"""
837
839
838 update_tk(self.tk)
840 update_tk(self.tk)
839 self.IP.runcode()
841 self.IP.runcode()
840 time.sleep(0.01)
842 time.sleep(0.01)
841 return True
843 return True
842
844
843
845
844 class IPShellWX(IPThread):
846 class IPShellWX(IPThread):
845 """Run a wx mainloop() in a separate thread.
847 """Run a wx mainloop() in a separate thread.
846
848
847 Python commands can be passed to the thread where they will be executed.
849 Python commands can be passed to the thread where they will be executed.
848 This is implemented by periodically checking for passed code using a
850 This is implemented by periodically checking for passed code using a
849 GTK timeout callback."""
851 GTK timeout callback."""
850
852
851 TIMEOUT = 100 # Millisecond interval between timeouts.
853 TIMEOUT = 100 # Millisecond interval between timeouts.
852
854
853 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
855 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
854 debug=1,shell_class=MTInteractiveShell):
856 debug=1,shell_class=MTInteractiveShell):
855
857
856 self.IP = make_IPython(argv,user_ns=user_ns,
858 self.IP = make_IPython(argv,user_ns=user_ns,
857 user_global_ns=user_global_ns,
859 user_global_ns=user_global_ns,
858 debug=debug,
860 debug=debug,
859 shell_class=shell_class,
861 shell_class=shell_class,
860 on_kill=[self.wxexit])
862 on_kill=[self.wxexit])
861
863
862 wantedwxversion=self.IP.rc.wxversion
864 wantedwxversion=self.IP.rc.wxversion
863 if wantedwxversion!="0":
865 if wantedwxversion!="0":
864 try:
866 try:
865 import wxversion
867 import wxversion
866 except ImportError:
868 except ImportError:
867 error('The wxversion module is needed for WX version selection')
869 error('The wxversion module is needed for WX version selection')
868 else:
870 else:
869 try:
871 try:
870 wxversion.select(wantedwxversion)
872 wxversion.select(wantedwxversion)
871 except:
873 except:
872 self.IP.InteractiveTB()
874 self.IP.InteractiveTB()
873 error('Requested wxPython version %s could not be loaded' %
875 error('Requested wxPython version %s could not be loaded' %
874 wantedwxversion)
876 wantedwxversion)
875
877
876 import wx
878 import wx
877
879
878 threading.Thread.__init__(self)
880 threading.Thread.__init__(self)
879 self.wx = wx
881 self.wx = wx
880 self.wx_mainloop = hijack_wx()
882 self.wx_mainloop = hijack_wx()
881
883
882 # Allows us to use both Tk and GTK.
884 # Allows us to use both Tk and GTK.
883 self.tk = get_tk()
885 self.tk = get_tk()
884
886
885 # HACK: slot for banner in self; it will be passed to the mainloop
887 # HACK: slot for banner in self; it will be passed to the mainloop
886 # method only and .run() needs it. The actual value will be set by
888 # method only and .run() needs it. The actual value will be set by
887 # .mainloop().
889 # .mainloop().
888 self._banner = None
890 self._banner = None
889
891
890 self.app = None
892 self.app = None
891
893
892 def wxexit(self, *args):
894 def wxexit(self, *args):
893 if self.app is not None:
895 if self.app is not None:
894 self.app.agent.timer.Stop()
896 self.app.agent.timer.Stop()
895 self.app.ExitMainLoop()
897 self.app.ExitMainLoop()
896
898
897 def mainloop(self,sys_exit=0,banner=None):
899 def mainloop(self,sys_exit=0,banner=None):
898
900
899 self._banner = banner
901 self._banner = banner
900
902
901 self.start()
903 self.start()
902
904
903 class TimerAgent(self.wx.MiniFrame):
905 class TimerAgent(self.wx.MiniFrame):
904 wx = self.wx
906 wx = self.wx
905 IP = self.IP
907 IP = self.IP
906 tk = self.tk
908 tk = self.tk
907 def __init__(self, parent, interval):
909 def __init__(self, parent, interval):
908 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
910 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
909 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
911 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
910 size=(100, 100),style=style)
912 size=(100, 100),style=style)
911 self.Show(False)
913 self.Show(False)
912 self.interval = interval
914 self.interval = interval
913 self.timerId = self.wx.NewId()
915 self.timerId = self.wx.NewId()
914
916
915 def StartWork(self):
917 def StartWork(self):
916 self.timer = self.wx.Timer(self, self.timerId)
918 self.timer = self.wx.Timer(self, self.timerId)
917 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
919 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
918 self.timer.Start(self.interval)
920 self.timer.Start(self.interval)
919
921
920 def OnTimer(self, event):
922 def OnTimer(self, event):
921 update_tk(self.tk)
923 update_tk(self.tk)
922 self.IP.runcode()
924 self.IP.runcode()
923
925
924 class App(self.wx.App):
926 class App(self.wx.App):
925 wx = self.wx
927 wx = self.wx
926 TIMEOUT = self.TIMEOUT
928 TIMEOUT = self.TIMEOUT
927 def OnInit(self):
929 def OnInit(self):
928 'Create the main window and insert the custom frame'
930 'Create the main window and insert the custom frame'
929 self.agent = TimerAgent(None, self.TIMEOUT)
931 self.agent = TimerAgent(None, self.TIMEOUT)
930 self.agent.Show(False)
932 self.agent.Show(False)
931 self.agent.StartWork()
933 self.agent.StartWork()
932 return True
934 return True
933
935
934 self.app = App(redirect=False)
936 self.app = App(redirect=False)
935 self.wx_mainloop(self.app)
937 self.wx_mainloop(self.app)
936 self.join()
938 self.join()
937
939
938
940
939 class IPShellQt(IPThread):
941 class IPShellQt(IPThread):
940 """Run a Qt event loop in a separate thread.
942 """Run a Qt event loop in a separate thread.
941
943
942 Python commands can be passed to the thread where they will be executed.
944 Python commands can be passed to the thread where they will be executed.
943 This is implemented by periodically checking for passed code using a
945 This is implemented by periodically checking for passed code using a
944 Qt timer / slot."""
946 Qt timer / slot."""
945
947
946 TIMEOUT = 100 # Millisecond interval between timeouts.
948 TIMEOUT = 100 # Millisecond interval between timeouts.
947
949
948 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
950 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
949 debug=0, shell_class=MTInteractiveShell):
951 debug=0, shell_class=MTInteractiveShell):
950
952
951 import qt
953 import qt
952
954
953 self.exec_loop = hijack_qt()
955 self.exec_loop = hijack_qt()
954
956
955 # Allows us to use both Tk and QT.
957 # Allows us to use both Tk and QT.
956 self.tk = get_tk()
958 self.tk = get_tk()
957
959
958 self.IP = make_IPython(argv,
960 self.IP = make_IPython(argv,
959 user_ns=user_ns,
961 user_ns=user_ns,
960 user_global_ns=user_global_ns,
962 user_global_ns=user_global_ns,
961 debug=debug,
963 debug=debug,
962 shell_class=shell_class,
964 shell_class=shell_class,
963 on_kill=[qt.qApp.exit])
965 on_kill=[qt.qApp.exit])
964
966
965 # HACK: slot for banner in self; it will be passed to the mainloop
967 # HACK: slot for banner in self; it will be passed to the mainloop
966 # method only and .run() needs it. The actual value will be set by
968 # method only and .run() needs it. The actual value will be set by
967 # .mainloop().
969 # .mainloop().
968 self._banner = None
970 self._banner = None
969
971
970 threading.Thread.__init__(self)
972 threading.Thread.__init__(self)
971
973
972 def mainloop(self, sys_exit=0, banner=None):
974 def mainloop(self, sys_exit=0, banner=None):
973
975
974 import qt
976 import qt
975
977
976 self._banner = banner
978 self._banner = banner
977
979
978 if qt.QApplication.startingUp():
980 if qt.QApplication.startingUp():
979 a = qt.QApplication(sys.argv)
981 a = qt.QApplication(sys.argv)
980
982
981 self.timer = qt.QTimer()
983 self.timer = qt.QTimer()
982 qt.QObject.connect(self.timer,
984 qt.QObject.connect(self.timer,
983 qt.SIGNAL('timeout()'),
985 qt.SIGNAL('timeout()'),
984 self.on_timer)
986 self.on_timer)
985
987
986 self.start()
988 self.start()
987 self.timer.start(self.TIMEOUT, True)
989 self.timer.start(self.TIMEOUT, True)
988 while True:
990 while True:
989 if self.IP._kill: break
991 if self.IP._kill: break
990 self.exec_loop()
992 self.exec_loop()
991 self.join()
993 self.join()
992
994
993 def on_timer(self):
995 def on_timer(self):
994 update_tk(self.tk)
996 update_tk(self.tk)
995 result = self.IP.runcode()
997 result = self.IP.runcode()
996 self.timer.start(self.TIMEOUT, True)
998 self.timer.start(self.TIMEOUT, True)
997 return result
999 return result
998
1000
999
1001
1000 class IPShellQt4(IPThread):
1002 class IPShellQt4(IPThread):
1001 """Run a Qt event loop in a separate thread.
1003 """Run a Qt event loop in a separate thread.
1002
1004
1003 Python commands can be passed to the thread where they will be executed.
1005 Python commands can be passed to the thread where they will be executed.
1004 This is implemented by periodically checking for passed code using a
1006 This is implemented by periodically checking for passed code using a
1005 Qt timer / slot."""
1007 Qt timer / slot."""
1006
1008
1007 TIMEOUT = 100 # Millisecond interval between timeouts.
1009 TIMEOUT = 100 # Millisecond interval between timeouts.
1008
1010
1009 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
1011 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
1010 debug=0, shell_class=MTInteractiveShell):
1012 debug=0, shell_class=MTInteractiveShell):
1011
1013
1012 from PyQt4 import QtCore, QtGui
1014 from PyQt4 import QtCore, QtGui
1013
1015
1014 try:
1016 try:
1015 # present in PyQt4-4.2.1 or later
1017 # present in PyQt4-4.2.1 or later
1016 QtCore.pyqtRemoveInputHook()
1018 QtCore.pyqtRemoveInputHook()
1017 except AttributeError:
1019 except AttributeError:
1018 pass
1020 pass
1019
1021
1020 if QtCore.PYQT_VERSION_STR == '4.3':
1022 if QtCore.PYQT_VERSION_STR == '4.3':
1021 warn('''PyQt4 version 4.3 detected.
1023 warn('''PyQt4 version 4.3 detected.
1022 If you experience repeated threading warnings, please update PyQt4.
1024 If you experience repeated threading warnings, please update PyQt4.
1023 ''')
1025 ''')
1024
1026
1025 self.exec_ = hijack_qt4()
1027 self.exec_ = hijack_qt4()
1026
1028
1027 # Allows us to use both Tk and QT.
1029 # Allows us to use both Tk and QT.
1028 self.tk = get_tk()
1030 self.tk = get_tk()
1029
1031
1030 self.IP = make_IPython(argv,
1032 self.IP = make_IPython(argv,
1031 user_ns=user_ns,
1033 user_ns=user_ns,
1032 user_global_ns=user_global_ns,
1034 user_global_ns=user_global_ns,
1033 debug=debug,
1035 debug=debug,
1034 shell_class=shell_class,
1036 shell_class=shell_class,
1035 on_kill=[QtGui.qApp.exit])
1037 on_kill=[QtGui.qApp.exit])
1036
1038
1037 # HACK: slot for banner in self; it will be passed to the mainloop
1039 # HACK: slot for banner in self; it will be passed to the mainloop
1038 # method only and .run() needs it. The actual value will be set by
1040 # method only and .run() needs it. The actual value will be set by
1039 # .mainloop().
1041 # .mainloop().
1040 self._banner = None
1042 self._banner = None
1041
1043
1042 threading.Thread.__init__(self)
1044 threading.Thread.__init__(self)
1043
1045
1044 def mainloop(self, sys_exit=0, banner=None):
1046 def mainloop(self, sys_exit=0, banner=None):
1045
1047
1046 from PyQt4 import QtCore, QtGui
1048 from PyQt4 import QtCore, QtGui
1047
1049
1048 self._banner = banner
1050 self._banner = banner
1049
1051
1050 if QtGui.QApplication.startingUp():
1052 if QtGui.QApplication.startingUp():
1051 a = QtGui.QApplication(sys.argv)
1053 a = QtGui.QApplication(sys.argv)
1052
1054
1053 self.timer = QtCore.QTimer()
1055 self.timer = QtCore.QTimer()
1054 QtCore.QObject.connect(self.timer,
1056 QtCore.QObject.connect(self.timer,
1055 QtCore.SIGNAL('timeout()'),
1057 QtCore.SIGNAL('timeout()'),
1056 self.on_timer)
1058 self.on_timer)
1057
1059
1058 self.start()
1060 self.start()
1059 self.timer.start(self.TIMEOUT)
1061 self.timer.start(self.TIMEOUT)
1060 while True:
1062 while True:
1061 if self.IP._kill: break
1063 if self.IP._kill: break
1062 self.exec_()
1064 self.exec_()
1063 self.join()
1065 self.join()
1064
1066
1065 def on_timer(self):
1067 def on_timer(self):
1066 update_tk(self.tk)
1068 update_tk(self.tk)
1067 result = self.IP.runcode()
1069 result = self.IP.runcode()
1068 self.timer.start(self.TIMEOUT)
1070 self.timer.start(self.TIMEOUT)
1069 return result
1071 return result
1070
1072
1071
1073
1072 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1074 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1073 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1075 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1074 def _load_pylab(user_ns):
1076 def _load_pylab(user_ns):
1075 """Allow users to disable pulling all of pylab into the top-level
1077 """Allow users to disable pulling all of pylab into the top-level
1076 namespace.
1078 namespace.
1077
1079
1078 This little utility must be called AFTER the actual ipython instance is
1080 This little utility must be called AFTER the actual ipython instance is
1079 running, since only then will the options file have been fully parsed."""
1081 running, since only then will the options file have been fully parsed."""
1080
1082
1081 ip = IPython.ipapi.get()
1083 ip = IPython.ipapi.get()
1082 if ip.options.pylab_import_all:
1084 if ip.options.pylab_import_all:
1083 ip.ex("from matplotlib.pylab import *")
1085 ip.ex("from matplotlib.pylab import *")
1084 ip.IP.user_config_ns.update(ip.user_ns)
1086 ip.IP.user_config_ns.update(ip.user_ns)
1085
1087
1086
1088
1087 class IPShellMatplotlib(IPShell):
1089 class IPShellMatplotlib(IPShell):
1088 """Subclass IPShell with MatplotlibShell as the internal shell.
1090 """Subclass IPShell with MatplotlibShell as the internal shell.
1089
1091
1090 Single-threaded class, meant for the Tk* and FLTK* backends.
1092 Single-threaded class, meant for the Tk* and FLTK* backends.
1091
1093
1092 Having this on a separate class simplifies the external driver code."""
1094 Having this on a separate class simplifies the external driver code."""
1093
1095
1094 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1096 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1095 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1097 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1096 shell_class=MatplotlibShell)
1098 shell_class=MatplotlibShell)
1097 _load_pylab(self.IP.user_ns)
1099 _load_pylab(self.IP.user_ns)
1098
1100
1099 class IPShellMatplotlibGTK(IPShellGTK):
1101 class IPShellMatplotlibGTK(IPShellGTK):
1100 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1102 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1101
1103
1102 Multi-threaded class, meant for the GTK* backends."""
1104 Multi-threaded class, meant for the GTK* backends."""
1103
1105
1104 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1106 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1105 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1107 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1106 shell_class=MatplotlibMTShell)
1108 shell_class=MatplotlibMTShell)
1107 _load_pylab(self.IP.user_ns)
1109 _load_pylab(self.IP.user_ns)
1108
1110
1109 class IPShellMatplotlibWX(IPShellWX):
1111 class IPShellMatplotlibWX(IPShellWX):
1110 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1112 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1111
1113
1112 Multi-threaded class, meant for the WX* backends."""
1114 Multi-threaded class, meant for the WX* backends."""
1113
1115
1114 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1116 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1115 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1117 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1116 shell_class=MatplotlibMTShell)
1118 shell_class=MatplotlibMTShell)
1117 _load_pylab(self.IP.user_ns)
1119 _load_pylab(self.IP.user_ns)
1118
1120
1119 class IPShellMatplotlibQt(IPShellQt):
1121 class IPShellMatplotlibQt(IPShellQt):
1120 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1122 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1121
1123
1122 Multi-threaded class, meant for the Qt* backends."""
1124 Multi-threaded class, meant for the Qt* backends."""
1123
1125
1124 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1126 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1125 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1127 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1126 shell_class=MatplotlibMTShell)
1128 shell_class=MatplotlibMTShell)
1127 _load_pylab(self.IP.user_ns)
1129 _load_pylab(self.IP.user_ns)
1128
1130
1129 class IPShellMatplotlibQt4(IPShellQt4):
1131 class IPShellMatplotlibQt4(IPShellQt4):
1130 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1132 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1131
1133
1132 Multi-threaded class, meant for the Qt4* backends."""
1134 Multi-threaded class, meant for the Qt4* backends."""
1133
1135
1134 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1136 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1135 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1137 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1136 shell_class=MatplotlibMTShell)
1138 shell_class=MatplotlibMTShell)
1137 _load_pylab(self.IP.user_ns)
1139 _load_pylab(self.IP.user_ns)
1138
1140
1139 #-----------------------------------------------------------------------------
1141 #-----------------------------------------------------------------------------
1140 # Factory functions to actually start the proper thread-aware shell
1142 # Factory functions to actually start the proper thread-aware shell
1141
1143
1142 def _select_shell(argv):
1144 def _select_shell(argv):
1143 """Select a shell from the given argv vector.
1145 """Select a shell from the given argv vector.
1144
1146
1145 This function implements the threading selection policy, allowing runtime
1147 This function implements the threading selection policy, allowing runtime
1146 control of the threading mode, both for general users and for matplotlib.
1148 control of the threading mode, both for general users and for matplotlib.
1147
1149
1148 Return:
1150 Return:
1149 Shell class to be instantiated for runtime operation.
1151 Shell class to be instantiated for runtime operation.
1150 """
1152 """
1151
1153
1152 global USE_TK
1154 global USE_TK
1153
1155
1154 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1156 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1155 'wthread' : IPShellMatplotlibWX,
1157 'wthread' : IPShellMatplotlibWX,
1156 'qthread' : IPShellMatplotlibQt,
1158 'qthread' : IPShellMatplotlibQt,
1157 'q4thread' : IPShellMatplotlibQt4,
1159 'q4thread' : IPShellMatplotlibQt4,
1158 'tkthread' : IPShellMatplotlib, # Tk is built-in
1160 'tkthread' : IPShellMatplotlib, # Tk is built-in
1159 }
1161 }
1160
1162
1161 th_shell = {'gthread' : IPShellGTK,
1163 th_shell = {'gthread' : IPShellGTK,
1162 'wthread' : IPShellWX,
1164 'wthread' : IPShellWX,
1163 'qthread' : IPShellQt,
1165 'qthread' : IPShellQt,
1164 'q4thread' : IPShellQt4,
1166 'q4thread' : IPShellQt4,
1165 'tkthread' : IPShell, # Tk is built-in
1167 'tkthread' : IPShell, # Tk is built-in
1166 }
1168 }
1167
1169
1168 backends = {'gthread' : 'GTKAgg',
1170 backends = {'gthread' : 'GTKAgg',
1169 'wthread' : 'WXAgg',
1171 'wthread' : 'WXAgg',
1170 'qthread' : 'QtAgg',
1172 'qthread' : 'QtAgg',
1171 'q4thread' :'Qt4Agg',
1173 'q4thread' :'Qt4Agg',
1172 'tkthread' :'TkAgg',
1174 'tkthread' :'TkAgg',
1173 }
1175 }
1174
1176
1175 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1177 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1176 'tkthread'])
1178 'tkthread'])
1177 user_opts = set([s.replace('-','') for s in argv[:3]])
1179 user_opts = set([s.replace('-','') for s in argv[:3]])
1178 special_opts = user_opts & all_opts
1180 special_opts = user_opts & all_opts
1179
1181
1180 if 'tk' in special_opts:
1182 if 'tk' in special_opts:
1181 USE_TK = True
1183 USE_TK = True
1182 special_opts.remove('tk')
1184 special_opts.remove('tk')
1183
1185
1184 if 'pylab' in special_opts:
1186 if 'pylab' in special_opts:
1185
1187
1186 try:
1188 try:
1187 import matplotlib
1189 import matplotlib
1188 except ImportError:
1190 except ImportError:
1189 error('matplotlib could NOT be imported! Starting normal IPython.')
1191 error('matplotlib could NOT be imported! Starting normal IPython.')
1190 return IPShell
1192 return IPShell
1191
1193
1192 special_opts.remove('pylab')
1194 special_opts.remove('pylab')
1193 # If there's any option left, it means the user wants to force the
1195 # If there's any option left, it means the user wants to force the
1194 # threading backend, else it's auto-selected from the rc file
1196 # threading backend, else it's auto-selected from the rc file
1195 if special_opts:
1197 if special_opts:
1196 th_mode = special_opts.pop()
1198 th_mode = special_opts.pop()
1197 matplotlib.rcParams['backend'] = backends[th_mode]
1199 matplotlib.rcParams['backend'] = backends[th_mode]
1198 else:
1200 else:
1199 backend = matplotlib.rcParams['backend']
1201 backend = matplotlib.rcParams['backend']
1200 if backend.startswith('GTK'):
1202 if backend.startswith('GTK'):
1201 th_mode = 'gthread'
1203 th_mode = 'gthread'
1202 elif backend.startswith('WX'):
1204 elif backend.startswith('WX'):
1203 th_mode = 'wthread'
1205 th_mode = 'wthread'
1204 elif backend.startswith('Qt4'):
1206 elif backend.startswith('Qt4'):
1205 th_mode = 'q4thread'
1207 th_mode = 'q4thread'
1206 elif backend.startswith('Qt'):
1208 elif backend.startswith('Qt'):
1207 th_mode = 'qthread'
1209 th_mode = 'qthread'
1208 else:
1210 else:
1209 # Any other backend, use plain Tk
1211 # Any other backend, use plain Tk
1210 th_mode = 'tkthread'
1212 th_mode = 'tkthread'
1211
1213
1212 return mpl_shell[th_mode]
1214 return mpl_shell[th_mode]
1213 else:
1215 else:
1214 # No pylab requested, just plain threads
1216 # No pylab requested, just plain threads
1215 try:
1217 try:
1216 th_mode = special_opts.pop()
1218 th_mode = special_opts.pop()
1217 except KeyError:
1219 except KeyError:
1218 th_mode = 'tkthread'
1220 th_mode = 'tkthread'
1219 return th_shell[th_mode]
1221 return th_shell[th_mode]
1220
1222
1221
1223
1222 # This is the one which should be called by external code.
1224 # This is the one which should be called by external code.
1223 def start(user_ns = None):
1225 def start(user_ns = None):
1224 """Return a running shell instance, dealing with threading options.
1226 """Return a running shell instance, dealing with threading options.
1225
1227
1226 This is a factory function which will instantiate the proper IPython shell
1228 This is a factory function which will instantiate the proper IPython shell
1227 based on the user's threading choice. Such a selector is needed because
1229 based on the user's threading choice. Such a selector is needed because
1228 different GUI toolkits require different thread handling details."""
1230 different GUI toolkits require different thread handling details."""
1229
1231
1230 shell = _select_shell(sys.argv)
1232 shell = _select_shell(sys.argv)
1231 return shell(user_ns = user_ns)
1233 return shell(user_ns = user_ns)
1232
1234
1233 # Some aliases for backwards compatibility
1235 # Some aliases for backwards compatibility
1234 IPythonShell = IPShell
1236 IPythonShell = IPShell
1235 IPythonShellEmbed = IPShellEmbed
1237 IPythonShellEmbed = IPShellEmbed
1236 #************************ End of file <Shell.py> ***************************
1238 #************************ End of file <Shell.py> ***************************
@@ -1,784 +1,806 b''
1 """Nose Plugin that supports IPython doctests.
1 """Nose Plugin that supports IPython doctests.
2
2
3 Limitations:
3 Limitations:
4
4
5 - When generating examples for use as doctests, make sure that you have
5 - When generating examples for use as doctests, make sure that you have
6 pretty-printing OFF. This can be done either by starting ipython with the
6 pretty-printing OFF. This can be done either by starting ipython with the
7 flag '--nopprint', by setting pprint to 0 in your ipythonrc file, or by
7 flag '--nopprint', by setting pprint to 0 in your ipythonrc file, or by
8 interactively disabling it with %Pprint. This is required so that IPython
8 interactively disabling it with %Pprint. This is required so that IPython
9 output matches that of normal Python, which is used by doctest for internal
9 output matches that of normal Python, which is used by doctest for internal
10 execution.
10 execution.
11
11
12 - Do not rely on specific prompt numbers for results (such as using
12 - Do not rely on specific prompt numbers for results (such as using
13 '_34==True', for example). For IPython tests run via an external process the
13 '_34==True', for example). For IPython tests run via an external process the
14 prompt numbers may be different, and IPython tests run as normal python code
14 prompt numbers may be different, and IPython tests run as normal python code
15 won't even have these special _NN variables set at all.
15 won't even have these special _NN variables set at all.
16 """
16 """
17
17
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Module imports
20 # Module imports
21
21
22 # From the standard library
22 # From the standard library
23 import __builtin__
23 import __builtin__
24 import commands
24 import commands
25 import doctest
25 import doctest
26 import inspect
26 import inspect
27 import logging
27 import logging
28 import os
28 import os
29 import re
29 import re
30 import sys
30 import sys
31 import traceback
31 import traceback
32 import unittest
32 import unittest
33
33
34 from inspect import getmodule
34 from inspect import getmodule
35 from StringIO import StringIO
35 from StringIO import StringIO
36
36
37 # We are overriding the default doctest runner, so we need to import a few
37 # We are overriding the default doctest runner, so we need to import a few
38 # things from doctest directly
38 # things from doctest directly
39 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
39 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
40 _unittest_reportflags, DocTestRunner,
40 _unittest_reportflags, DocTestRunner,
41 _extract_future_flags, pdb, _OutputRedirectingPdb,
41 _extract_future_flags, pdb, _OutputRedirectingPdb,
42 _exception_traceback,
42 _exception_traceback,
43 linecache)
43 linecache)
44
44
45 # Third-party modules
45 # Third-party modules
46 import nose.core
46 import nose.core
47
47
48 from nose.plugins import doctests, Plugin
48 from nose.plugins import doctests, Plugin
49 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
49 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
50
50
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52 # Module globals and other constants
52 # Module globals and other constants
53
53
54 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
55
55
56 ###########################################################################
56 ###########################################################################
57 # *** HACK ***
57 # *** HACK ***
58 # We must start our own ipython object and heavily muck with it so that all the
58 # We must start our own ipython object and heavily muck with it so that all the
59 # modifications IPython makes to system behavior don't send the doctest
59 # modifications IPython makes to system behavior don't send the doctest
60 # machinery into a fit. This code should be considered a gross hack, but it
60 # machinery into a fit. This code should be considered a gross hack, but it
61 # gets the job done.
61 # gets the job done.
62
62
63
63
64 # Hack to modify the %run command so we can sync the user's namespace with the
64 # Hack to modify the %run command so we can sync the user's namespace with the
65 # test globals. Once we move over to a clean magic system, this will be done
65 # test globals. Once we move over to a clean magic system, this will be done
66 # with much less ugliness.
66 # with much less ugliness.
67
67
68 def _run_ns_sync(self,arg_s,runner=None):
68 def _run_ns_sync(self,arg_s,runner=None):
69 """Modified version of %run that syncs testing namespaces.
69 """Modified version of %run that syncs testing namespaces.
70
70
71 This is strictly needed for running doctests that call %run.
71 This is strictly needed for running doctests that call %run.
72 """
72 """
73
73
74 out = _ip.IP.magic_run_ori(arg_s,runner)
74 out = _ip.IP.magic_run_ori(arg_s,runner)
75 _run_ns_sync.test_globs.update(_ip.user_ns)
75 _run_ns_sync.test_globs.update(_ip.user_ns)
76 return out
76 return out
77
77
78
78
79 class ipnsdict(dict):
79 class ipnsdict(dict):
80 """A special subclass of dict for use as an IPython namespace in doctests.
80 """A special subclass of dict for use as an IPython namespace in doctests.
81
81
82 This subclass adds a simple checkpointing capability so that when testing
82 This subclass adds a simple checkpointing capability so that when testing
83 machinery clears it (we use it as the test execution context), it doesn't
83 machinery clears it (we use it as the test execution context), it doesn't
84 get completely destroyed.
84 get completely destroyed.
85 """
85 """
86
86
87 def __init__(self,*a):
87 def __init__(self,*a):
88 dict.__init__(self,*a)
88 dict.__init__(self,*a)
89 self._savedict = {}
89 self._savedict = {}
90
90
91 def clear(self):
91 def clear(self):
92 dict.clear(self)
92 dict.clear(self)
93 self.update(self._savedict)
93 self.update(self._savedict)
94
94
95 def _checkpoint(self):
95 def _checkpoint(self):
96 self._savedict.clear()
96 self._savedict.clear()
97 self._savedict.update(self)
97 self._savedict.update(self)
98
98
99 def update(self,other):
99 def update(self,other):
100 self._checkpoint()
100 self._checkpoint()
101 dict.update(self,other)
101 dict.update(self,other)
102 # If '_' is in the namespace, python won't set it when executing code,
102 # If '_' is in the namespace, python won't set it when executing code,
103 # and we have examples that test it. So we ensure that the namespace
103 # and we have examples that test it. So we ensure that the namespace
104 # is always 'clean' of it before it's used for test code execution.
104 # is always 'clean' of it before it's used for test code execution.
105 self.pop('_',None)
105 self.pop('_',None)
106
106
107
107
108 def start_ipython():
108 def start_ipython():
109 """Start a global IPython shell, which we need for IPython-specific syntax.
109 """Start a global IPython shell, which we need for IPython-specific syntax.
110 """
110 """
111 import new
111 import new
112
112
113 import IPython
113 import IPython
114
114
115 def xsys(cmd):
115 def xsys(cmd):
116 """Execute a command and print its output.
116 """Execute a command and print its output.
117
117
118 This is just a convenience function to replace the IPython system call
118 This is just a convenience function to replace the IPython system call
119 with one that is more doctest-friendly.
119 with one that is more doctest-friendly.
120 """
120 """
121 cmd = _ip.IP.var_expand(cmd,depth=1)
121 cmd = _ip.IP.var_expand(cmd,depth=1)
122 sys.stdout.write(commands.getoutput(cmd))
122 sys.stdout.write(commands.getoutput(cmd))
123 sys.stdout.flush()
123 sys.stdout.flush()
124
124
125 # Store certain global objects that IPython modifies
125 # Store certain global objects that IPython modifies
126 _displayhook = sys.displayhook
126 _displayhook = sys.displayhook
127 _excepthook = sys.excepthook
127 _excepthook = sys.excepthook
128 _main = sys.modules.get('__main__')
128 _main = sys.modules.get('__main__')
129
129
130 # Start IPython instance. We customize it to start with minimal frills.
130 # Start IPython instance. We customize it to start with minimal frills.
131 user_ns,global_ns = IPython.ipapi.make_user_namespaces(ipnsdict(),dict())
131 user_ns,global_ns = IPython.ipapi.make_user_namespaces(ipnsdict(),dict())
132
132
133 IPython.Shell.IPShell(['--classic','--noterm_title'],
133 IPython.Shell.IPShell(['--classic','--noterm_title'],
134 user_ns,global_ns)
134 user_ns,global_ns)
135
135
136 # Deactivate the various python system hooks added by ipython for
136 # Deactivate the various python system hooks added by ipython for
137 # interactive convenience so we don't confuse the doctest system
137 # interactive convenience so we don't confuse the doctest system
138 sys.modules['__main__'] = _main
138 sys.modules['__main__'] = _main
139 sys.displayhook = _displayhook
139 sys.displayhook = _displayhook
140 sys.excepthook = _excepthook
140 sys.excepthook = _excepthook
141
141
142 # So that ipython magics and aliases can be doctested (they work by making
142 # So that ipython magics and aliases can be doctested (they work by making
143 # a call into a global _ip object)
143 # a call into a global _ip object)
144 _ip = IPython.ipapi.get()
144 _ip = IPython.ipapi.get()
145 __builtin__._ip = _ip
145 __builtin__._ip = _ip
146
146
147 # Modify the IPython system call with one that uses getoutput, so that we
147 # Modify the IPython system call with one that uses getoutput, so that we
148 # can capture subcommands and print them to Python's stdout, otherwise the
148 # can capture subcommands and print them to Python's stdout, otherwise the
149 # doctest machinery would miss them.
149 # doctest machinery would miss them.
150 _ip.system = xsys
150 _ip.system = xsys
151
151
152 # Also patch our %run function in.
152 # Also patch our %run function in.
153 im = new.instancemethod(_run_ns_sync,_ip.IP, _ip.IP.__class__)
153 im = new.instancemethod(_run_ns_sync,_ip.IP, _ip.IP.__class__)
154 _ip.IP.magic_run_ori = _ip.IP.magic_run
154 _ip.IP.magic_run_ori = _ip.IP.magic_run
155 _ip.IP.magic_run = im
155 _ip.IP.magic_run = im
156
156
157 # The start call MUST be made here. I'm not sure yet why it doesn't work if
157 # The start call MUST be made here. I'm not sure yet why it doesn't work if
158 # it is made later, at plugin initialization time, but in all my tests, that's
158 # it is made later, at plugin initialization time, but in all my tests, that's
159 # the case.
159 # the case.
160 start_ipython()
160 start_ipython()
161
161
162 # *** END HACK ***
162 # *** END HACK ***
163 ###########################################################################
163 ###########################################################################
164
164
165 # Classes and functions
165 # Classes and functions
166
166
167 def is_extension_module(filename):
167 def is_extension_module(filename):
168 """Return whether the given filename is an extension module.
168 """Return whether the given filename is an extension module.
169
169
170 This simply checks that the extension is either .so or .pyd.
170 This simply checks that the extension is either .so or .pyd.
171 """
171 """
172 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
172 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
173
173
174
174
175 class nodoc(object):
175 class nodoc(object):
176 def __init__(self,obj):
176 def __init__(self,obj):
177 self.obj = obj
177 self.obj = obj
178
178
179 def __getattribute__(self,key):
179 def __getattribute__(self,key):
180 if key == '__doc__':
180 if key == '__doc__':
181 return None
181 return None
182 else:
182 else:
183 return getattr(object.__getattribute__(self,'obj'),key)
183 return getattr(object.__getattribute__(self,'obj'),key)
184
184
185 # Modified version of the one in the stdlib, that fixes a python bug (doctests
185 # Modified version of the one in the stdlib, that fixes a python bug (doctests
186 # not found in extension modules, http://bugs.python.org/issue3158)
186 # not found in extension modules, http://bugs.python.org/issue3158)
187 class DocTestFinder(doctest.DocTestFinder):
187 class DocTestFinder(doctest.DocTestFinder):
188
188
189 def _from_module(self, module, object):
189 def _from_module(self, module, object):
190 """
190 """
191 Return true if the given object is defined in the given
191 Return true if the given object is defined in the given
192 module.
192 module.
193 """
193 """
194 if module is None:
194 if module is None:
195 return True
195 return True
196 elif inspect.isfunction(object):
196 elif inspect.isfunction(object):
197 return module.__dict__ is object.func_globals
197 return module.__dict__ is object.func_globals
198 elif inspect.isbuiltin(object):
198 elif inspect.isbuiltin(object):
199 return module.__name__ == object.__module__
199 return module.__name__ == object.__module__
200 elif inspect.isclass(object):
200 elif inspect.isclass(object):
201 return module.__name__ == object.__module__
201 return module.__name__ == object.__module__
202 elif inspect.ismethod(object):
202 elif inspect.ismethod(object):
203 # This one may be a bug in cython that fails to correctly set the
203 # This one may be a bug in cython that fails to correctly set the
204 # __module__ attribute of methods, but since the same error is easy
204 # __module__ attribute of methods, but since the same error is easy
205 # to make by extension code writers, having this safety in place
205 # to make by extension code writers, having this safety in place
206 # isn't such a bad idea
206 # isn't such a bad idea
207 return module.__name__ == object.im_class.__module__
207 return module.__name__ == object.im_class.__module__
208 elif inspect.getmodule(object) is not None:
208 elif inspect.getmodule(object) is not None:
209 return module is inspect.getmodule(object)
209 return module is inspect.getmodule(object)
210 elif hasattr(object, '__module__'):
210 elif hasattr(object, '__module__'):
211 return module.__name__ == object.__module__
211 return module.__name__ == object.__module__
212 elif isinstance(object, property):
212 elif isinstance(object, property):
213 return True # [XX] no way not be sure.
213 return True # [XX] no way not be sure.
214 else:
214 else:
215 raise ValueError("object must be a class or function")
215 raise ValueError("object must be a class or function")
216
216
217 def _find(self, tests, obj, name, module, source_lines, globs, seen):
217 def _find(self, tests, obj, name, module, source_lines, globs, seen):
218 """
218 """
219 Find tests for the given object and any contained objects, and
219 Find tests for the given object and any contained objects, and
220 add them to `tests`.
220 add them to `tests`.
221 """
221 """
222
222
223 if hasattr(obj,"skip_doctest"):
223 if hasattr(obj,"skip_doctest"):
224 #print 'SKIPPING DOCTEST FOR:',obj # dbg
224 #print 'SKIPPING DOCTEST FOR:',obj # dbg
225 obj = nodoc(obj)
225 obj = nodoc(obj)
226
226
227 doctest.DocTestFinder._find(self,tests, obj, name, module,
227 doctest.DocTestFinder._find(self,tests, obj, name, module,
228 source_lines, globs, seen)
228 source_lines, globs, seen)
229
229
230 # Below we re-run pieces of the above method with manual modifications,
230 # Below we re-run pieces of the above method with manual modifications,
231 # because the original code is buggy and fails to correctly identify
231 # because the original code is buggy and fails to correctly identify
232 # doctests in extension modules.
232 # doctests in extension modules.
233
233
234 # Local shorthands
234 # Local shorthands
235 from inspect import isroutine, isclass, ismodule
235 from inspect import isroutine, isclass, ismodule
236
236
237 # Look for tests in a module's contained objects.
237 # Look for tests in a module's contained objects.
238 if inspect.ismodule(obj) and self._recurse:
238 if inspect.ismodule(obj) and self._recurse:
239 for valname, val in obj.__dict__.items():
239 for valname, val in obj.__dict__.items():
240 valname1 = '%s.%s' % (name, valname)
240 valname1 = '%s.%s' % (name, valname)
241 if ( (isroutine(val) or isclass(val))
241 if ( (isroutine(val) or isclass(val))
242 and self._from_module(module, val) ):
242 and self._from_module(module, val) ):
243
243
244 self._find(tests, val, valname1, module, source_lines,
244 self._find(tests, val, valname1, module, source_lines,
245 globs, seen)
245 globs, seen)
246
246
247 # Look for tests in a class's contained objects.
247 # Look for tests in a class's contained objects.
248 if inspect.isclass(obj) and self._recurse:
248 if inspect.isclass(obj) and self._recurse:
249 #print 'RECURSE into class:',obj # dbg
249 #print 'RECURSE into class:',obj # dbg
250 for valname, val in obj.__dict__.items():
250 for valname, val in obj.__dict__.items():
251 # Special handling for staticmethod/classmethod.
251 # Special handling for staticmethod/classmethod.
252 if isinstance(val, staticmethod):
252 if isinstance(val, staticmethod):
253 val = getattr(obj, valname)
253 val = getattr(obj, valname)
254 if isinstance(val, classmethod):
254 if isinstance(val, classmethod):
255 val = getattr(obj, valname).im_func
255 val = getattr(obj, valname).im_func
256
256
257 # Recurse to methods, properties, and nested classes.
257 # Recurse to methods, properties, and nested classes.
258 if ((inspect.isfunction(val) or inspect.isclass(val) or
258 if ((inspect.isfunction(val) or inspect.isclass(val) or
259 inspect.ismethod(val) or
259 inspect.ismethod(val) or
260 isinstance(val, property)) and
260 isinstance(val, property)) and
261 self._from_module(module, val)):
261 self._from_module(module, val)):
262 valname = '%s.%s' % (name, valname)
262 valname = '%s.%s' % (name, valname)
263 self._find(tests, val, valname, module, source_lines,
263 self._find(tests, val, valname, module, source_lines,
264 globs, seen)
264 globs, seen)
265
265
266
266
267 class IPDoctestOutputChecker(doctest.OutputChecker):
267 class IPDoctestOutputChecker(doctest.OutputChecker):
268 """Second-chance checker with support for random tests.
268 """Second-chance checker with support for random tests.
269
269
270 If the default comparison doesn't pass, this checker looks in the expected
270 If the default comparison doesn't pass, this checker looks in the expected
271 output string for flags that tell us to ignore the output.
271 output string for flags that tell us to ignore the output.
272 """
272 """
273
273
274 random_re = re.compile(r'#\s*random\s+')
274 random_re = re.compile(r'#\s*random\s+')
275
275
276 def check_output(self, want, got, optionflags):
276 def check_output(self, want, got, optionflags):
277 """Check output, accepting special markers embedded in the output.
277 """Check output, accepting special markers embedded in the output.
278
278
279 If the output didn't pass the default validation but the special string
279 If the output didn't pass the default validation but the special string
280 '#random' is included, we accept it."""
280 '#random' is included, we accept it."""
281
281
282 # Let the original tester verify first, in case people have valid tests
282 # Let the original tester verify first, in case people have valid tests
283 # that happen to have a comment saying '#random' embedded in.
283 # that happen to have a comment saying '#random' embedded in.
284 ret = doctest.OutputChecker.check_output(self, want, got,
284 ret = doctest.OutputChecker.check_output(self, want, got,
285 optionflags)
285 optionflags)
286 if not ret and self.random_re.search(want):
286 if not ret and self.random_re.search(want):
287 #print >> sys.stderr, 'RANDOM OK:',want # dbg
287 #print >> sys.stderr, 'RANDOM OK:',want # dbg
288 return True
288 return True
289
289
290 return ret
290 return ret
291
291
292
292
293 class DocTestCase(doctests.DocTestCase):
293 class DocTestCase(doctests.DocTestCase):
294 """Proxy for DocTestCase: provides an address() method that
294 """Proxy for DocTestCase: provides an address() method that
295 returns the correct address for the doctest case. Otherwise
295 returns the correct address for the doctest case. Otherwise
296 acts as a proxy to the test case. To provide hints for address(),
296 acts as a proxy to the test case. To provide hints for address(),
297 an obj may also be passed -- this will be used as the test object
297 an obj may also be passed -- this will be used as the test object
298 for purposes of determining the test address, if it is provided.
298 for purposes of determining the test address, if it is provided.
299 """
299 """
300
300
301 # Note: this method was taken from numpy's nosetester module.
301 # Note: this method was taken from numpy's nosetester module.
302
302
303 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
303 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
304 # its constructor that blocks non-default arguments from being passed
304 # its constructor that blocks non-default arguments from being passed
305 # down into doctest.DocTestCase
305 # down into doctest.DocTestCase
306
306
307 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
307 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
308 checker=None, obj=None, result_var='_'):
308 checker=None, obj=None, result_var='_'):
309 self._result_var = result_var
309 self._result_var = result_var
310 doctests.DocTestCase.__init__(self, test,
310 doctests.DocTestCase.__init__(self, test,
311 optionflags=optionflags,
311 optionflags=optionflags,
312 setUp=setUp, tearDown=tearDown,
312 setUp=setUp, tearDown=tearDown,
313 checker=checker)
313 checker=checker)
314 # Now we must actually copy the original constructor from the stdlib
314 # Now we must actually copy the original constructor from the stdlib
315 # doctest class, because we can't call it directly and a bug in nose
315 # doctest class, because we can't call it directly and a bug in nose
316 # means it never gets passed the right arguments.
316 # means it never gets passed the right arguments.
317
317
318 self._dt_optionflags = optionflags
318 self._dt_optionflags = optionflags
319 self._dt_checker = checker
319 self._dt_checker = checker
320 self._dt_test = test
320 self._dt_test = test
321 self._dt_setUp = setUp
321 self._dt_setUp = setUp
322 self._dt_tearDown = tearDown
322 self._dt_tearDown = tearDown
323
323
324 # XXX - store this runner once in the object!
324 # XXX - store this runner once in the object!
325 runner = IPDocTestRunner(optionflags=optionflags,
325 runner = IPDocTestRunner(optionflags=optionflags,
326 checker=checker, verbose=False)
326 checker=checker, verbose=False)
327 self._dt_runner = runner
327 self._dt_runner = runner
328
328
329
329
330 # Each doctest should remember what directory it was loaded from...
330 # Each doctest should remember what directory it was loaded from...
331 self._ori_dir = os.getcwd()
331 self._ori_dir = os.getcwd()
332
332
333 # Modified runTest from the default stdlib
333 # Modified runTest from the default stdlib
334 def runTest(self):
334 def runTest(self):
335 test = self._dt_test
335 test = self._dt_test
336 runner = self._dt_runner
336 runner = self._dt_runner
337
337
338 old = sys.stdout
338 old = sys.stdout
339 new = StringIO()
339 new = StringIO()
340 optionflags = self._dt_optionflags
340 optionflags = self._dt_optionflags
341
341
342 if not (optionflags & REPORTING_FLAGS):
342 if not (optionflags & REPORTING_FLAGS):
343 # The option flags don't include any reporting flags,
343 # The option flags don't include any reporting flags,
344 # so add the default reporting flags
344 # so add the default reporting flags
345 optionflags |= _unittest_reportflags
345 optionflags |= _unittest_reportflags
346
346
347 try:
347 try:
348 # Save our current directory and switch out to the one where the
348 # Save our current directory and switch out to the one where the
349 # test was originally created, in case another doctest did a
349 # test was originally created, in case another doctest did a
350 # directory change. We'll restore this in the finally clause.
350 # directory change. We'll restore this in the finally clause.
351 curdir = os.getcwd()
351 curdir = os.getcwd()
352 os.chdir(self._ori_dir)
352 os.chdir(self._ori_dir)
353
353
354 runner.DIVIDER = "-"*70
354 runner.DIVIDER = "-"*70
355 failures, tries = runner.run(test,out=new.write,
355 failures, tries = runner.run(test,out=new.write,
356 clear_globs=False)
356 clear_globs=False)
357 finally:
357 finally:
358 sys.stdout = old
358 sys.stdout = old
359 os.chdir(curdir)
359 os.chdir(curdir)
360
360
361 if failures:
361 if failures:
362 raise self.failureException(self.format_failure(new.getvalue()))
362 raise self.failureException(self.format_failure(new.getvalue()))
363
363
364 def setUp(self):
364 def setUp(self):
365 """Modified test setup that syncs with ipython namespace"""
365 """Modified test setup that syncs with ipython namespace"""
366
366
367 if isinstance(self._dt_test.examples[0],IPExample):
367 if isinstance(self._dt_test.examples[0],IPExample):
368 # for IPython examples *only*, we swap the globals with the ipython
368 # for IPython examples *only*, we swap the globals with the ipython
369 # namespace, after updating it with the globals (which doctest
369 # namespace, after updating it with the globals (which doctest
370 # fills with the necessary info from the module being tested).
370 # fills with the necessary info from the module being tested).
371 _ip.IP.user_ns.update(self._dt_test.globs)
371 _ip.IP.user_ns.update(self._dt_test.globs)
372 self._dt_test.globs = _ip.IP.user_ns
372 self._dt_test.globs = _ip.IP.user_ns
373
373
374 doctests.DocTestCase.setUp(self)
374 doctests.DocTestCase.setUp(self)
375
375
376
376
377
377
378 # A simple subclassing of the original with a different class name, so we can
378 # A simple subclassing of the original with a different class name, so we can
379 # distinguish and treat differently IPython examples from pure python ones.
379 # distinguish and treat differently IPython examples from pure python ones.
380 class IPExample(doctest.Example): pass
380 class IPExample(doctest.Example): pass
381
381
382
382
383 class IPExternalExample(doctest.Example):
383 class IPExternalExample(doctest.Example):
384 """Doctest examples to be run in an external process."""
384 """Doctest examples to be run in an external process."""
385
385
386 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
386 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
387 options=None):
387 options=None):
388 # Parent constructor
388 # Parent constructor
389 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
389 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
390
390
391 # An EXTRA newline is needed to prevent pexpect hangs
391 # An EXTRA newline is needed to prevent pexpect hangs
392 self.source += '\n'
392 self.source += '\n'
393
393
394
394
395 class IPDocTestParser(doctest.DocTestParser):
395 class IPDocTestParser(doctest.DocTestParser):
396 """
396 """
397 A class used to parse strings containing doctest examples.
397 A class used to parse strings containing doctest examples.
398
398
399 Note: This is a version modified to properly recognize IPython input and
399 Note: This is a version modified to properly recognize IPython input and
400 convert any IPython examples into valid Python ones.
400 convert any IPython examples into valid Python ones.
401 """
401 """
402 # This regular expression is used to find doctest examples in a
402 # This regular expression is used to find doctest examples in a
403 # string. It defines three groups: `source` is the source code
403 # string. It defines three groups: `source` is the source code
404 # (including leading indentation and prompts); `indent` is the
404 # (including leading indentation and prompts); `indent` is the
405 # indentation of the first (PS1) line of the source code; and
405 # indentation of the first (PS1) line of the source code; and
406 # `want` is the expected output (including leading indentation).
406 # `want` is the expected output (including leading indentation).
407
407
408 # Classic Python prompts or default IPython ones
408 # Classic Python prompts or default IPython ones
409 _PS1_PY = r'>>>'
409 _PS1_PY = r'>>>'
410 _PS2_PY = r'\.\.\.'
410 _PS2_PY = r'\.\.\.'
411
411
412 _PS1_IP = r'In\ \[\d+\]:'
412 _PS1_IP = r'In\ \[\d+\]:'
413 _PS2_IP = r'\ \ \ \.\.\.+:'
413 _PS2_IP = r'\ \ \ \.\.\.+:'
414
414
415 _RE_TPL = r'''
415 _RE_TPL = r'''
416 # Source consists of a PS1 line followed by zero or more PS2 lines.
416 # Source consists of a PS1 line followed by zero or more PS2 lines.
417 (?P<source>
417 (?P<source>
418 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
418 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
419 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
419 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
420 \n? # a newline
420 \n? # a newline
421 # Want consists of any non-blank lines that do not start with PS1.
421 # Want consists of any non-blank lines that do not start with PS1.
422 (?P<want> (?:(?![ ]*$) # Not a blank line
422 (?P<want> (?:(?![ ]*$) # Not a blank line
423 (?![ ]*%s) # Not a line starting with PS1
423 (?![ ]*%s) # Not a line starting with PS1
424 (?![ ]*%s) # Not a line starting with PS2
424 (?![ ]*%s) # Not a line starting with PS2
425 .*$\n? # But any other line
425 .*$\n? # But any other line
426 )*)
426 )*)
427 '''
427 '''
428
428
429 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
429 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
430 re.MULTILINE | re.VERBOSE)
430 re.MULTILINE | re.VERBOSE)
431
431
432 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
432 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
433 re.MULTILINE | re.VERBOSE)
433 re.MULTILINE | re.VERBOSE)
434
434
435 # Mark a test as being fully random. In this case, we simply append the
435 # Mark a test as being fully random. In this case, we simply append the
436 # random marker ('#random') to each individual example's output. This way
436 # random marker ('#random') to each individual example's output. This way
437 # we don't need to modify any other code.
437 # we don't need to modify any other code.
438 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
438 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
439
439
440 # Mark tests to be executed in an external process - currently unsupported.
440 # Mark tests to be executed in an external process - currently unsupported.
441 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
441 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
442
442
443 def ip2py(self,source):
443 def ip2py(self,source):
444 """Convert input IPython source into valid Python."""
444 """Convert input IPython source into valid Python."""
445 out = []
445 out = []
446 newline = out.append
446 newline = out.append
447 for lnum,line in enumerate(source.splitlines()):
447 for lnum,line in enumerate(source.splitlines()):
448 newline(_ip.IP.prefilter(line,lnum>0))
448 newline(_ip.IP.prefilter(line,lnum>0))
449 newline('') # ensure a closing newline, needed by doctest
449 newline('') # ensure a closing newline, needed by doctest
450 #print "PYSRC:", '\n'.join(out) # dbg
450 #print "PYSRC:", '\n'.join(out) # dbg
451 return '\n'.join(out)
451 return '\n'.join(out)
452
452
453 def parse(self, string, name='<string>'):
453 def parse(self, string, name='<string>'):
454 """
454 """
455 Divide the given string into examples and intervening text,
455 Divide the given string into examples and intervening text,
456 and return them as a list of alternating Examples and strings.
456 and return them as a list of alternating Examples and strings.
457 Line numbers for the Examples are 0-based. The optional
457 Line numbers for the Examples are 0-based. The optional
458 argument `name` is a name identifying this string, and is only
458 argument `name` is a name identifying this string, and is only
459 used for error messages.
459 used for error messages.
460 """
460 """
461
461
462 #print 'Parse string:\n',string # dbg
462 #print 'Parse string:\n',string # dbg
463
463
464 string = string.expandtabs()
464 string = string.expandtabs()
465 # If all lines begin with the same indentation, then strip it.
465 # If all lines begin with the same indentation, then strip it.
466 min_indent = self._min_indent(string)
466 min_indent = self._min_indent(string)
467 if min_indent > 0:
467 if min_indent > 0:
468 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
468 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
469
469
470 output = []
470 output = []
471 charno, lineno = 0, 0
471 charno, lineno = 0, 0
472
472
473 # We make 'all random' tests by adding the '# random' mark to every
473 # We make 'all random' tests by adding the '# random' mark to every
474 # block of output in the test.
474 # block of output in the test.
475 if self._RANDOM_TEST.search(string):
475 if self._RANDOM_TEST.search(string):
476 random_marker = '\n# random'
476 random_marker = '\n# random'
477 else:
477 else:
478 random_marker = ''
478 random_marker = ''
479
479
480 # Whether to convert the input from ipython to python syntax
480 # Whether to convert the input from ipython to python syntax
481 ip2py = False
481 ip2py = False
482 # Find all doctest examples in the string. First, try them as Python
482 # Find all doctest examples in the string. First, try them as Python
483 # examples, then as IPython ones
483 # examples, then as IPython ones
484 terms = list(self._EXAMPLE_RE_PY.finditer(string))
484 terms = list(self._EXAMPLE_RE_PY.finditer(string))
485 if terms:
485 if terms:
486 # Normal Python example
486 # Normal Python example
487 #print '-'*70 # dbg
487 #print '-'*70 # dbg
488 #print 'PyExample, Source:\n',string # dbg
488 #print 'PyExample, Source:\n',string # dbg
489 #print '-'*70 # dbg
489 #print '-'*70 # dbg
490 Example = doctest.Example
490 Example = doctest.Example
491 else:
491 else:
492 # It's an ipython example. Note that IPExamples are run
492 # It's an ipython example. Note that IPExamples are run
493 # in-process, so their syntax must be turned into valid python.
493 # in-process, so their syntax must be turned into valid python.
494 # IPExternalExamples are run out-of-process (via pexpect) so they
494 # IPExternalExamples are run out-of-process (via pexpect) so they
495 # don't need any filtering (a real ipython will be executing them).
495 # don't need any filtering (a real ipython will be executing them).
496 terms = list(self._EXAMPLE_RE_IP.finditer(string))
496 terms = list(self._EXAMPLE_RE_IP.finditer(string))
497 if self._EXTERNAL_IP.search(string):
497 if self._EXTERNAL_IP.search(string):
498 #print '-'*70 # dbg
498 #print '-'*70 # dbg
499 #print 'IPExternalExample, Source:\n',string # dbg
499 #print 'IPExternalExample, Source:\n',string # dbg
500 #print '-'*70 # dbg
500 #print '-'*70 # dbg
501 Example = IPExternalExample
501 Example = IPExternalExample
502 else:
502 else:
503 #print '-'*70 # dbg
503 #print '-'*70 # dbg
504 #print 'IPExample, Source:\n',string # dbg
504 #print 'IPExample, Source:\n',string # dbg
505 #print '-'*70 # dbg
505 #print '-'*70 # dbg
506 Example = IPExample
506 Example = IPExample
507 ip2py = True
507 ip2py = True
508
508
509 for m in terms:
509 for m in terms:
510 # Add the pre-example text to `output`.
510 # Add the pre-example text to `output`.
511 output.append(string[charno:m.start()])
511 output.append(string[charno:m.start()])
512 # Update lineno (lines before this example)
512 # Update lineno (lines before this example)
513 lineno += string.count('\n', charno, m.start())
513 lineno += string.count('\n', charno, m.start())
514 # Extract info from the regexp match.
514 # Extract info from the regexp match.
515 (source, options, want, exc_msg) = \
515 (source, options, want, exc_msg) = \
516 self._parse_example(m, name, lineno,ip2py)
516 self._parse_example(m, name, lineno,ip2py)
517
517
518 # Append the random-output marker (it defaults to empty in most
518 # Append the random-output marker (it defaults to empty in most
519 # cases, it's only non-empty for 'all-random' tests):
519 # cases, it's only non-empty for 'all-random' tests):
520 want += random_marker
520 want += random_marker
521
521
522 if Example is IPExternalExample:
522 if Example is IPExternalExample:
523 options[doctest.NORMALIZE_WHITESPACE] = True
523 options[doctest.NORMALIZE_WHITESPACE] = True
524 want += '\n'
524 want += '\n'
525
525
526 # Create an Example, and add it to the list.
526 # Create an Example, and add it to the list.
527 if not self._IS_BLANK_OR_COMMENT(source):
527 if not self._IS_BLANK_OR_COMMENT(source):
528 output.append(Example(source, want, exc_msg,
528 output.append(Example(source, want, exc_msg,
529 lineno=lineno,
529 lineno=lineno,
530 indent=min_indent+len(m.group('indent')),
530 indent=min_indent+len(m.group('indent')),
531 options=options))
531 options=options))
532 # Update lineno (lines inside this example)
532 # Update lineno (lines inside this example)
533 lineno += string.count('\n', m.start(), m.end())
533 lineno += string.count('\n', m.start(), m.end())
534 # Update charno.
534 # Update charno.
535 charno = m.end()
535 charno = m.end()
536 # Add any remaining post-example text to `output`.
536 # Add any remaining post-example text to `output`.
537 output.append(string[charno:])
537 output.append(string[charno:])
538 return output
538 return output
539
539
540 def _parse_example(self, m, name, lineno,ip2py=False):
540 def _parse_example(self, m, name, lineno,ip2py=False):
541 """
541 """
542 Given a regular expression match from `_EXAMPLE_RE` (`m`),
542 Given a regular expression match from `_EXAMPLE_RE` (`m`),
543 return a pair `(source, want)`, where `source` is the matched
543 return a pair `(source, want)`, where `source` is the matched
544 example's source code (with prompts and indentation stripped);
544 example's source code (with prompts and indentation stripped);
545 and `want` is the example's expected output (with indentation
545 and `want` is the example's expected output (with indentation
546 stripped).
546 stripped).
547
547
548 `name` is the string's name, and `lineno` is the line number
548 `name` is the string's name, and `lineno` is the line number
549 where the example starts; both are used for error messages.
549 where the example starts; both are used for error messages.
550
550
551 Optional:
551 Optional:
552 `ip2py`: if true, filter the input via IPython to convert the syntax
552 `ip2py`: if true, filter the input via IPython to convert the syntax
553 into valid python.
553 into valid python.
554 """
554 """
555
555
556 # Get the example's indentation level.
556 # Get the example's indentation level.
557 indent = len(m.group('indent'))
557 indent = len(m.group('indent'))
558
558
559 # Divide source into lines; check that they're properly
559 # Divide source into lines; check that they're properly
560 # indented; and then strip their indentation & prompts.
560 # indented; and then strip their indentation & prompts.
561 source_lines = m.group('source').split('\n')
561 source_lines = m.group('source').split('\n')
562
562
563 # We're using variable-length input prompts
563 # We're using variable-length input prompts
564 ps1 = m.group('ps1')
564 ps1 = m.group('ps1')
565 ps2 = m.group('ps2')
565 ps2 = m.group('ps2')
566 ps1_len = len(ps1)
566 ps1_len = len(ps1)
567
567
568 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
568 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
569 if ps2:
569 if ps2:
570 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
570 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
571
571
572 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
572 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
573
573
574 if ip2py:
574 if ip2py:
575 # Convert source input from IPython into valid Python syntax
575 # Convert source input from IPython into valid Python syntax
576 source = self.ip2py(source)
576 source = self.ip2py(source)
577
577
578 # Divide want into lines; check that it's properly indented; and
578 # Divide want into lines; check that it's properly indented; and
579 # then strip the indentation. Spaces before the last newline should
579 # then strip the indentation. Spaces before the last newline should
580 # be preserved, so plain rstrip() isn't good enough.
580 # be preserved, so plain rstrip() isn't good enough.
581 want = m.group('want')
581 want = m.group('want')
582 want_lines = want.split('\n')
582 want_lines = want.split('\n')
583 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
583 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
584 del want_lines[-1] # forget final newline & spaces after it
584 del want_lines[-1] # forget final newline & spaces after it
585 self._check_prefix(want_lines, ' '*indent, name,
585 self._check_prefix(want_lines, ' '*indent, name,
586 lineno + len(source_lines))
586 lineno + len(source_lines))
587
587
588 # Remove ipython output prompt that might be present in the first line
588 # Remove ipython output prompt that might be present in the first line
589 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
589 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
590
590
591 want = '\n'.join([wl[indent:] for wl in want_lines])
591 want = '\n'.join([wl[indent:] for wl in want_lines])
592
592
593 # If `want` contains a traceback message, then extract it.
593 # If `want` contains a traceback message, then extract it.
594 m = self._EXCEPTION_RE.match(want)
594 m = self._EXCEPTION_RE.match(want)
595 if m:
595 if m:
596 exc_msg = m.group('msg')
596 exc_msg = m.group('msg')
597 else:
597 else:
598 exc_msg = None
598 exc_msg = None
599
599
600 # Extract options from the source.
600 # Extract options from the source.
601 options = self._find_options(source, name, lineno)
601 options = self._find_options(source, name, lineno)
602
602
603 return source, options, want, exc_msg
603 return source, options, want, exc_msg
604
604
605 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
605 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
606 """
606 """
607 Given the lines of a source string (including prompts and
607 Given the lines of a source string (including prompts and
608 leading indentation), check to make sure that every prompt is
608 leading indentation), check to make sure that every prompt is
609 followed by a space character. If any line is not followed by
609 followed by a space character. If any line is not followed by
610 a space character, then raise ValueError.
610 a space character, then raise ValueError.
611
611
612 Note: IPython-modified version which takes the input prompt length as a
612 Note: IPython-modified version which takes the input prompt length as a
613 parameter, so that prompts of variable length can be dealt with.
613 parameter, so that prompts of variable length can be dealt with.
614 """
614 """
615 space_idx = indent+ps1_len
615 space_idx = indent+ps1_len
616 min_len = space_idx+1
616 min_len = space_idx+1
617 for i, line in enumerate(lines):
617 for i, line in enumerate(lines):
618 if len(line) >= min_len and line[space_idx] != ' ':
618 if len(line) >= min_len and line[space_idx] != ' ':
619 raise ValueError('line %r of the docstring for %s '
619 raise ValueError('line %r of the docstring for %s '
620 'lacks blank after %s: %r' %
620 'lacks blank after %s: %r' %
621 (lineno+i+1, name,
621 (lineno+i+1, name,
622 line[indent:space_idx], line))
622 line[indent:space_idx], line))
623
623
624
624
625 SKIP = doctest.register_optionflag('SKIP')
625 SKIP = doctest.register_optionflag('SKIP')
626
626
627
627
628 class IPDocTestRunner(doctest.DocTestRunner,object):
628 class IPDocTestRunner(doctest.DocTestRunner,object):
629 """Test runner that synchronizes the IPython namespace with test globals.
629 """Test runner that synchronizes the IPython namespace with test globals.
630 """
630 """
631
631
632 def run(self, test, compileflags=None, out=None, clear_globs=True):
632 def run(self, test, compileflags=None, out=None, clear_globs=True):
633
633
634 # Hack: ipython needs access to the execution context of the example,
634 # Hack: ipython needs access to the execution context of the example,
635 # so that it can propagate user variables loaded by %run into
635 # so that it can propagate user variables loaded by %run into
636 # test.globs. We put them here into our modified %run as a function
636 # test.globs. We put them here into our modified %run as a function
637 # attribute. Our new %run will then only make the namespace update
637 # attribute. Our new %run will then only make the namespace update
638 # when called (rather than unconconditionally updating test.globs here
638 # when called (rather than unconconditionally updating test.globs here
639 # for all examples, most of which won't be calling %run anyway).
639 # for all examples, most of which won't be calling %run anyway).
640 _run_ns_sync.test_globs = test.globs
640 _run_ns_sync.test_globs = test.globs
641
641
642 return super(IPDocTestRunner,self).run(test,
642 return super(IPDocTestRunner,self).run(test,
643 compileflags,out,clear_globs)
643 compileflags,out,clear_globs)
644
644
645
645
646 class DocFileCase(doctest.DocFileCase):
646 class DocFileCase(doctest.DocFileCase):
647 """Overrides to provide filename
647 """Overrides to provide filename
648 """
648 """
649 def address(self):
649 def address(self):
650 return (self._dt_test.filename, None, None)
650 return (self._dt_test.filename, None, None)
651
651
652
652
653 class ExtensionDoctest(doctests.Doctest):
653 class ExtensionDoctest(doctests.Doctest):
654 """Nose Plugin that supports doctests in extension modules.
654 """Nose Plugin that supports doctests in extension modules.
655 """
655 """
656 name = 'extdoctest' # call nosetests with --with-extdoctest
656 name = 'extdoctest' # call nosetests with --with-extdoctest
657 enabled = True
657 enabled = True
658
658
659 def options(self, parser, env=os.environ):
659 def options(self, parser, env=os.environ):
660 Plugin.options(self, parser, env)
660 Plugin.options(self, parser, env)
661 parser.add_option('--doctest-tests', action='store_true',
662 dest='doctest_tests',
663 default=env.get('NOSE_DOCTEST_TESTS',True),
664 help="Also look for doctests in test modules. "
665 "Note that classes, methods and functions should "
666 "have either doctests or non-doctest tests, "
667 "not both. [NOSE_DOCTEST_TESTS]")
668 parser.add_option('--doctest-extension', action="append",
669 dest="doctestExtension",
670 help="Also look for doctests in files with "
671 "this extension [NOSE_DOCTEST_EXTENSION]")
672 # Set the default as a list, if given in env; otherwise
673 # an additional value set on the command line will cause
674 # an error.
675 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
676 if env_setting is not None:
677 parser.set_defaults(doctestExtension=tolist(env_setting))
678
661
679
662 def configure(self, options, config):
680 def configure(self, options, config):
663 Plugin.configure(self, options, config)
681 Plugin.configure(self, options, config)
664 self.doctest_tests = options.doctest_tests
682 self.doctest_tests = options.doctest_tests
665 self.extension = tolist(options.doctestExtension)
683 self.extension = tolist(options.doctestExtension)
666
684
667 self.parser = doctest.DocTestParser()
685 self.parser = doctest.DocTestParser()
668 self.finder = DocTestFinder()
686 self.finder = DocTestFinder()
669 self.checker = IPDoctestOutputChecker()
687 self.checker = IPDoctestOutputChecker()
670 self.globs = None
688 self.globs = None
671 self.extraglobs = None
689 self.extraglobs = None
672
690
673 def loadTestsFromExtensionModule(self,filename):
691 def loadTestsFromExtensionModule(self,filename):
674 bpath,mod = os.path.split(filename)
692 bpath,mod = os.path.split(filename)
675 modname = os.path.splitext(mod)[0]
693 modname = os.path.splitext(mod)[0]
676 try:
694 try:
677 sys.path.append(bpath)
695 sys.path.append(bpath)
678 module = __import__(modname)
696 module = __import__(modname)
679 tests = list(self.loadTestsFromModule(module))
697 tests = list(self.loadTestsFromModule(module))
680 finally:
698 finally:
681 sys.path.pop()
699 sys.path.pop()
682 return tests
700 return tests
683
701
684 # NOTE: the method below is almost a copy of the original one in nose, with
702 # NOTE: the method below is almost a copy of the original one in nose, with
685 # a few modifications to control output checking.
703 # a few modifications to control output checking.
686
704
687 def loadTestsFromModule(self, module):
705 def loadTestsFromModule(self, module):
688 #print 'lTM',module # dbg
706 #print 'lTM',module # dbg
689
707
690 if not self.matches(module.__name__):
708 if not self.matches(module.__name__):
691 log.debug("Doctest doesn't want module %s", module)
709 log.debug("Doctest doesn't want module %s", module)
692 return
710 return
693
711
694 tests = self.finder.find(module,globs=self.globs,
712 tests = self.finder.find(module,globs=self.globs,
695 extraglobs=self.extraglobs)
713 extraglobs=self.extraglobs)
696 if not tests:
714 if not tests:
697 return
715 return
698
716
699 # always use whitespace and ellipsis options
717 # always use whitespace and ellipsis options
700 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
718 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
701
719
702 tests.sort()
720 tests.sort()
703 module_file = module.__file__
721 module_file = module.__file__
704 if module_file[-4:] in ('.pyc', '.pyo'):
722 if module_file[-4:] in ('.pyc', '.pyo'):
705 module_file = module_file[:-1]
723 module_file = module_file[:-1]
706 for test in tests:
724 for test in tests:
707 if not test.examples:
725 if not test.examples:
708 continue
726 continue
709 if not test.filename:
727 if not test.filename:
710 test.filename = module_file
728 test.filename = module_file
711
729
712 yield DocTestCase(test,
730 yield DocTestCase(test,
713 optionflags=optionflags,
731 optionflags=optionflags,
714 checker=self.checker)
732 checker=self.checker)
715
733
716
734
717 def loadTestsFromFile(self, filename):
735 def loadTestsFromFile(self, filename):
718 #print 'lTF',filename # dbg
736 #print 'lTF',filename # dbg
719
737
720 if is_extension_module(filename):
738 if is_extension_module(filename):
721 for t in self.loadTestsFromExtensionModule(filename):
739 for t in self.loadTestsFromExtensionModule(filename):
722 yield t
740 yield t
723 else:
741 else:
724 if self.extension and anyp(filename.endswith, self.extension):
742 if self.extension and anyp(filename.endswith, self.extension):
725 name = os.path.basename(filename)
743 name = os.path.basename(filename)
726 dh = open(filename)
744 dh = open(filename)
727 try:
745 try:
728 doc = dh.read()
746 doc = dh.read()
729 finally:
747 finally:
730 dh.close()
748 dh.close()
731 test = self.parser.get_doctest(
749 test = self.parser.get_doctest(
732 doc, globs={'__file__': filename}, name=name,
750 doc, globs={'__file__': filename}, name=name,
733 filename=filename, lineno=0)
751 filename=filename, lineno=0)
734 if test.examples:
752 if test.examples:
735 #print 'FileCase:',test.examples # dbg
753 #print 'FileCase:',test.examples # dbg
736 yield DocFileCase(test)
754 yield DocFileCase(test)
737 else:
755 else:
738 yield False # no tests to load
756 yield False # no tests to load
739
757
740 def wantFile(self,filename):
758 def wantFile(self,filename):
741 """Return whether the given filename should be scanned for tests.
759 """Return whether the given filename should be scanned for tests.
742
760
743 Modified version that accepts extension modules as valid containers for
761 Modified version that accepts extension modules as valid containers for
744 doctests.
762 doctests.
745 """
763 """
746 #print 'Filename:',filename # dbg
764 print 'Filename:',filename # dbg
747
765
748 # XXX - temporarily hardcoded list, will move to driver later
766 # XXX - temporarily hardcoded list, will move to driver later
749 exclude = ['IPython/external/',
767 exclude = ['IPython/external/',
750 'IPython/Extensions/ipy_',
751 'IPython/platutils_win32',
768 'IPython/platutils_win32',
752 'IPython/frontend/cocoa',
769 'IPython/frontend/cocoa',
753 'IPython_doctest_plugin',
770 'IPython_doctest_plugin',
754 'IPython/Gnuplot',
771 'IPython/Gnuplot',
755 'IPython/Extensions/PhysicalQIn']
772 'IPython/Extensions/ipy_',
773 'IPython/Extensions/PhysicalQIn',
774 'IPython/Extensions/scitedirector',
775 'IPython/testing/plugin',
776 ]
756
777
757 for fex in exclude:
778 for fex in exclude:
758 if fex in filename: # substring
779 if fex in filename: # substring
759 #print '###>>> SKIP:',filename # dbg
780 #print '###>>> SKIP:',filename # dbg
760 return False
781 return False
761
782
762 if is_extension_module(filename):
783 if is_extension_module(filename):
763 return True
784 return True
764 else:
785 else:
765 return doctests.Doctest.wantFile(self,filename)
786 return doctests.Doctest.wantFile(self,filename)
766
787
767
788
768 class IPythonDoctest(ExtensionDoctest):
789 class IPythonDoctest(ExtensionDoctest):
769 """Nose Plugin that supports doctests in extension modules.
790 """Nose Plugin that supports doctests in extension modules.
770 """
791 """
771 name = 'ipdoctest' # call nosetests with --with-ipdoctest
792 name = 'ipdoctest' # call nosetests with --with-ipdoctest
772 enabled = True
793 enabled = True
773
794
774 def configure(self, options, config):
795 def configure(self, options, config):
775
796
776 Plugin.configure(self, options, config)
797 Plugin.configure(self, options, config)
777 self.doctest_tests = options.doctest_tests
798 self.doctest_tests = options.doctest_tests
778 self.extension = tolist(options.doctestExtension)
799 self.extension = tolist(options.doctestExtension)
779
800
780 self.parser = IPDocTestParser()
801 self.parser = IPDocTestParser()
781 self.finder = DocTestFinder(parser=self.parser)
802 self.finder = DocTestFinder(parser=self.parser)
782 self.checker = IPDoctestOutputChecker()
803 self.checker = IPDoctestOutputChecker()
783 self.globs = None
804 self.globs = None
784 self.extraglobs = None
805 self.extraglobs = None
806
@@ -1,86 +1,87 b''
1 """DEPRECATED - use IPython.testing.util instead.
1 """DEPRECATED - use IPython.testing.util instead.
2
2
3 Utilities for testing code.
3 Utilities for testing code.
4 """
4 """
5
5
6 #############################################################################
6 #############################################################################
7
7
8 # This was old testing code we never really used in IPython. The pieces of
8 # This was old testing code we never really used in IPython. The pieces of
9 # testing machinery from snakeoil that were good have already been merged into
9 # testing machinery from snakeoil that were good have already been merged into
10 # the nose plugin, so this can be taken away soon. Leave a warning for now,
10 # the nose plugin, so this can be taken away soon. Leave a warning for now,
11 # we'll remove it in a later release (around 0.10 or so).
11 # we'll remove it in a later release (around 0.10 or so).
12
12 from warnings import warn
13 from warnings import warn
13 warn('This will be removed soon. Use IPython.testing.util instead',
14 warn('This will be removed soon. Use IPython.testing.util instead',
14 DeprecationWarning)
15 DeprecationWarning)
15
16
16 #############################################################################
17 #############################################################################
17
18
18 # Required modules and packages
19 # Required modules and packages
19
20
20 # Standard Python lib
21 # Standard Python lib
21 import os
22 import os
22 import sys
23 import sys
23
24
24 # From this project
25 # From this project
25 from IPython.tools import utils
26 from IPython.tools import utils
26
27
27 # path to our own installation, so we can find source files under this.
28 # path to our own installation, so we can find source files under this.
28 TEST_PATH = os.path.dirname(os.path.abspath(__file__))
29 TEST_PATH = os.path.dirname(os.path.abspath(__file__))
29
30
30 # Global flag, used by vprint
31 # Global flag, used by vprint
31 VERBOSE = '-v' in sys.argv or '--verbose' in sys.argv
32 VERBOSE = '-v' in sys.argv or '--verbose' in sys.argv
32
33
33 ##########################################################################
34 ##########################################################################
34 # Code begins
35 # Code begins
35
36
36 # Some utility functions
37 # Some utility functions
37 def vprint(*args):
38 def vprint(*args):
38 """Print-like function which relies on a global VERBOSE flag."""
39 """Print-like function which relies on a global VERBOSE flag."""
39 if not VERBOSE:
40 if not VERBOSE:
40 return
41 return
41
42
42 write = sys.stdout.write
43 write = sys.stdout.write
43 for item in args:
44 for item in args:
44 write(str(item))
45 write(str(item))
45 write('\n')
46 write('\n')
46 sys.stdout.flush()
47 sys.stdout.flush()
47
48
48 def test_path(path):
49 def test_path(path):
49 """Return a path as a subdir of the test package.
50 """Return a path as a subdir of the test package.
50
51
51 This finds the correct path of the test package on disk, and prepends it
52 This finds the correct path of the test package on disk, and prepends it
52 to the input path."""
53 to the input path."""
53
54
54 return os.path.join(TEST_PATH,path)
55 return os.path.join(TEST_PATH,path)
55
56
56 def fullPath(startPath,files):
57 def fullPath(startPath,files):
57 """Make full paths for all the listed files, based on startPath.
58 """Make full paths for all the listed files, based on startPath.
58
59
59 Only the base part of startPath is kept, since this routine is typically
60 Only the base part of startPath is kept, since this routine is typically
60 used with a script's __file__ variable as startPath. The base of startPath
61 used with a script's __file__ variable as startPath. The base of startPath
61 is then prepended to all the listed files, forming the output list.
62 is then prepended to all the listed files, forming the output list.
62
63
63 :Parameters:
64 :Parameters:
64 startPath : string
65 startPath : string
65 Initial path to use as the base for the results. This path is split
66 Initial path to use as the base for the results. This path is split
66 using os.path.split() and only its first component is kept.
67 using os.path.split() and only its first component is kept.
67
68
68 files : string or list
69 files : string or list
69 One or more files.
70 One or more files.
70
71
71 :Examples:
72 :Examples:
72
73
73 >>> fullPath('/foo/bar.py',['a.txt','b.txt'])
74 >>> fullPath('/foo/bar.py',['a.txt','b.txt'])
74 ['/foo/a.txt', '/foo/b.txt']
75 ['/foo/a.txt', '/foo/b.txt']
75
76
76 >>> fullPath('/foo',['a.txt','b.txt'])
77 >>> fullPath('/foo',['a.txt','b.txt'])
77 ['/a.txt', '/b.txt']
78 ['/a.txt', '/b.txt']
78
79
79 If a single file is given, the output is still a list:
80 If a single file is given, the output is still a list:
80 >>> fullPath('/foo','a.txt')
81 >>> fullPath('/foo','a.txt')
81 ['/a.txt']
82 ['/a.txt']
82 """
83 """
83
84
84 files = utils.list_strings(files)
85 files = utils.list_strings(files)
85 base = os.path.split(startPath)[0]
86 base = os.path.split(startPath)[0]
86 return [ os.path.join(base,f) for f in files ]
87 return [ os.path.join(base,f) for f in files ]
@@ -1,1061 +1,1062 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ultraTB.py -- Spice up your tracebacks!
3 ultraTB.py -- Spice up your tracebacks!
4
4
5 * ColorTB
5 * ColorTB
6 I've always found it a bit hard to visually parse tracebacks in Python. The
6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 ColorTB class is a solution to that problem. It colors the different parts of a
7 ColorTB class is a solution to that problem. It colors the different parts of a
8 traceback in a manner similar to what you would expect from a syntax-highlighting
8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 text editor.
9 text editor.
10
10
11 Installation instructions for ColorTB:
11 Installation instructions for ColorTB:
12 import sys,ultraTB
12 import sys,ultraTB
13 sys.excepthook = ultraTB.ColorTB()
13 sys.excepthook = ultraTB.ColorTB()
14
14
15 * VerboseTB
15 * VerboseTB
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 and intended it for CGI programmers, but why should they have all the fun? I
18 and intended it for CGI programmers, but why should they have all the fun? I
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 but kind of neat, and maybe useful for long-running programs that you believe
20 but kind of neat, and maybe useful for long-running programs that you believe
21 are bug-free. If a crash *does* occur in that type of program you want details.
21 are bug-free. If a crash *does* occur in that type of program you want details.
22 Give it a shot--you'll love it or you'll hate it.
22 Give it a shot--you'll love it or you'll hate it.
23
23
24 Note:
24 Note:
25
25
26 The Verbose mode prints the variables currently visible where the exception
26 The Verbose mode prints the variables currently visible where the exception
27 happened (shortening their strings if too long). This can potentially be
27 happened (shortening their strings if too long). This can potentially be
28 very slow, if you happen to have a huge data structure whose string
28 very slow, if you happen to have a huge data structure whose string
29 representation is complex to compute. Your computer may appear to freeze for
29 representation is complex to compute. Your computer may appear to freeze for
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 with Ctrl-C (maybe hitting it more than once).
31 with Ctrl-C (maybe hitting it more than once).
32
32
33 If you encounter this kind of situation often, you may want to use the
33 If you encounter this kind of situation often, you may want to use the
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 variables (but otherwise includes the information and context given by
35 variables (but otherwise includes the information and context given by
36 Verbose).
36 Verbose).
37
37
38
38
39 Installation instructions for ColorTB:
39 Installation instructions for ColorTB:
40 import sys,ultraTB
40 import sys,ultraTB
41 sys.excepthook = ultraTB.VerboseTB()
41 sys.excepthook = ultraTB.VerboseTB()
42
42
43 Note: Much of the code in this module was lifted verbatim from the standard
43 Note: Much of the code in this module was lifted verbatim from the standard
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45
45
46 * Color schemes
46 * Color schemes
47 The colors are defined in the class TBTools through the use of the
47 The colors are defined in the class TBTools through the use of the
48 ColorSchemeTable class. Currently the following exist:
48 ColorSchemeTable class. Currently the following exist:
49
49
50 - NoColor: allows all of this module to be used in any terminal (the color
50 - NoColor: allows all of this module to be used in any terminal (the color
51 escapes are just dummy blank strings).
51 escapes are just dummy blank strings).
52
52
53 - Linux: is meant to look good in a terminal like the Linux console (black
53 - Linux: is meant to look good in a terminal like the Linux console (black
54 or very dark background).
54 or very dark background).
55
55
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 in light background terminals.
57 in light background terminals.
58
58
59 You can implement other color schemes easily, the syntax is fairly
59 You can implement other color schemes easily, the syntax is fairly
60 self-explanatory. Please send back new schemes you develop to the author for
60 self-explanatory. Please send back new schemes you develop to the author for
61 possible inclusion in future releases.
61 possible inclusion in future releases.
62
62
63 $Id: ultraTB.py 2908 2007-12-30 21:07:46Z vivainio $"""
63 $Id: ultraTB.py 2908 2007-12-30 21:07:46Z vivainio $"""
64
64
65 #*****************************************************************************
65 #*****************************************************************************
66 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
66 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
67 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
67 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
68 #
68 #
69 # Distributed under the terms of the BSD License. The full license is in
69 # Distributed under the terms of the BSD License. The full license is in
70 # the file COPYING, distributed as part of this software.
70 # the file COPYING, distributed as part of this software.
71 #*****************************************************************************
71 #*****************************************************************************
72
72
73 from IPython import Release
73 from IPython import Release
74 __author__ = '%s <%s>\n%s <%s>' % (Release.authors['Nathan']+
74 __author__ = '%s <%s>\n%s <%s>' % (Release.authors['Nathan']+
75 Release.authors['Fernando'])
75 Release.authors['Fernando'])
76 __license__ = Release.license
76 __license__ = Release.license
77
77
78 # Required modules
78 # Required modules
79 import inspect
79 import inspect
80 import keyword
80 import keyword
81 import linecache
81 import linecache
82 import os
82 import os
83 import pydoc
83 import pydoc
84 import re
84 import re
85 import string
85 import string
86 import sys
86 import sys
87 import time
87 import time
88 import tokenize
88 import tokenize
89 import traceback
89 import traceback
90 import types
90 import types
91
91
92 # For purposes of monkeypatching inspect to fix a bug in it.
92 # For purposes of monkeypatching inspect to fix a bug in it.
93 from inspect import getsourcefile, getfile, getmodule,\
93 from inspect import getsourcefile, getfile, getmodule,\
94 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
94 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
95
95
96
96
97 # IPython's own modules
97 # IPython's own modules
98 # Modified pdb which doesn't damage IPython's readline handling
98 # Modified pdb which doesn't damage IPython's readline handling
99 from IPython import Debugger, PyColorize
99 from IPython import Debugger, PyColorize
100 from IPython.ipstruct import Struct
100 from IPython.ipstruct import Struct
101 from IPython.excolors import ExceptionColors
101 from IPython.excolors import ExceptionColors
102 from IPython.genutils import Term,uniq_stable,error,info
102 from IPython.genutils import Term,uniq_stable,error,info
103
103
104 # Globals
104 # Globals
105 # amount of space to put line numbers before verbose tracebacks
105 # amount of space to put line numbers before verbose tracebacks
106 INDENT_SIZE = 8
106 INDENT_SIZE = 8
107
107
108 # Default color scheme. This is used, for example, by the traceback
108 # Default color scheme. This is used, for example, by the traceback
109 # formatter. When running in an actual IPython instance, the user's rc.colors
109 # formatter. When running in an actual IPython instance, the user's rc.colors
110 # value is used, but havinga module global makes this functionality available
110 # value is used, but havinga module global makes this functionality available
111 # to users of ultraTB who are NOT running inside ipython.
111 # to users of ultraTB who are NOT running inside ipython.
112 DEFAULT_SCHEME = 'NoColor'
112 DEFAULT_SCHEME = 'NoColor'
113
113
114 #---------------------------------------------------------------------------
114 #---------------------------------------------------------------------------
115 # Code begins
115 # Code begins
116
116
117 # Utility functions
117 # Utility functions
118 def inspect_error():
118 def inspect_error():
119 """Print a message about internal inspect errors.
119 """Print a message about internal inspect errors.
120
120
121 These are unfortunately quite common."""
121 These are unfortunately quite common."""
122
122
123 error('Internal Python error in the inspect module.\n'
123 error('Internal Python error in the inspect module.\n'
124 'Below is the traceback from this internal error.\n')
124 'Below is the traceback from this internal error.\n')
125
125
126
126
127 def findsource(object):
127 def findsource(object):
128 """Return the entire source file and starting line number for an object.
128 """Return the entire source file and starting line number for an object.
129
129
130 The argument may be a module, class, method, function, traceback, frame,
130 The argument may be a module, class, method, function, traceback, frame,
131 or code object. The source code is returned as a list of all the lines
131 or code object. The source code is returned as a list of all the lines
132 in the file and the line number indexes a line in that list. An IOError
132 in the file and the line number indexes a line in that list. An IOError
133 is raised if the source code cannot be retrieved.
133 is raised if the source code cannot be retrieved.
134
134
135 FIXED version with which we monkeypatch the stdlib to work around a bug."""
135 FIXED version with which we monkeypatch the stdlib to work around a bug."""
136
136
137 file = getsourcefile(object) or getfile(object)
137 file = getsourcefile(object) or getfile(object)
138 # If the object is a frame, then trying to get the globals dict from its
138 # If the object is a frame, then trying to get the globals dict from its
139 # module won't work. Instead, the frame object itself has the globals
139 # module won't work. Instead, the frame object itself has the globals
140 # dictionary.
140 # dictionary.
141 globals_dict = None
141 globals_dict = None
142 if inspect.isframe(object):
142 if inspect.isframe(object):
143 # XXX: can this ever be false?
143 # XXX: can this ever be false?
144 globals_dict = object.f_globals
144 globals_dict = object.f_globals
145 else:
145 else:
146 module = getmodule(object, file)
146 module = getmodule(object, file)
147 if module:
147 if module:
148 globals_dict = module.__dict__
148 globals_dict = module.__dict__
149 lines = linecache.getlines(file, globals_dict)
149 lines = linecache.getlines(file, globals_dict)
150 if not lines:
150 if not lines:
151 raise IOError('could not get source code')
151 raise IOError('could not get source code')
152
152
153 if ismodule(object):
153 if ismodule(object):
154 return lines, 0
154 return lines, 0
155
155
156 if isclass(object):
156 if isclass(object):
157 name = object.__name__
157 name = object.__name__
158 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
158 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
159 # make some effort to find the best matching class definition:
159 # make some effort to find the best matching class definition:
160 # use the one with the least indentation, which is the one
160 # use the one with the least indentation, which is the one
161 # that's most probably not inside a function definition.
161 # that's most probably not inside a function definition.
162 candidates = []
162 candidates = []
163 for i in range(len(lines)):
163 for i in range(len(lines)):
164 match = pat.match(lines[i])
164 match = pat.match(lines[i])
165 if match:
165 if match:
166 # if it's at toplevel, it's already the best one
166 # if it's at toplevel, it's already the best one
167 if lines[i][0] == 'c':
167 if lines[i][0] == 'c':
168 return lines, i
168 return lines, i
169 # else add whitespace to candidate list
169 # else add whitespace to candidate list
170 candidates.append((match.group(1), i))
170 candidates.append((match.group(1), i))
171 if candidates:
171 if candidates:
172 # this will sort by whitespace, and by line number,
172 # this will sort by whitespace, and by line number,
173 # less whitespace first
173 # less whitespace first
174 candidates.sort()
174 candidates.sort()
175 return lines, candidates[0][1]
175 return lines, candidates[0][1]
176 else:
176 else:
177 raise IOError('could not find class definition')
177 raise IOError('could not find class definition')
178
178
179 if ismethod(object):
179 if ismethod(object):
180 object = object.im_func
180 object = object.im_func
181 if isfunction(object):
181 if isfunction(object):
182 object = object.func_code
182 object = object.func_code
183 if istraceback(object):
183 if istraceback(object):
184 object = object.tb_frame
184 object = object.tb_frame
185 if isframe(object):
185 if isframe(object):
186 object = object.f_code
186 object = object.f_code
187 if iscode(object):
187 if iscode(object):
188 if not hasattr(object, 'co_firstlineno'):
188 if not hasattr(object, 'co_firstlineno'):
189 raise IOError('could not find function definition')
189 raise IOError('could not find function definition')
190 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
190 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
191 pmatch = pat.match
191 pmatch = pat.match
192 # fperez - fix: sometimes, co_firstlineno can give a number larger than
192 # fperez - fix: sometimes, co_firstlineno can give a number larger than
193 # the length of lines, which causes an error. Safeguard against that.
193 # the length of lines, which causes an error. Safeguard against that.
194 lnum = min(object.co_firstlineno,len(lines))-1
194 lnum = min(object.co_firstlineno,len(lines))-1
195 while lnum > 0:
195 while lnum > 0:
196 if pmatch(lines[lnum]): break
196 if pmatch(lines[lnum]): break
197 lnum -= 1
197 lnum -= 1
198
198
199 return lines, lnum
199 return lines, lnum
200 raise IOError('could not find code object')
200 raise IOError('could not find code object')
201
201
202 # Monkeypatch inspect to apply our bugfix. This code only works with py25
202 # Monkeypatch inspect to apply our bugfix. This code only works with py25
203 if sys.version_info[:2] >= (2,5):
203 if sys.version_info[:2] >= (2,5):
204 inspect.findsource = findsource
204 inspect.findsource = findsource
205
205
206 def fix_frame_records_filenames(records):
206 def fix_frame_records_filenames(records):
207 """Try to fix the filenames in each record from inspect.getinnerframes().
207 """Try to fix the filenames in each record from inspect.getinnerframes().
208
208
209 Particularly, modules loaded from within zip files have useless filenames
209 Particularly, modules loaded from within zip files have useless filenames
210 attached to their code object, and inspect.getinnerframes() just uses it.
210 attached to their code object, and inspect.getinnerframes() just uses it.
211 """
211 """
212 fixed_records = []
212 fixed_records = []
213 for frame, filename, line_no, func_name, lines, index in records:
213 for frame, filename, line_no, func_name, lines, index in records:
214 # Look inside the frame's globals dictionary for __file__, which should
214 # Look inside the frame's globals dictionary for __file__, which should
215 # be better.
215 # be better.
216 better_fn = frame.f_globals.get('__file__', None)
216 better_fn = frame.f_globals.get('__file__', None)
217 if isinstance(better_fn, str):
217 if isinstance(better_fn, str):
218 # Check the type just in case someone did something weird with
218 # Check the type just in case someone did something weird with
219 # __file__. It might also be None if the error occurred during
219 # __file__. It might also be None if the error occurred during
220 # import.
220 # import.
221 filename = better_fn
221 filename = better_fn
222 fixed_records.append((frame, filename, line_no, func_name, lines, index))
222 fixed_records.append((frame, filename, line_no, func_name, lines, index))
223 return fixed_records
223 return fixed_records
224
224
225
225
226 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
226 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
227 import linecache
227 import linecache
228 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
228 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
229
229
230 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
230 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
231
231
232 # If the error is at the console, don't build any context, since it would
232 # If the error is at the console, don't build any context, since it would
233 # otherwise produce 5 blank lines printed out (there is no file at the
233 # otherwise produce 5 blank lines printed out (there is no file at the
234 # console)
234 # console)
235 rec_check = records[tb_offset:]
235 rec_check = records[tb_offset:]
236 try:
236 try:
237 rname = rec_check[0][1]
237 rname = rec_check[0][1]
238 if rname == '<ipython console>' or rname.endswith('<string>'):
238 if rname == '<ipython console>' or rname.endswith('<string>'):
239 return rec_check
239 return rec_check
240 except IndexError:
240 except IndexError:
241 pass
241 pass
242
242
243 aux = traceback.extract_tb(etb)
243 aux = traceback.extract_tb(etb)
244 assert len(records) == len(aux)
244 assert len(records) == len(aux)
245 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
245 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
246 maybeStart = lnum-1 - context//2
246 maybeStart = lnum-1 - context//2
247 start = max(maybeStart, 0)
247 start = max(maybeStart, 0)
248 end = start + context
248 end = start + context
249 lines = linecache.getlines(file)[start:end]
249 lines = linecache.getlines(file)[start:end]
250 # pad with empty lines if necessary
250 # pad with empty lines if necessary
251 if maybeStart < 0:
251 if maybeStart < 0:
252 lines = (['\n'] * -maybeStart) + lines
252 lines = (['\n'] * -maybeStart) + lines
253 if len(lines) < context:
253 if len(lines) < context:
254 lines += ['\n'] * (context - len(lines))
254 lines += ['\n'] * (context - len(lines))
255 buf = list(records[i])
255 buf = list(records[i])
256 buf[LNUM_POS] = lnum
256 buf[LNUM_POS] = lnum
257 buf[INDEX_POS] = lnum - 1 - start
257 buf[INDEX_POS] = lnum - 1 - start
258 buf[LINES_POS] = lines
258 buf[LINES_POS] = lines
259 records[i] = tuple(buf)
259 records[i] = tuple(buf)
260 return records[tb_offset:]
260 return records[tb_offset:]
261
261
262 # Helper function -- largely belongs to VerboseTB, but we need the same
262 # Helper function -- largely belongs to VerboseTB, but we need the same
263 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
263 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
264 # can be recognized properly by ipython.el's py-traceback-line-re
264 # can be recognized properly by ipython.el's py-traceback-line-re
265 # (SyntaxErrors have to be treated specially because they have no traceback)
265 # (SyntaxErrors have to be treated specially because they have no traceback)
266
266
267 _parser = PyColorize.Parser()
267 _parser = PyColorize.Parser()
268
268
269 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None):
269 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None):
270 numbers_width = INDENT_SIZE - 1
270 numbers_width = INDENT_SIZE - 1
271 res = []
271 res = []
272 i = lnum - index
272 i = lnum - index
273
273
274 # This lets us get fully syntax-highlighted tracebacks.
274 # This lets us get fully syntax-highlighted tracebacks.
275 if scheme is None:
275 if scheme is None:
276 try:
276 try:
277 scheme = __IPYTHON__.rc.colors
277 scheme = __IPYTHON__.rc.colors
278 except:
278 except:
279 scheme = DEFAULT_SCHEME
279 scheme = DEFAULT_SCHEME
280 _line_format = _parser.format2
280 _line_format = _parser.format2
281
281
282 for line in lines:
282 for line in lines:
283 new_line, err = _line_format(line,'str',scheme)
283 new_line, err = _line_format(line,'str',scheme)
284 if not err: line = new_line
284 if not err: line = new_line
285
285
286 if i == lnum:
286 if i == lnum:
287 # This is the line with the error
287 # This is the line with the error
288 pad = numbers_width - len(str(i))
288 pad = numbers_width - len(str(i))
289 if pad >= 3:
289 if pad >= 3:
290 marker = '-'*(pad-3) + '-> '
290 marker = '-'*(pad-3) + '-> '
291 elif pad == 2:
291 elif pad == 2:
292 marker = '> '
292 marker = '> '
293 elif pad == 1:
293 elif pad == 1:
294 marker = '>'
294 marker = '>'
295 else:
295 else:
296 marker = ''
296 marker = ''
297 num = marker + str(i)
297 num = marker + str(i)
298 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
298 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
299 Colors.line, line, Colors.Normal)
299 Colors.line, line, Colors.Normal)
300 else:
300 else:
301 num = '%*s' % (numbers_width,i)
301 num = '%*s' % (numbers_width,i)
302 line = '%s%s%s %s' %(Colors.lineno, num,
302 line = '%s%s%s %s' %(Colors.lineno, num,
303 Colors.Normal, line)
303 Colors.Normal, line)
304
304
305 res.append(line)
305 res.append(line)
306 if lvals and i == lnum:
306 if lvals and i == lnum:
307 res.append(lvals + '\n')
307 res.append(lvals + '\n')
308 i = i + 1
308 i = i + 1
309 return res
309 return res
310
310
311
311
312 #---------------------------------------------------------------------------
312 #---------------------------------------------------------------------------
313 # Module classes
313 # Module classes
314 class TBTools:
314 class TBTools:
315 """Basic tools used by all traceback printer classes."""
315 """Basic tools used by all traceback printer classes."""
316
316
317 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
317 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
318 # Whether to call the interactive pdb debugger after printing
318 # Whether to call the interactive pdb debugger after printing
319 # tracebacks or not
319 # tracebacks or not
320 self.call_pdb = call_pdb
320 self.call_pdb = call_pdb
321
321
322 # Create color table
322 # Create color table
323 self.color_scheme_table = ExceptionColors
323 self.color_scheme_table = ExceptionColors
324
324
325 self.set_colors(color_scheme)
325 self.set_colors(color_scheme)
326 self.old_scheme = color_scheme # save initial value for toggles
326 self.old_scheme = color_scheme # save initial value for toggles
327
327
328 if call_pdb:
328 if call_pdb:
329 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
329 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
330 else:
330 else:
331 self.pdb = None
331 self.pdb = None
332
332
333 def set_colors(self,*args,**kw):
333 def set_colors(self,*args,**kw):
334 """Shorthand access to the color table scheme selector method."""
334 """Shorthand access to the color table scheme selector method."""
335
335
336 # Set own color table
336 # Set own color table
337 self.color_scheme_table.set_active_scheme(*args,**kw)
337 self.color_scheme_table.set_active_scheme(*args,**kw)
338 # for convenience, set Colors to the active scheme
338 # for convenience, set Colors to the active scheme
339 self.Colors = self.color_scheme_table.active_colors
339 self.Colors = self.color_scheme_table.active_colors
340 # Also set colors of debugger
340 # Also set colors of debugger
341 if hasattr(self,'pdb') and self.pdb is not None:
341 if hasattr(self,'pdb') and self.pdb is not None:
342 self.pdb.set_colors(*args,**kw)
342 self.pdb.set_colors(*args,**kw)
343
343
344 def color_toggle(self):
344 def color_toggle(self):
345 """Toggle between the currently active color scheme and NoColor."""
345 """Toggle between the currently active color scheme and NoColor."""
346
346
347 if self.color_scheme_table.active_scheme_name == 'NoColor':
347 if self.color_scheme_table.active_scheme_name == 'NoColor':
348 self.color_scheme_table.set_active_scheme(self.old_scheme)
348 self.color_scheme_table.set_active_scheme(self.old_scheme)
349 self.Colors = self.color_scheme_table.active_colors
349 self.Colors = self.color_scheme_table.active_colors
350 else:
350 else:
351 self.old_scheme = self.color_scheme_table.active_scheme_name
351 self.old_scheme = self.color_scheme_table.active_scheme_name
352 self.color_scheme_table.set_active_scheme('NoColor')
352 self.color_scheme_table.set_active_scheme('NoColor')
353 self.Colors = self.color_scheme_table.active_colors
353 self.Colors = self.color_scheme_table.active_colors
354
354
355 #---------------------------------------------------------------------------
355 #---------------------------------------------------------------------------
356 class ListTB(TBTools):
356 class ListTB(TBTools):
357 """Print traceback information from a traceback list, with optional color.
357 """Print traceback information from a traceback list, with optional color.
358
358
359 Calling: requires 3 arguments:
359 Calling: requires 3 arguments:
360 (etype, evalue, elist)
360 (etype, evalue, elist)
361 as would be obtained by:
361 as would be obtained by:
362 etype, evalue, tb = sys.exc_info()
362 etype, evalue, tb = sys.exc_info()
363 if tb:
363 if tb:
364 elist = traceback.extract_tb(tb)
364 elist = traceback.extract_tb(tb)
365 else:
365 else:
366 elist = None
366 elist = None
367
367
368 It can thus be used by programs which need to process the traceback before
368 It can thus be used by programs which need to process the traceback before
369 printing (such as console replacements based on the code module from the
369 printing (such as console replacements based on the code module from the
370 standard library).
370 standard library).
371
371
372 Because they are meant to be called without a full traceback (only a
372 Because they are meant to be called without a full traceback (only a
373 list), instances of this class can't call the interactive pdb debugger."""
373 list), instances of this class can't call the interactive pdb debugger."""
374
374
375 def __init__(self,color_scheme = 'NoColor'):
375 def __init__(self,color_scheme = 'NoColor'):
376 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
376 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
377
377
378 def __call__(self, etype, value, elist):
378 def __call__(self, etype, value, elist):
379 Term.cout.flush()
379 Term.cout.flush()
380 print >> Term.cerr, self.text(etype,value,elist)
380 print >> Term.cerr, self.text(etype,value,elist)
381 Term.cerr.flush()
381 Term.cerr.flush()
382
382
383 def text(self,etype, value, elist,context=5):
383 def text(self,etype, value, elist,context=5):
384 """Return a color formatted string with the traceback info."""
384 """Return a color formatted string with the traceback info."""
385
385
386 Colors = self.Colors
386 Colors = self.Colors
387 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
387 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
388 if elist:
388 if elist:
389 out_string.append('Traceback %s(most recent call last)%s:' % \
389 out_string.append('Traceback %s(most recent call last)%s:' % \
390 (Colors.normalEm, Colors.Normal) + '\n')
390 (Colors.normalEm, Colors.Normal) + '\n')
391 out_string.extend(self._format_list(elist))
391 out_string.extend(self._format_list(elist))
392 lines = self._format_exception_only(etype, value)
392 lines = self._format_exception_only(etype, value)
393 for line in lines[:-1]:
393 for line in lines[:-1]:
394 out_string.append(" "+line)
394 out_string.append(" "+line)
395 out_string.append(lines[-1])
395 out_string.append(lines[-1])
396 return ''.join(out_string)
396 return ''.join(out_string)
397
397
398 def _format_list(self, extracted_list):
398 def _format_list(self, extracted_list):
399 """Format a list of traceback entry tuples for printing.
399 """Format a list of traceback entry tuples for printing.
400
400
401 Given a list of tuples as returned by extract_tb() or
401 Given a list of tuples as returned by extract_tb() or
402 extract_stack(), return a list of strings ready for printing.
402 extract_stack(), return a list of strings ready for printing.
403 Each string in the resulting list corresponds to the item with the
403 Each string in the resulting list corresponds to the item with the
404 same index in the argument list. Each string ends in a newline;
404 same index in the argument list. Each string ends in a newline;
405 the strings may contain internal newlines as well, for those items
405 the strings may contain internal newlines as well, for those items
406 whose source text line is not None.
406 whose source text line is not None.
407
407
408 Lifted almost verbatim from traceback.py
408 Lifted almost verbatim from traceback.py
409 """
409 """
410
410
411 Colors = self.Colors
411 Colors = self.Colors
412 list = []
412 list = []
413 for filename, lineno, name, line in extracted_list[:-1]:
413 for filename, lineno, name, line in extracted_list[:-1]:
414 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
414 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
415 (Colors.filename, filename, Colors.Normal,
415 (Colors.filename, filename, Colors.Normal,
416 Colors.lineno, lineno, Colors.Normal,
416 Colors.lineno, lineno, Colors.Normal,
417 Colors.name, name, Colors.Normal)
417 Colors.name, name, Colors.Normal)
418 if line:
418 if line:
419 item = item + ' %s\n' % line.strip()
419 item = item + ' %s\n' % line.strip()
420 list.append(item)
420 list.append(item)
421 # Emphasize the last entry
421 # Emphasize the last entry
422 filename, lineno, name, line = extracted_list[-1]
422 filename, lineno, name, line = extracted_list[-1]
423 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
423 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
424 (Colors.normalEm,
424 (Colors.normalEm,
425 Colors.filenameEm, filename, Colors.normalEm,
425 Colors.filenameEm, filename, Colors.normalEm,
426 Colors.linenoEm, lineno, Colors.normalEm,
426 Colors.linenoEm, lineno, Colors.normalEm,
427 Colors.nameEm, name, Colors.normalEm,
427 Colors.nameEm, name, Colors.normalEm,
428 Colors.Normal)
428 Colors.Normal)
429 if line:
429 if line:
430 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
430 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
431 Colors.Normal)
431 Colors.Normal)
432 list.append(item)
432 list.append(item)
433 return list
433 return list
434
434
435 def _format_exception_only(self, etype, value):
435 def _format_exception_only(self, etype, value):
436 """Format the exception part of a traceback.
436 """Format the exception part of a traceback.
437
437
438 The arguments are the exception type and value such as given by
438 The arguments are the exception type and value such as given by
439 sys.exc_info()[:2]. The return value is a list of strings, each ending
439 sys.exc_info()[:2]. The return value is a list of strings, each ending
440 in a newline. Normally, the list contains a single string; however,
440 in a newline. Normally, the list contains a single string; however,
441 for SyntaxError exceptions, it contains several lines that (when
441 for SyntaxError exceptions, it contains several lines that (when
442 printed) display detailed information about where the syntax error
442 printed) display detailed information about where the syntax error
443 occurred. The message indicating which exception occurred is the
443 occurred. The message indicating which exception occurred is the
444 always last string in the list.
444 always last string in the list.
445
445
446 Also lifted nearly verbatim from traceback.py
446 Also lifted nearly verbatim from traceback.py
447 """
447 """
448
448
449 have_filedata = False
449 Colors = self.Colors
450 Colors = self.Colors
450 list = []
451 list = []
451 try:
452 try:
452 stype = Colors.excName + etype.__name__ + Colors.Normal
453 stype = Colors.excName + etype.__name__ + Colors.Normal
453 except AttributeError:
454 except AttributeError:
454 stype = etype # String exceptions don't get special coloring
455 stype = etype # String exceptions don't get special coloring
455 if value is None:
456 if value is None:
456 list.append( str(stype) + '\n')
457 list.append( str(stype) + '\n')
457 else:
458 else:
458 if etype is SyntaxError:
459 if etype is SyntaxError:
459 try:
460 try:
460 msg, (filename, lineno, offset, line) = value
461 msg, (filename, lineno, offset, line) = value
461 except:
462 except:
462 have_filedata = False
463 have_filedata = False
463 else:
464 else:
464 have_filedata = True
465 have_filedata = True
465 #print 'filename is',filename # dbg
466 #print 'filename is',filename # dbg
466 if not filename: filename = "<string>"
467 if not filename: filename = "<string>"
467 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
468 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
468 (Colors.normalEm,
469 (Colors.normalEm,
469 Colors.filenameEm, filename, Colors.normalEm,
470 Colors.filenameEm, filename, Colors.normalEm,
470 Colors.linenoEm, lineno, Colors.Normal ))
471 Colors.linenoEm, lineno, Colors.Normal ))
471 if line is not None:
472 if line is not None:
472 i = 0
473 i = 0
473 while i < len(line) and line[i].isspace():
474 while i < len(line) and line[i].isspace():
474 i = i+1
475 i = i+1
475 list.append('%s %s%s\n' % (Colors.line,
476 list.append('%s %s%s\n' % (Colors.line,
476 line.strip(),
477 line.strip(),
477 Colors.Normal))
478 Colors.Normal))
478 if offset is not None:
479 if offset is not None:
479 s = ' '
480 s = ' '
480 for c in line[i:offset-1]:
481 for c in line[i:offset-1]:
481 if c.isspace():
482 if c.isspace():
482 s = s + c
483 s = s + c
483 else:
484 else:
484 s = s + ' '
485 s = s + ' '
485 list.append('%s%s^%s\n' % (Colors.caret, s,
486 list.append('%s%s^%s\n' % (Colors.caret, s,
486 Colors.Normal) )
487 Colors.Normal) )
487 value = msg
488 value = msg
488 s = self._some_str(value)
489 s = self._some_str(value)
489 if s:
490 if s:
490 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
491 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
491 Colors.Normal, s))
492 Colors.Normal, s))
492 else:
493 else:
493 list.append('%s\n' % str(stype))
494 list.append('%s\n' % str(stype))
494
495
495 # vds:>>
496 # vds:>>
496 if have_filedata:
497 if have_filedata:
497 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
498 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
498 # vds:<<
499 # vds:<<
499
500
500 return list
501 return list
501
502
502 def _some_str(self, value):
503 def _some_str(self, value):
503 # Lifted from traceback.py
504 # Lifted from traceback.py
504 try:
505 try:
505 return str(value)
506 return str(value)
506 except:
507 except:
507 return '<unprintable %s object>' % type(value).__name__
508 return '<unprintable %s object>' % type(value).__name__
508
509
509 #----------------------------------------------------------------------------
510 #----------------------------------------------------------------------------
510 class VerboseTB(TBTools):
511 class VerboseTB(TBTools):
511 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
512 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
512 of HTML. Requires inspect and pydoc. Crazy, man.
513 of HTML. Requires inspect and pydoc. Crazy, man.
513
514
514 Modified version which optionally strips the topmost entries from the
515 Modified version which optionally strips the topmost entries from the
515 traceback, to be used with alternate interpreters (because their own code
516 traceback, to be used with alternate interpreters (because their own code
516 would appear in the traceback)."""
517 would appear in the traceback)."""
517
518
518 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
519 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
519 call_pdb = 0, include_vars=1):
520 call_pdb = 0, include_vars=1):
520 """Specify traceback offset, headers and color scheme.
521 """Specify traceback offset, headers and color scheme.
521
522
522 Define how many frames to drop from the tracebacks. Calling it with
523 Define how many frames to drop from the tracebacks. Calling it with
523 tb_offset=1 allows use of this handler in interpreters which will have
524 tb_offset=1 allows use of this handler in interpreters which will have
524 their own code at the top of the traceback (VerboseTB will first
525 their own code at the top of the traceback (VerboseTB will first
525 remove that frame before printing the traceback info)."""
526 remove that frame before printing the traceback info)."""
526 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
527 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
527 self.tb_offset = tb_offset
528 self.tb_offset = tb_offset
528 self.long_header = long_header
529 self.long_header = long_header
529 self.include_vars = include_vars
530 self.include_vars = include_vars
530
531
531 def text(self, etype, evalue, etb, context=5):
532 def text(self, etype, evalue, etb, context=5):
532 """Return a nice text document describing the traceback."""
533 """Return a nice text document describing the traceback."""
533
534
534 # some locals
535 # some locals
535 try:
536 try:
536 etype = etype.__name__
537 etype = etype.__name__
537 except AttributeError:
538 except AttributeError:
538 pass
539 pass
539 Colors = self.Colors # just a shorthand + quicker name lookup
540 Colors = self.Colors # just a shorthand + quicker name lookup
540 ColorsNormal = Colors.Normal # used a lot
541 ColorsNormal = Colors.Normal # used a lot
541 col_scheme = self.color_scheme_table.active_scheme_name
542 col_scheme = self.color_scheme_table.active_scheme_name
542 indent = ' '*INDENT_SIZE
543 indent = ' '*INDENT_SIZE
543 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
544 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
544 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
545 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
545 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
546 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
546
547
547 # some internal-use functions
548 # some internal-use functions
548 def text_repr(value):
549 def text_repr(value):
549 """Hopefully pretty robust repr equivalent."""
550 """Hopefully pretty robust repr equivalent."""
550 # this is pretty horrible but should always return *something*
551 # this is pretty horrible but should always return *something*
551 try:
552 try:
552 return pydoc.text.repr(value)
553 return pydoc.text.repr(value)
553 except KeyboardInterrupt:
554 except KeyboardInterrupt:
554 raise
555 raise
555 except:
556 except:
556 try:
557 try:
557 return repr(value)
558 return repr(value)
558 except KeyboardInterrupt:
559 except KeyboardInterrupt:
559 raise
560 raise
560 except:
561 except:
561 try:
562 try:
562 # all still in an except block so we catch
563 # all still in an except block so we catch
563 # getattr raising
564 # getattr raising
564 name = getattr(value, '__name__', None)
565 name = getattr(value, '__name__', None)
565 if name:
566 if name:
566 # ick, recursion
567 # ick, recursion
567 return text_repr(name)
568 return text_repr(name)
568 klass = getattr(value, '__class__', None)
569 klass = getattr(value, '__class__', None)
569 if klass:
570 if klass:
570 return '%s instance' % text_repr(klass)
571 return '%s instance' % text_repr(klass)
571 except KeyboardInterrupt:
572 except KeyboardInterrupt:
572 raise
573 raise
573 except:
574 except:
574 return 'UNRECOVERABLE REPR FAILURE'
575 return 'UNRECOVERABLE REPR FAILURE'
575 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
576 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
576 def nullrepr(value, repr=text_repr): return ''
577 def nullrepr(value, repr=text_repr): return ''
577
578
578 # meat of the code begins
579 # meat of the code begins
579 try:
580 try:
580 etype = etype.__name__
581 etype = etype.__name__
581 except AttributeError:
582 except AttributeError:
582 pass
583 pass
583
584
584 if self.long_header:
585 if self.long_header:
585 # Header with the exception type, python version, and date
586 # Header with the exception type, python version, and date
586 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
587 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
587 date = time.ctime(time.time())
588 date = time.ctime(time.time())
588
589
589 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
590 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
590 exc, ' '*(75-len(str(etype))-len(pyver)),
591 exc, ' '*(75-len(str(etype))-len(pyver)),
591 pyver, string.rjust(date, 75) )
592 pyver, string.rjust(date, 75) )
592 head += "\nA problem occured executing Python code. Here is the sequence of function"\
593 head += "\nA problem occured executing Python code. Here is the sequence of function"\
593 "\ncalls leading up to the error, with the most recent (innermost) call last."
594 "\ncalls leading up to the error, with the most recent (innermost) call last."
594 else:
595 else:
595 # Simplified header
596 # Simplified header
596 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
597 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
597 string.rjust('Traceback (most recent call last)',
598 string.rjust('Traceback (most recent call last)',
598 75 - len(str(etype)) ) )
599 75 - len(str(etype)) ) )
599 frames = []
600 frames = []
600 # Flush cache before calling inspect. This helps alleviate some of the
601 # Flush cache before calling inspect. This helps alleviate some of the
601 # problems with python 2.3's inspect.py.
602 # problems with python 2.3's inspect.py.
602 linecache.checkcache()
603 linecache.checkcache()
603 # Drop topmost frames if requested
604 # Drop topmost frames if requested
604 try:
605 try:
605 # Try the default getinnerframes and Alex's: Alex's fixes some
606 # Try the default getinnerframes and Alex's: Alex's fixes some
606 # problems, but it generates empty tracebacks for console errors
607 # problems, but it generates empty tracebacks for console errors
607 # (5 blanks lines) where none should be returned.
608 # (5 blanks lines) where none should be returned.
608 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
609 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
609 #print 'python records:', records # dbg
610 #print 'python records:', records # dbg
610 records = _fixed_getinnerframes(etb, context,self.tb_offset)
611 records = _fixed_getinnerframes(etb, context,self.tb_offset)
611 #print 'alex records:', records # dbg
612 #print 'alex records:', records # dbg
612 except:
613 except:
613
614
614 # FIXME: I've been getting many crash reports from python 2.3
615 # FIXME: I've been getting many crash reports from python 2.3
615 # users, traceable to inspect.py. If I can find a small test-case
616 # users, traceable to inspect.py. If I can find a small test-case
616 # to reproduce this, I should either write a better workaround or
617 # to reproduce this, I should either write a better workaround or
617 # file a bug report against inspect (if that's the real problem).
618 # file a bug report against inspect (if that's the real problem).
618 # So far, I haven't been able to find an isolated example to
619 # So far, I haven't been able to find an isolated example to
619 # reproduce the problem.
620 # reproduce the problem.
620 inspect_error()
621 inspect_error()
621 traceback.print_exc(file=Term.cerr)
622 traceback.print_exc(file=Term.cerr)
622 info('\nUnfortunately, your original traceback can not be constructed.\n')
623 info('\nUnfortunately, your original traceback can not be constructed.\n')
623 return ''
624 return ''
624
625
625 # build some color string templates outside these nested loops
626 # build some color string templates outside these nested loops
626 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
627 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
627 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
628 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
628 ColorsNormal)
629 ColorsNormal)
629 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
630 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
630 (Colors.vName, Colors.valEm, ColorsNormal)
631 (Colors.vName, Colors.valEm, ColorsNormal)
631 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
632 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
632 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
633 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
633 Colors.vName, ColorsNormal)
634 Colors.vName, ColorsNormal)
634 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
635 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
635 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
636 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
636 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
637 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
637 ColorsNormal)
638 ColorsNormal)
638
639
639 # now, loop over all records printing context and info
640 # now, loop over all records printing context and info
640 abspath = os.path.abspath
641 abspath = os.path.abspath
641 for frame, file, lnum, func, lines, index in records:
642 for frame, file, lnum, func, lines, index in records:
642 #print '*** record:',file,lnum,func,lines,index # dbg
643 #print '*** record:',file,lnum,func,lines,index # dbg
643 try:
644 try:
644 file = file and abspath(file) or '?'
645 file = file and abspath(file) or '?'
645 except OSError:
646 except OSError:
646 # if file is '<console>' or something not in the filesystem,
647 # if file is '<console>' or something not in the filesystem,
647 # the abspath call will throw an OSError. Just ignore it and
648 # the abspath call will throw an OSError. Just ignore it and
648 # keep the original file string.
649 # keep the original file string.
649 pass
650 pass
650 link = tpl_link % file
651 link = tpl_link % file
651 try:
652 try:
652 args, varargs, varkw, locals = inspect.getargvalues(frame)
653 args, varargs, varkw, locals = inspect.getargvalues(frame)
653 except:
654 except:
654 # This can happen due to a bug in python2.3. We should be
655 # This can happen due to a bug in python2.3. We should be
655 # able to remove this try/except when 2.4 becomes a
656 # able to remove this try/except when 2.4 becomes a
656 # requirement. Bug details at http://python.org/sf/1005466
657 # requirement. Bug details at http://python.org/sf/1005466
657 inspect_error()
658 inspect_error()
658 traceback.print_exc(file=Term.cerr)
659 traceback.print_exc(file=Term.cerr)
659 info("\nIPython's exception reporting continues...\n")
660 info("\nIPython's exception reporting continues...\n")
660
661
661 if func == '?':
662 if func == '?':
662 call = ''
663 call = ''
663 else:
664 else:
664 # Decide whether to include variable details or not
665 # Decide whether to include variable details or not
665 var_repr = self.include_vars and eqrepr or nullrepr
666 var_repr = self.include_vars and eqrepr or nullrepr
666 try:
667 try:
667 call = tpl_call % (func,inspect.formatargvalues(args,
668 call = tpl_call % (func,inspect.formatargvalues(args,
668 varargs, varkw,
669 varargs, varkw,
669 locals,formatvalue=var_repr))
670 locals,formatvalue=var_repr))
670 except KeyError:
671 except KeyError:
671 # Very odd crash from inspect.formatargvalues(). The
672 # Very odd crash from inspect.formatargvalues(). The
672 # scenario under which it appeared was a call to
673 # scenario under which it appeared was a call to
673 # view(array,scale) in NumTut.view.view(), where scale had
674 # view(array,scale) in NumTut.view.view(), where scale had
674 # been defined as a scalar (it should be a tuple). Somehow
675 # been defined as a scalar (it should be a tuple). Somehow
675 # inspect messes up resolving the argument list of view()
676 # inspect messes up resolving the argument list of view()
676 # and barfs out. At some point I should dig into this one
677 # and barfs out. At some point I should dig into this one
677 # and file a bug report about it.
678 # and file a bug report about it.
678 inspect_error()
679 inspect_error()
679 traceback.print_exc(file=Term.cerr)
680 traceback.print_exc(file=Term.cerr)
680 info("\nIPython's exception reporting continues...\n")
681 info("\nIPython's exception reporting continues...\n")
681 call = tpl_call_fail % func
682 call = tpl_call_fail % func
682
683
683 # Initialize a list of names on the current line, which the
684 # Initialize a list of names on the current line, which the
684 # tokenizer below will populate.
685 # tokenizer below will populate.
685 names = []
686 names = []
686
687
687 def tokeneater(token_type, token, start, end, line):
688 def tokeneater(token_type, token, start, end, line):
688 """Stateful tokeneater which builds dotted names.
689 """Stateful tokeneater which builds dotted names.
689
690
690 The list of names it appends to (from the enclosing scope) can
691 The list of names it appends to (from the enclosing scope) can
691 contain repeated composite names. This is unavoidable, since
692 contain repeated composite names. This is unavoidable, since
692 there is no way to disambguate partial dotted structures until
693 there is no way to disambguate partial dotted structures until
693 the full list is known. The caller is responsible for pruning
694 the full list is known. The caller is responsible for pruning
694 the final list of duplicates before using it."""
695 the final list of duplicates before using it."""
695
696
696 # build composite names
697 # build composite names
697 if token == '.':
698 if token == '.':
698 try:
699 try:
699 names[-1] += '.'
700 names[-1] += '.'
700 # store state so the next token is added for x.y.z names
701 # store state so the next token is added for x.y.z names
701 tokeneater.name_cont = True
702 tokeneater.name_cont = True
702 return
703 return
703 except IndexError:
704 except IndexError:
704 pass
705 pass
705 if token_type == tokenize.NAME and token not in keyword.kwlist:
706 if token_type == tokenize.NAME and token not in keyword.kwlist:
706 if tokeneater.name_cont:
707 if tokeneater.name_cont:
707 # Dotted names
708 # Dotted names
708 names[-1] += token
709 names[-1] += token
709 tokeneater.name_cont = False
710 tokeneater.name_cont = False
710 else:
711 else:
711 # Regular new names. We append everything, the caller
712 # Regular new names. We append everything, the caller
712 # will be responsible for pruning the list later. It's
713 # will be responsible for pruning the list later. It's
713 # very tricky to try to prune as we go, b/c composite
714 # very tricky to try to prune as we go, b/c composite
714 # names can fool us. The pruning at the end is easy
715 # names can fool us. The pruning at the end is easy
715 # to do (or the caller can print a list with repeated
716 # to do (or the caller can print a list with repeated
716 # names if so desired.
717 # names if so desired.
717 names.append(token)
718 names.append(token)
718 elif token_type == tokenize.NEWLINE:
719 elif token_type == tokenize.NEWLINE:
719 raise IndexError
720 raise IndexError
720 # we need to store a bit of state in the tokenizer to build
721 # we need to store a bit of state in the tokenizer to build
721 # dotted names
722 # dotted names
722 tokeneater.name_cont = False
723 tokeneater.name_cont = False
723
724
724 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
725 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
725 line = getline(file, lnum[0])
726 line = getline(file, lnum[0])
726 lnum[0] += 1
727 lnum[0] += 1
727 return line
728 return line
728
729
729 # Build the list of names on this line of code where the exception
730 # Build the list of names on this line of code where the exception
730 # occurred.
731 # occurred.
731 try:
732 try:
732 # This builds the names list in-place by capturing it from the
733 # This builds the names list in-place by capturing it from the
733 # enclosing scope.
734 # enclosing scope.
734 tokenize.tokenize(linereader, tokeneater)
735 tokenize.tokenize(linereader, tokeneater)
735 except IndexError:
736 except IndexError:
736 # signals exit of tokenizer
737 # signals exit of tokenizer
737 pass
738 pass
738 except tokenize.TokenError,msg:
739 except tokenize.TokenError,msg:
739 _m = ("An unexpected error occurred while tokenizing input\n"
740 _m = ("An unexpected error occurred while tokenizing input\n"
740 "The following traceback may be corrupted or invalid\n"
741 "The following traceback may be corrupted or invalid\n"
741 "The error message is: %s\n" % msg)
742 "The error message is: %s\n" % msg)
742 error(_m)
743 error(_m)
743
744
744 # prune names list of duplicates, but keep the right order
745 # prune names list of duplicates, but keep the right order
745 unique_names = uniq_stable(names)
746 unique_names = uniq_stable(names)
746
747
747 # Start loop over vars
748 # Start loop over vars
748 lvals = []
749 lvals = []
749 if self.include_vars:
750 if self.include_vars:
750 for name_full in unique_names:
751 for name_full in unique_names:
751 name_base = name_full.split('.',1)[0]
752 name_base = name_full.split('.',1)[0]
752 if name_base in frame.f_code.co_varnames:
753 if name_base in frame.f_code.co_varnames:
753 if locals.has_key(name_base):
754 if locals.has_key(name_base):
754 try:
755 try:
755 value = repr(eval(name_full,locals))
756 value = repr(eval(name_full,locals))
756 except:
757 except:
757 value = undefined
758 value = undefined
758 else:
759 else:
759 value = undefined
760 value = undefined
760 name = tpl_local_var % name_full
761 name = tpl_local_var % name_full
761 else:
762 else:
762 if frame.f_globals.has_key(name_base):
763 if frame.f_globals.has_key(name_base):
763 try:
764 try:
764 value = repr(eval(name_full,frame.f_globals))
765 value = repr(eval(name_full,frame.f_globals))
765 except:
766 except:
766 value = undefined
767 value = undefined
767 else:
768 else:
768 value = undefined
769 value = undefined
769 name = tpl_global_var % name_full
770 name = tpl_global_var % name_full
770 lvals.append(tpl_name_val % (name,value))
771 lvals.append(tpl_name_val % (name,value))
771 if lvals:
772 if lvals:
772 lvals = '%s%s' % (indent,em_normal.join(lvals))
773 lvals = '%s%s' % (indent,em_normal.join(lvals))
773 else:
774 else:
774 lvals = ''
775 lvals = ''
775
776
776 level = '%s %s\n' % (link,call)
777 level = '%s %s\n' % (link,call)
777
778
778 if index is None:
779 if index is None:
779 frames.append(level)
780 frames.append(level)
780 else:
781 else:
781 frames.append('%s%s' % (level,''.join(
782 frames.append('%s%s' % (level,''.join(
782 _formatTracebackLines(lnum,index,lines,Colors,lvals,
783 _formatTracebackLines(lnum,index,lines,Colors,lvals,
783 col_scheme))))
784 col_scheme))))
784
785
785 # Get (safely) a string form of the exception info
786 # Get (safely) a string form of the exception info
786 try:
787 try:
787 etype_str,evalue_str = map(str,(etype,evalue))
788 etype_str,evalue_str = map(str,(etype,evalue))
788 except:
789 except:
789 # User exception is improperly defined.
790 # User exception is improperly defined.
790 etype,evalue = str,sys.exc_info()[:2]
791 etype,evalue = str,sys.exc_info()[:2]
791 etype_str,evalue_str = map(str,(etype,evalue))
792 etype_str,evalue_str = map(str,(etype,evalue))
792 # ... and format it
793 # ... and format it
793 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
794 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
794 ColorsNormal, evalue_str)]
795 ColorsNormal, evalue_str)]
795 if type(evalue) is types.InstanceType:
796 if type(evalue) is types.InstanceType:
796 try:
797 try:
797 names = [w for w in dir(evalue) if isinstance(w, basestring)]
798 names = [w for w in dir(evalue) if isinstance(w, basestring)]
798 except:
799 except:
799 # Every now and then, an object with funny inernals blows up
800 # Every now and then, an object with funny inernals blows up
800 # when dir() is called on it. We do the best we can to report
801 # when dir() is called on it. We do the best we can to report
801 # the problem and continue
802 # the problem and continue
802 _m = '%sException reporting error (object with broken dir())%s:'
803 _m = '%sException reporting error (object with broken dir())%s:'
803 exception.append(_m % (Colors.excName,ColorsNormal))
804 exception.append(_m % (Colors.excName,ColorsNormal))
804 etype_str,evalue_str = map(str,sys.exc_info()[:2])
805 etype_str,evalue_str = map(str,sys.exc_info()[:2])
805 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
806 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
806 ColorsNormal, evalue_str))
807 ColorsNormal, evalue_str))
807 names = []
808 names = []
808 for name in names:
809 for name in names:
809 value = text_repr(getattr(evalue, name))
810 value = text_repr(getattr(evalue, name))
810 exception.append('\n%s%s = %s' % (indent, name, value))
811 exception.append('\n%s%s = %s' % (indent, name, value))
811
812
812 # vds: >>
813 # vds: >>
813 if records:
814 if records:
814 filepath, lnum = records[-1][1:3]
815 filepath, lnum = records[-1][1:3]
815 #print "file:", str(file), "linenb", str(lnum) # dbg
816 #print "file:", str(file), "linenb", str(lnum) # dbg
816 filepath = os.path.abspath(filepath)
817 filepath = os.path.abspath(filepath)
817 __IPYTHON__.hooks.synchronize_with_editor(filepath, lnum, 0)
818 __IPYTHON__.hooks.synchronize_with_editor(filepath, lnum, 0)
818 # vds: <<
819 # vds: <<
819
820
820 # return all our info assembled as a single string
821 # return all our info assembled as a single string
821 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
822 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
822
823
823 def debugger(self,force=False):
824 def debugger(self,force=False):
824 """Call up the pdb debugger if desired, always clean up the tb
825 """Call up the pdb debugger if desired, always clean up the tb
825 reference.
826 reference.
826
827
827 Keywords:
828 Keywords:
828
829
829 - force(False): by default, this routine checks the instance call_pdb
830 - force(False): by default, this routine checks the instance call_pdb
830 flag and does not actually invoke the debugger if the flag is false.
831 flag and does not actually invoke the debugger if the flag is false.
831 The 'force' option forces the debugger to activate even if the flag
832 The 'force' option forces the debugger to activate even if the flag
832 is false.
833 is false.
833
834
834 If the call_pdb flag is set, the pdb interactive debugger is
835 If the call_pdb flag is set, the pdb interactive debugger is
835 invoked. In all cases, the self.tb reference to the current traceback
836 invoked. In all cases, the self.tb reference to the current traceback
836 is deleted to prevent lingering references which hamper memory
837 is deleted to prevent lingering references which hamper memory
837 management.
838 management.
838
839
839 Note that each call to pdb() does an 'import readline', so if your app
840 Note that each call to pdb() does an 'import readline', so if your app
840 requires a special setup for the readline completers, you'll have to
841 requires a special setup for the readline completers, you'll have to
841 fix that by hand after invoking the exception handler."""
842 fix that by hand after invoking the exception handler."""
842
843
843 if force or self.call_pdb:
844 if force or self.call_pdb:
844 if self.pdb is None:
845 if self.pdb is None:
845 self.pdb = Debugger.Pdb(
846 self.pdb = Debugger.Pdb(
846 self.color_scheme_table.active_scheme_name)
847 self.color_scheme_table.active_scheme_name)
847 # the system displayhook may have changed, restore the original
848 # the system displayhook may have changed, restore the original
848 # for pdb
849 # for pdb
849 dhook = sys.displayhook
850 dhook = sys.displayhook
850 sys.displayhook = sys.__displayhook__
851 sys.displayhook = sys.__displayhook__
851 self.pdb.reset()
852 self.pdb.reset()
852 # Find the right frame so we don't pop up inside ipython itself
853 # Find the right frame so we don't pop up inside ipython itself
853 if hasattr(self,'tb'):
854 if hasattr(self,'tb'):
854 etb = self.tb
855 etb = self.tb
855 else:
856 else:
856 etb = self.tb = sys.last_traceback
857 etb = self.tb = sys.last_traceback
857 while self.tb.tb_next is not None:
858 while self.tb.tb_next is not None:
858 self.tb = self.tb.tb_next
859 self.tb = self.tb.tb_next
859 try:
860 try:
860 if etb and etb.tb_next:
861 if etb and etb.tb_next:
861 etb = etb.tb_next
862 etb = etb.tb_next
862 self.pdb.botframe = etb.tb_frame
863 self.pdb.botframe = etb.tb_frame
863 self.pdb.interaction(self.tb.tb_frame, self.tb)
864 self.pdb.interaction(self.tb.tb_frame, self.tb)
864 finally:
865 finally:
865 sys.displayhook = dhook
866 sys.displayhook = dhook
866
867
867 if hasattr(self,'tb'):
868 if hasattr(self,'tb'):
868 del self.tb
869 del self.tb
869
870
870 def handler(self, info=None):
871 def handler(self, info=None):
871 (etype, evalue, etb) = info or sys.exc_info()
872 (etype, evalue, etb) = info or sys.exc_info()
872 self.tb = etb
873 self.tb = etb
873 Term.cout.flush()
874 Term.cout.flush()
874 print >> Term.cerr, self.text(etype, evalue, etb)
875 print >> Term.cerr, self.text(etype, evalue, etb)
875 Term.cerr.flush()
876 Term.cerr.flush()
876
877
877 # Changed so an instance can just be called as VerboseTB_inst() and print
878 # Changed so an instance can just be called as VerboseTB_inst() and print
878 # out the right info on its own.
879 # out the right info on its own.
879 def __call__(self, etype=None, evalue=None, etb=None):
880 def __call__(self, etype=None, evalue=None, etb=None):
880 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
881 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
881 if etb is None:
882 if etb is None:
882 self.handler()
883 self.handler()
883 else:
884 else:
884 self.handler((etype, evalue, etb))
885 self.handler((etype, evalue, etb))
885 try:
886 try:
886 self.debugger()
887 self.debugger()
887 except KeyboardInterrupt:
888 except KeyboardInterrupt:
888 print "\nKeyboardInterrupt"
889 print "\nKeyboardInterrupt"
889
890
890 #----------------------------------------------------------------------------
891 #----------------------------------------------------------------------------
891 class FormattedTB(VerboseTB,ListTB):
892 class FormattedTB(VerboseTB,ListTB):
892 """Subclass ListTB but allow calling with a traceback.
893 """Subclass ListTB but allow calling with a traceback.
893
894
894 It can thus be used as a sys.excepthook for Python > 2.1.
895 It can thus be used as a sys.excepthook for Python > 2.1.
895
896
896 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
897 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
897
898
898 Allows a tb_offset to be specified. This is useful for situations where
899 Allows a tb_offset to be specified. This is useful for situations where
899 one needs to remove a number of topmost frames from the traceback (such as
900 one needs to remove a number of topmost frames from the traceback (such as
900 occurs with python programs that themselves execute other python code,
901 occurs with python programs that themselves execute other python code,
901 like Python shells). """
902 like Python shells). """
902
903
903 def __init__(self, mode = 'Plain', color_scheme='Linux',
904 def __init__(self, mode = 'Plain', color_scheme='Linux',
904 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
905 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
905
906
906 # NEVER change the order of this list. Put new modes at the end:
907 # NEVER change the order of this list. Put new modes at the end:
907 self.valid_modes = ['Plain','Context','Verbose']
908 self.valid_modes = ['Plain','Context','Verbose']
908 self.verbose_modes = self.valid_modes[1:3]
909 self.verbose_modes = self.valid_modes[1:3]
909
910
910 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
911 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
911 call_pdb=call_pdb,include_vars=include_vars)
912 call_pdb=call_pdb,include_vars=include_vars)
912 self.set_mode(mode)
913 self.set_mode(mode)
913
914
914 def _extract_tb(self,tb):
915 def _extract_tb(self,tb):
915 if tb:
916 if tb:
916 return traceback.extract_tb(tb)
917 return traceback.extract_tb(tb)
917 else:
918 else:
918 return None
919 return None
919
920
920 def text(self, etype, value, tb,context=5,mode=None):
921 def text(self, etype, value, tb,context=5,mode=None):
921 """Return formatted traceback.
922 """Return formatted traceback.
922
923
923 If the optional mode parameter is given, it overrides the current
924 If the optional mode parameter is given, it overrides the current
924 mode."""
925 mode."""
925
926
926 if mode is None:
927 if mode is None:
927 mode = self.mode
928 mode = self.mode
928 if mode in self.verbose_modes:
929 if mode in self.verbose_modes:
929 # verbose modes need a full traceback
930 # verbose modes need a full traceback
930 return VerboseTB.text(self,etype, value, tb,context=5)
931 return VerboseTB.text(self,etype, value, tb,context=5)
931 else:
932 else:
932 # We must check the source cache because otherwise we can print
933 # We must check the source cache because otherwise we can print
933 # out-of-date source code.
934 # out-of-date source code.
934 linecache.checkcache()
935 linecache.checkcache()
935 # Now we can extract and format the exception
936 # Now we can extract and format the exception
936 elist = self._extract_tb(tb)
937 elist = self._extract_tb(tb)
937 if len(elist) > self.tb_offset:
938 if len(elist) > self.tb_offset:
938 del elist[:self.tb_offset]
939 del elist[:self.tb_offset]
939 return ListTB.text(self,etype,value,elist)
940 return ListTB.text(self,etype,value,elist)
940
941
941 def set_mode(self,mode=None):
942 def set_mode(self,mode=None):
942 """Switch to the desired mode.
943 """Switch to the desired mode.
943
944
944 If mode is not specified, cycles through the available modes."""
945 If mode is not specified, cycles through the available modes."""
945
946
946 if not mode:
947 if not mode:
947 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
948 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
948 len(self.valid_modes)
949 len(self.valid_modes)
949 self.mode = self.valid_modes[new_idx]
950 self.mode = self.valid_modes[new_idx]
950 elif mode not in self.valid_modes:
951 elif mode not in self.valid_modes:
951 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
952 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
952 'Valid modes: '+str(self.valid_modes)
953 'Valid modes: '+str(self.valid_modes)
953 else:
954 else:
954 self.mode = mode
955 self.mode = mode
955 # include variable details only in 'Verbose' mode
956 # include variable details only in 'Verbose' mode
956 self.include_vars = (self.mode == self.valid_modes[2])
957 self.include_vars = (self.mode == self.valid_modes[2])
957
958
958 # some convenient shorcuts
959 # some convenient shorcuts
959 def plain(self):
960 def plain(self):
960 self.set_mode(self.valid_modes[0])
961 self.set_mode(self.valid_modes[0])
961
962
962 def context(self):
963 def context(self):
963 self.set_mode(self.valid_modes[1])
964 self.set_mode(self.valid_modes[1])
964
965
965 def verbose(self):
966 def verbose(self):
966 self.set_mode(self.valid_modes[2])
967 self.set_mode(self.valid_modes[2])
967
968
968 #----------------------------------------------------------------------------
969 #----------------------------------------------------------------------------
969 class AutoFormattedTB(FormattedTB):
970 class AutoFormattedTB(FormattedTB):
970 """A traceback printer which can be called on the fly.
971 """A traceback printer which can be called on the fly.
971
972
972 It will find out about exceptions by itself.
973 It will find out about exceptions by itself.
973
974
974 A brief example:
975 A brief example:
975
976
976 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
977 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
977 try:
978 try:
978 ...
979 ...
979 except:
980 except:
980 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
981 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
981 """
982 """
982 def __call__(self,etype=None,evalue=None,etb=None,
983 def __call__(self,etype=None,evalue=None,etb=None,
983 out=None,tb_offset=None):
984 out=None,tb_offset=None):
984 """Print out a formatted exception traceback.
985 """Print out a formatted exception traceback.
985
986
986 Optional arguments:
987 Optional arguments:
987 - out: an open file-like object to direct output to.
988 - out: an open file-like object to direct output to.
988
989
989 - tb_offset: the number of frames to skip over in the stack, on a
990 - tb_offset: the number of frames to skip over in the stack, on a
990 per-call basis (this overrides temporarily the instance's tb_offset
991 per-call basis (this overrides temporarily the instance's tb_offset
991 given at initialization time. """
992 given at initialization time. """
992
993
993 if out is None:
994 if out is None:
994 out = Term.cerr
995 out = Term.cerr
995 Term.cout.flush()
996 Term.cout.flush()
996 if tb_offset is not None:
997 if tb_offset is not None:
997 tb_offset, self.tb_offset = self.tb_offset, tb_offset
998 tb_offset, self.tb_offset = self.tb_offset, tb_offset
998 print >> out, self.text(etype, evalue, etb)
999 print >> out, self.text(etype, evalue, etb)
999 self.tb_offset = tb_offset
1000 self.tb_offset = tb_offset
1000 else:
1001 else:
1001 print >> out, self.text(etype, evalue, etb)
1002 print >> out, self.text(etype, evalue, etb)
1002 out.flush()
1003 out.flush()
1003 try:
1004 try:
1004 self.debugger()
1005 self.debugger()
1005 except KeyboardInterrupt:
1006 except KeyboardInterrupt:
1006 print "\nKeyboardInterrupt"
1007 print "\nKeyboardInterrupt"
1007
1008
1008 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1009 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1009 if etype is None:
1010 if etype is None:
1010 etype,value,tb = sys.exc_info()
1011 etype,value,tb = sys.exc_info()
1011 self.tb = tb
1012 self.tb = tb
1012 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1013 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1013
1014
1014 #---------------------------------------------------------------------------
1015 #---------------------------------------------------------------------------
1015 # A simple class to preserve Nathan's original functionality.
1016 # A simple class to preserve Nathan's original functionality.
1016 class ColorTB(FormattedTB):
1017 class ColorTB(FormattedTB):
1017 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1018 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1018 def __init__(self,color_scheme='Linux',call_pdb=0):
1019 def __init__(self,color_scheme='Linux',call_pdb=0):
1019 FormattedTB.__init__(self,color_scheme=color_scheme,
1020 FormattedTB.__init__(self,color_scheme=color_scheme,
1020 call_pdb=call_pdb)
1021 call_pdb=call_pdb)
1021
1022
1022 #----------------------------------------------------------------------------
1023 #----------------------------------------------------------------------------
1023 # module testing (minimal)
1024 # module testing (minimal)
1024 if __name__ == "__main__":
1025 if __name__ == "__main__":
1025 def spam(c, (d, e)):
1026 def spam(c, (d, e)):
1026 x = c + d
1027 x = c + d
1027 y = c * d
1028 y = c * d
1028 foo(x, y)
1029 foo(x, y)
1029
1030
1030 def foo(a, b, bar=1):
1031 def foo(a, b, bar=1):
1031 eggs(a, b + bar)
1032 eggs(a, b + bar)
1032
1033
1033 def eggs(f, g, z=globals()):
1034 def eggs(f, g, z=globals()):
1034 h = f + g
1035 h = f + g
1035 i = f - g
1036 i = f - g
1036 return h / i
1037 return h / i
1037
1038
1038 print ''
1039 print ''
1039 print '*** Before ***'
1040 print '*** Before ***'
1040 try:
1041 try:
1041 print spam(1, (2, 3))
1042 print spam(1, (2, 3))
1042 except:
1043 except:
1043 traceback.print_exc()
1044 traceback.print_exc()
1044 print ''
1045 print ''
1045
1046
1046 handler = ColorTB()
1047 handler = ColorTB()
1047 print '*** ColorTB ***'
1048 print '*** ColorTB ***'
1048 try:
1049 try:
1049 print spam(1, (2, 3))
1050 print spam(1, (2, 3))
1050 except:
1051 except:
1051 apply(handler, sys.exc_info() )
1052 apply(handler, sys.exc_info() )
1052 print ''
1053 print ''
1053
1054
1054 handler = VerboseTB()
1055 handler = VerboseTB()
1055 print '*** VerboseTB ***'
1056 print '*** VerboseTB ***'
1056 try:
1057 try:
1057 print spam(1, (2, 3))
1058 print spam(1, (2, 3))
1058 except:
1059 except:
1059 apply(handler, sys.exc_info() )
1060 apply(handler, sys.exc_info() )
1060 print ''
1061 print ''
1061
1062
@@ -1,179 +1,177 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
2 # -*- coding: utf-8 -*-
3 """Setup script for IPython.
3 """Setup script for IPython.
4
4
5 Under Posix environments it works like a typical setup.py script.
5 Under Posix environments it works like a typical setup.py script.
6 Under Windows, the command sdist is not supported, since IPython
6 Under Windows, the command sdist is not supported, since IPython
7 requires utilities which are not available under Windows."""
7 requires utilities which are not available under Windows."""
8
8
9 #-------------------------------------------------------------------------------
9 #-------------------------------------------------------------------------------
10 # Copyright (C) 2008 The IPython Development Team
10 # Copyright (C) 2008 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-------------------------------------------------------------------------------
14 #-------------------------------------------------------------------------------
15
15
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19
19
20 # Stdlib imports
20 # Stdlib imports
21 import os
21 import os
22 import sys
22 import sys
23
23
24 from glob import glob
24 from glob import glob
25
25
26 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
26 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
27 # update it when the contents of directories change.
27 # update it when the contents of directories change.
28 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
28 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
29
29
30 from distutils.core import setup
30 from distutils.core import setup
31
31
32 # Local imports
32 # Local imports
33 from IPython.genutils import target_update
33 from IPython.genutils import target_update
34
34
35 from setupbase import (
35 from setupbase import (
36 setup_args,
36 setup_args,
37 find_packages,
37 find_packages,
38 find_package_data,
38 find_package_data,
39 find_scripts,
39 find_scripts,
40 find_data_files,
40 find_data_files,
41 check_for_dependencies
41 check_for_dependencies
42 )
42 )
43
43
44 isfile = os.path.isfile
44 isfile = os.path.isfile
45
45
46 #-------------------------------------------------------------------------------
46 #-------------------------------------------------------------------------------
47 # Handle OS specific things
47 # Handle OS specific things
48 #-------------------------------------------------------------------------------
48 #-------------------------------------------------------------------------------
49
49
50 if os.name == 'posix':
50 if os.name == 'posix':
51 os_name = 'posix'
51 os_name = 'posix'
52 elif os.name in ['nt','dos']:
52 elif os.name in ['nt','dos']:
53 os_name = 'windows'
53 os_name = 'windows'
54 else:
54 else:
55 print 'Unsupported operating system:',os.name
55 print 'Unsupported operating system:',os.name
56 sys.exit(1)
56 sys.exit(1)
57
57
58 # Under Windows, 'sdist' has not been supported. Now that the docs build with
58 # Under Windows, 'sdist' has not been supported. Now that the docs build with
59 # Sphinx it might work, but let's not turn it on until someone confirms that it
59 # Sphinx it might work, but let's not turn it on until someone confirms that it
60 # actually works.
60 # actually works.
61 if os_name == 'windows' and 'sdist' in sys.argv:
61 if os_name == 'windows' and 'sdist' in sys.argv:
62 print 'The sdist command is not available under Windows. Exiting.'
62 print 'The sdist command is not available under Windows. Exiting.'
63 sys.exit(1)
63 sys.exit(1)
64
64
65 #-------------------------------------------------------------------------------
65 #-------------------------------------------------------------------------------
66 # Things related to the IPython documentation
66 # Things related to the IPython documentation
67 #-------------------------------------------------------------------------------
67 #-------------------------------------------------------------------------------
68
68
69 # update the manuals when building a source dist
69 # update the manuals when building a source dist
70 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
70 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
71 import textwrap
71 import textwrap
72
72
73 # List of things to be updated. Each entry is a triplet of args for
73 # List of things to be updated. Each entry is a triplet of args for
74 # target_update()
74 # target_update()
75 to_update = [
75 to_update = [
76 # FIXME - Disabled for now: we need to redo an automatic way
76 # FIXME - Disabled for now: we need to redo an automatic way
77 # of generating the magic info inside the rst.
77 # of generating the magic info inside the rst.
78 #('docs/magic.tex',
78 #('docs/magic.tex',
79 #['IPython/Magic.py'],
79 #['IPython/Magic.py'],
80 #"cd doc && ./update_magic.sh" ),
80 #"cd doc && ./update_magic.sh" ),
81
81
82 ('docs/man/ipython.1.gz',
82 ('docs/man/ipython.1.gz',
83 ['docs/man/ipython.1'],
83 ['docs/man/ipython.1'],
84 "cd docs/man && gzip -9c ipython.1 > ipython.1.gz"),
84 "cd docs/man && gzip -9c ipython.1 > ipython.1.gz"),
85
85
86 ('docs/man/pycolor.1.gz',
86 ('docs/man/pycolor.1.gz',
87 ['docs/man/pycolor.1'],
87 ['docs/man/pycolor.1'],
88 "cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz"),
88 "cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz"),
89 ]
89 ]
90
90
91 # Only build the docs is sphinx is present
91 # Only build the docs is sphinx is present
92 try:
92 try:
93 import sphinx
93 import sphinx
94 except ImportError:
94 except ImportError:
95 pass
95 pass
96 else:
96 else:
97 pass
97 pass
98 # BEG: This is disabled as I am not sure what to depend on.
98 # BEG: This is disabled as I am not sure what to depend on.
99 # I actually don't think we should be automatically building
99 # I actually don't think we should be automatically building
100 # the docs for people.
100 # the docs for people.
101 # The do_sphinx scripts builds html and pdf, so just one
101 # The do_sphinx scripts builds html and pdf, so just one
102 # target is enough to cover all manual generation
102 # target is enough to cover all manual generation
103 # to_update.append(
103 # to_update.append(
104 # ('docs/manual/ipython.pdf',
104 # ('docs/manual/ipython.pdf',
105 # ['IPython/Release.py','docs/source/ipython.rst'],
105 # ['IPython/Release.py','docs/source/ipython.rst'],
106 # "cd docs && python do_sphinx.py")
106 # "cd docs && python do_sphinx.py")
107 # )
107 # )
108
108
109 [ target_update(*t) for t in to_update ]
109 [ target_update(*t) for t in to_update ]
110
110
111 # Build the docs
111 # Build the docs
112 os.system('cd docs && make dist')
112 os.system('cd docs && make dist')
113
113
114 #---------------------------------------------------------------------------
114 #---------------------------------------------------------------------------
115 # Find all the packages, package data, scripts and data_files
115 # Find all the packages, package data, scripts and data_files
116 #---------------------------------------------------------------------------
116 #---------------------------------------------------------------------------
117
117
118 packages = find_packages()
118 packages = find_packages()
119 package_data = find_package_data()
119 package_data = find_package_data()
120 scripts = find_scripts()
120 scripts = find_scripts()
121 data_files = find_data_files()
121 data_files = find_data_files()
122
122
123 #---------------------------------------------------------------------------
123 #---------------------------------------------------------------------------
124 # Handle dependencies and setuptools specific things
124 # Handle dependencies and setuptools specific things
125 #---------------------------------------------------------------------------
125 #---------------------------------------------------------------------------
126
126
127 # This dict is used for passing extra arguments that are setuptools
127 # This dict is used for passing extra arguments that are setuptools
128 # specific to setup
128 # specific to setup
129 setuptools_extra_args = {}
129 setuptools_extra_args = {}
130
130
131 if 'setuptools' in sys.modules:
131 if 'setuptools' in sys.modules:
132 setuptools_extra_args['zip_safe'] = False
132 setuptools_extra_args['zip_safe'] = False
133 setuptools_extra_args['entry_points'] = {
133 setuptools_extra_args['entry_points'] = {
134 'console_scripts': [
134 'console_scripts': [
135 'ipython = IPython.ipapi:launch_new_instance',
135 'ipython = IPython.ipapi:launch_new_instance',
136 'pycolor = IPython.PyColorize:main',
136 'pycolor = IPython.PyColorize:main',
137 'ipcontroller = IPython.kernel.scripts.ipcontroller:main',
137 'ipcontroller = IPython.kernel.scripts.ipcontroller:main',
138 'ipengine = IPython.kernel.scripts.ipengine:main',
138 'ipengine = IPython.kernel.scripts.ipengine:main',
139 'ipcluster = IPython.kernel.scripts.ipcluster:main',
139 'ipcluster = IPython.kernel.scripts.ipcluster:main',
140 'ipythonx = IPython.frontend.wx.ipythonx:main'
140 'ipythonx = IPython.frontend.wx.ipythonx:main'
141 ]
141 ]
142 }
142 }
143 setup_args["extras_require"] = dict(
143 setup_args["extras_require"] = dict(
144 kernel = [
144 kernel = [
145 "zope.interface>=3.4.1",
145 "zope.interface>=3.4.1",
146 "Twisted>=8.0.1",
146 "Twisted>=8.0.1",
147 "foolscap>=0.2.6"
147 "foolscap>=0.2.6"
148 ],
148 ],
149 doc=['Sphinx>=0.3','pygments'],
149 doc=['Sphinx>=0.3','pygments'],
150 test='nose>=0.10.1',
150 test='nose>=0.10.1',
151 security=["pyOpenSSL>=0.6"]
151 security=["pyOpenSSL>=0.6"]
152 )
152 )
153 # Allow setuptools to handle the scripts
153 # Allow setuptools to handle the scripts
154 scripts = []
154 scripts = []
155 # eggs will lack docs, examples
156 data_files = []
157 else:
155 else:
158 # package_data of setuptools was introduced to distutils in 2.4
156 # package_data of setuptools was introduced to distutils in 2.4
159 cfgfiles = filter(isfile, glob('IPython/UserConfig/*'))
157 cfgfiles = filter(isfile, glob('IPython/UserConfig/*'))
160 if sys.version_info < (2,4):
158 if sys.version_info < (2,4):
161 data_files.append(('lib', 'IPython/UserConfig', cfgfiles))
159 data_files.append(('lib', 'IPython/UserConfig', cfgfiles))
162 # If we are running without setuptools, call this function which will
160 # If we are running without setuptools, call this function which will
163 # check for dependencies an inform the user what is needed. This is
161 # check for dependencies an inform the user what is needed. This is
164 # just to make life easy for users.
162 # just to make life easy for users.
165 check_for_dependencies()
163 check_for_dependencies()
166
164
167
165
168 #---------------------------------------------------------------------------
166 #---------------------------------------------------------------------------
169 # Do the actual setup now
167 # Do the actual setup now
170 #---------------------------------------------------------------------------
168 #---------------------------------------------------------------------------
171
169
172 setup_args['packages'] = packages
170 setup_args['packages'] = packages
173 setup_args['package_data'] = package_data
171 setup_args['package_data'] = package_data
174 setup_args['scripts'] = scripts
172 setup_args['scripts'] = scripts
175 setup_args['data_files'] = data_files
173 setup_args['data_files'] = data_files
176 setup_args.update(setuptools_extra_args)
174 setup_args.update(setuptools_extra_args)
177
175
178 if __name__ == '__main__':
176 if __name__ == '__main__':
179 setup(**setup_args)
177 setup(**setup_args)
@@ -1,275 +1,276 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """
3 """
4 This module defines the things that are used in setup.py for building IPython
4 This module defines the things that are used in setup.py for building IPython
5
5
6 This includes:
6 This includes:
7
7
8 * The basic arguments to setup
8 * The basic arguments to setup
9 * Functions for finding things like packages, package data, etc.
9 * Functions for finding things like packages, package data, etc.
10 * A function for checking dependencies.
10 * A function for checking dependencies.
11 """
11 """
12
12
13 __docformat__ = "restructuredtext en"
13 __docformat__ = "restructuredtext en"
14
14
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16 # Copyright (C) 2008 The IPython Development Team
16 # Copyright (C) 2008 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21
21
22 #-------------------------------------------------------------------------------
22 #-------------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-------------------------------------------------------------------------------
24 #-------------------------------------------------------------------------------
25
25
26 import os, sys
26 import os, sys
27
27
28 from glob import glob
28 from glob import glob
29
29
30 from setupext import install_data_ext
30 from setupext import install_data_ext
31
31
32 #-------------------------------------------------------------------------------
32 #-------------------------------------------------------------------------------
33 # Useful globals and utility functions
33 # Useful globals and utility functions
34 #-------------------------------------------------------------------------------
34 #-------------------------------------------------------------------------------
35
35
36 # A few handy globals
36 # A few handy globals
37 isfile = os.path.isfile
37 isfile = os.path.isfile
38 pjoin = os.path.join
38 pjoin = os.path.join
39
39
40 def oscmd(s):
40 def oscmd(s):
41 print ">", s
41 print ">", s
42 os.system(s)
42 os.system(s)
43
43
44 # A little utility we'll need below, since glob() does NOT allow you to do
44 # A little utility we'll need below, since glob() does NOT allow you to do
45 # exclusion on multiple endings!
45 # exclusion on multiple endings!
46 def file_doesnt_endwith(test,endings):
46 def file_doesnt_endwith(test,endings):
47 """Return true if test is a file and its name does NOT end with any
47 """Return true if test is a file and its name does NOT end with any
48 of the strings listed in endings."""
48 of the strings listed in endings."""
49 if not isfile(test):
49 if not isfile(test):
50 return False
50 return False
51 for e in endings:
51 for e in endings:
52 if test.endswith(e):
52 if test.endswith(e):
53 return False
53 return False
54 return True
54 return True
55
55
56 #---------------------------------------------------------------------------
56 #---------------------------------------------------------------------------
57 # Basic project information
57 # Basic project information
58 #---------------------------------------------------------------------------
58 #---------------------------------------------------------------------------
59
59
60 # Release.py contains version, authors, license, url, keywords, etc.
60 # Release.py contains version, authors, license, url, keywords, etc.
61 execfile(pjoin('IPython','Release.py'))
61 execfile(pjoin('IPython','Release.py'))
62
62
63 # Create a dict with the basic information
63 # Create a dict with the basic information
64 # This dict is eventually passed to setup after additional keys are added.
64 # This dict is eventually passed to setup after additional keys are added.
65 setup_args = dict(
65 setup_args = dict(
66 name = name,
66 name = name,
67 version = version,
67 version = version,
68 description = description,
68 description = description,
69 long_description = long_description,
69 long_description = long_description,
70 author = author,
70 author = author,
71 author_email = author_email,
71 author_email = author_email,
72 url = url,
72 url = url,
73 download_url = download_url,
73 download_url = download_url,
74 license = license,
74 license = license,
75 platforms = platforms,
75 platforms = platforms,
76 keywords = keywords,
76 keywords = keywords,
77 cmdclass = {'install_data': install_data_ext},
77 cmdclass = {'install_data': install_data_ext},
78 )
78 )
79
79
80
80
81 #---------------------------------------------------------------------------
81 #---------------------------------------------------------------------------
82 # Find packages
82 # Find packages
83 #---------------------------------------------------------------------------
83 #---------------------------------------------------------------------------
84
84
85 def add_package(packages,pname,config=False,tests=False,scripts=False,
85 def add_package(packages,pname,config=False,tests=False,scripts=False,
86 others=None):
86 others=None):
87 """
87 """
88 Add a package to the list of packages, including certain subpackages.
88 Add a package to the list of packages, including certain subpackages.
89 """
89 """
90 packages.append('.'.join(['IPython',pname]))
90 packages.append('.'.join(['IPython',pname]))
91 if config:
91 if config:
92 packages.append('.'.join(['IPython',pname,'config']))
92 packages.append('.'.join(['IPython',pname,'config']))
93 if tests:
93 if tests:
94 packages.append('.'.join(['IPython',pname,'tests']))
94 packages.append('.'.join(['IPython',pname,'tests']))
95 if scripts:
95 if scripts:
96 packages.append('.'.join(['IPython',pname,'scripts']))
96 packages.append('.'.join(['IPython',pname,'scripts']))
97 if others is not None:
97 if others is not None:
98 for o in others:
98 for o in others:
99 packages.append('.'.join(['IPython',pname,o]))
99 packages.append('.'.join(['IPython',pname,o]))
100
100
101 def find_packages():
101 def find_packages():
102 """
102 """
103 Find all of IPython's packages.
103 Find all of IPython's packages.
104 """
104 """
105 packages = ['IPython']
105 packages = ['IPython']
106 add_package(packages, 'config', tests=True)
106 add_package(packages, 'config', tests=True)
107 add_package(packages , 'Extensions')
107 add_package(packages , 'Extensions')
108 add_package(packages, 'external')
108 add_package(packages, 'external')
109 add_package(packages, 'gui')
109 add_package(packages, 'gui')
110 add_package(packages, 'gui.wx')
110 add_package(packages, 'gui.wx')
111 add_package(packages, 'frontend', tests=True)
111 add_package(packages, 'frontend', tests=True)
112 add_package(packages, 'frontend._process')
112 add_package(packages, 'frontend._process')
113 add_package(packages, 'frontend.wx')
113 add_package(packages, 'frontend.wx')
114 add_package(packages, 'frontend.cocoa', tests=True)
114 add_package(packages, 'frontend.cocoa', tests=True)
115 add_package(packages, 'kernel', config=True, tests=True, scripts=True)
115 add_package(packages, 'kernel', config=True, tests=True, scripts=True)
116 add_package(packages, 'kernel.core', config=True, tests=True)
116 add_package(packages, 'kernel.core', config=True, tests=True)
117 add_package(packages, 'testing', tests=True)
117 add_package(packages, 'testing', tests=True)
118 add_package(packages, 'tools', tests=True)
118 add_package(packages, 'tools', tests=True)
119 add_package(packages, 'UserConfig')
119 add_package(packages, 'UserConfig')
120 return packages
120 return packages
121
121
122 #---------------------------------------------------------------------------
122 #---------------------------------------------------------------------------
123 # Find package data
123 # Find package data
124 #---------------------------------------------------------------------------
124 #---------------------------------------------------------------------------
125
125
126 def find_package_data():
126 def find_package_data():
127 """
127 """
128 Find IPython's package_data.
128 Find IPython's package_data.
129 """
129 """
130 # This is not enough for these things to appear in an sdist.
130 # This is not enough for these things to appear in an sdist.
131 # We need to muck with the MANIFEST to get this to work
131 # We need to muck with the MANIFEST to get this to work
132 package_data = {
132 package_data = {
133 'IPython.UserConfig' : ['*'],
133 'IPython.UserConfig' : ['*'],
134 'IPython.tools.tests' : ['*.txt'],
134 'IPython.tools.tests' : ['*.txt'],
135 'IPython.testing' : ['*.txt']
135 'IPython.testing' : ['*.txt']
136 }
136 }
137 return package_data
137 return package_data
138
138
139
139
140 #---------------------------------------------------------------------------
140 #---------------------------------------------------------------------------
141 # Find data files
141 # Find data files
142 #---------------------------------------------------------------------------
142 #---------------------------------------------------------------------------
143
143
144 def make_dir_struct(tag,base,out_base):
144 def make_dir_struct(tag,base,out_base):
145 """Make the directory structure of all files below a starting dir.
145 """Make the directory structure of all files below a starting dir.
146
146
147 This is just a convenience routine to help build a nested directory
147 This is just a convenience routine to help build a nested directory
148 hierarchy because distutils is too stupid to do this by itself.
148 hierarchy because distutils is too stupid to do this by itself.
149
149
150 XXX - this needs a proper docstring!
150 XXX - this needs a proper docstring!
151 """
151 """
152
152
153 # we'll use these a lot below
153 # we'll use these a lot below
154 lbase = len(base)
154 lbase = len(base)
155 pathsep = os.path.sep
155 pathsep = os.path.sep
156 lpathsep = len(pathsep)
156 lpathsep = len(pathsep)
157
157
158 out = []
158 out = []
159 for (dirpath,dirnames,filenames) in os.walk(base):
159 for (dirpath,dirnames,filenames) in os.walk(base):
160 # we need to strip out the dirpath from the base to map it to the
160 # we need to strip out the dirpath from the base to map it to the
161 # output (installation) path. This requires possibly stripping the
161 # output (installation) path. This requires possibly stripping the
162 # path separator, because otherwise pjoin will not work correctly
162 # path separator, because otherwise pjoin will not work correctly
163 # (pjoin('foo/','/bar') returns '/bar').
163 # (pjoin('foo/','/bar') returns '/bar').
164
164
165 dp_eff = dirpath[lbase:]
165 dp_eff = dirpath[lbase:]
166 if dp_eff.startswith(pathsep):
166 if dp_eff.startswith(pathsep):
167 dp_eff = dp_eff[lpathsep:]
167 dp_eff = dp_eff[lpathsep:]
168 # The output path must be anchored at the out_base marker
168 # The output path must be anchored at the out_base marker
169 out_path = pjoin(out_base,dp_eff)
169 out_path = pjoin(out_base,dp_eff)
170 # Now we can generate the final filenames. Since os.walk only produces
170 # Now we can generate the final filenames. Since os.walk only produces
171 # filenames, we must join back with the dirpath to get full valid file
171 # filenames, we must join back with the dirpath to get full valid file
172 # paths:
172 # paths:
173 pfiles = [pjoin(dirpath,f) for f in filenames]
173 pfiles = [pjoin(dirpath,f) for f in filenames]
174 # Finally, generate the entry we need, which is a triple of (tag,output
174 # Finally, generate the entry we need, which is a triple of (tag,output
175 # path, files) for use as a data_files parameter in install_data.
175 # path, files) for use as a data_files parameter in install_data.
176 out.append((tag,out_path,pfiles))
176 out.append((tag,out_path,pfiles))
177
177
178 return out
178 return out
179
179
180
180
181 def find_data_files():
181 def find_data_files():
182 """
182 """
183 Find IPython's data_files.
183 Find IPython's data_files.
184
184
185 Most of these are docs.
185 Most of these are docs.
186 """
186 """
187
187
188 docdirbase = 'share/doc/ipython'
188 docdirbase = 'share/doc/ipython'
189 manpagebase = 'share/man/man1'
189 manpagebase = 'share/man/man1'
190
190
191 # Simple file lists can be made by hand
191 # Simple file lists can be made by hand
192 manpages = filter(isfile, glob('docs/man/*.1.gz'))
192 manpages = filter(isfile, glob('docs/man/*.1.gz'))
193 igridhelpfiles = filter(isfile, glob('IPython/Extensions/igrid_help.*'))
193 igridhelpfiles = filter(isfile, glob('IPython/Extensions/igrid_help.*'))
194
194
195 # For nested structures, use the utility above
195 # For nested structures, use the utility above
196 example_files = make_dir_struct('data','docs/examples',
196 example_files = make_dir_struct('data','docs/examples',
197 pjoin(docdirbase,'examples'))
197 pjoin(docdirbase,'examples'))
198 manual_files = make_dir_struct('data','docs/dist',pjoin(docdirbase,'manual'))
198 manual_files = make_dir_struct('data','docs/dist',pjoin(docdirbase,'manual'))
199
199
200 # And assemble the entire output list
200 # And assemble the entire output list
201 data_files = [ ('data',manpagebase, manpages),
201 data_files = [ ('data',manpagebase, manpages),
202 ('data',pjoin(docdirbase,'extensions'),igridhelpfiles),
202 ('data',pjoin(docdirbase,'extensions'),igridhelpfiles),
203 ] + manual_files + example_files
203 ] + manual_files + example_files
204
204
205 ## import pprint # dbg
205 ## import pprint # dbg
206 ## print '*'*80
206 ## print '*'*80
207 ## print 'data files'
207 ## print 'data files'
208 ## pprint.pprint(data_files)
208 ## pprint.pprint(data_files)
209 ## print '*'*80
209 ## print '*'*80
210
210
211 return data_files
211 return data_files
212
212
213 #---------------------------------------------------------------------------
213 #---------------------------------------------------------------------------
214 # Find scripts
214 # Find scripts
215 #---------------------------------------------------------------------------
215 #---------------------------------------------------------------------------
216
216
217 def find_scripts():
217 def find_scripts():
218 """
218 """
219 Find IPython's scripts.
219 Find IPython's scripts.
220 """
220 """
221 scripts = ['IPython/kernel/scripts/ipengine',
221 scripts = ['IPython/kernel/scripts/ipengine',
222 'IPython/kernel/scripts/ipcontroller',
222 'IPython/kernel/scripts/ipcontroller',
223 'IPython/kernel/scripts/ipcluster',
223 'IPython/kernel/scripts/ipcluster',
224 'scripts/ipython',
224 'scripts/ipython',
225 'scripts/ipythonx',
225 'scripts/ipythonx',
226 'scripts/pycolor',
226 'scripts/pycolor',
227 'scripts/irunner',
227 'scripts/irunner',
228 'scripts/iptest',
228 ]
229 ]
229
230
230 # Script to be run by the windows binary installer after the default setup
231 # Script to be run by the windows binary installer after the default setup
231 # routine, to add shortcuts and similar windows-only things. Windows
232 # routine, to add shortcuts and similar windows-only things. Windows
232 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
233 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
233 # doesn't find them.
234 # doesn't find them.
234 if 'bdist_wininst' in sys.argv:
235 if 'bdist_wininst' in sys.argv:
235 if len(sys.argv) > 2 and ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
236 if len(sys.argv) > 2 and ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
236 print >> sys.stderr,"ERROR: bdist_wininst must be run alone. Exiting."
237 print >> sys.stderr,"ERROR: bdist_wininst must be run alone. Exiting."
237 sys.exit(1)
238 sys.exit(1)
238 scripts.append('scripts/ipython_win_post_install.py')
239 scripts.append('scripts/ipython_win_post_install.py')
239
240
240 return scripts
241 return scripts
241
242
242 #---------------------------------------------------------------------------
243 #---------------------------------------------------------------------------
243 # Verify all dependencies
244 # Verify all dependencies
244 #---------------------------------------------------------------------------
245 #---------------------------------------------------------------------------
245
246
246 def check_for_dependencies():
247 def check_for_dependencies():
247 """Check for IPython's dependencies.
248 """Check for IPython's dependencies.
248
249
249 This function should NOT be called if running under setuptools!
250 This function should NOT be called if running under setuptools!
250 """
251 """
251 from setupext.setupext import (
252 from setupext.setupext import (
252 print_line, print_raw, print_status, print_message,
253 print_line, print_raw, print_status, print_message,
253 check_for_zopeinterface, check_for_twisted,
254 check_for_zopeinterface, check_for_twisted,
254 check_for_foolscap, check_for_pyopenssl,
255 check_for_foolscap, check_for_pyopenssl,
255 check_for_sphinx, check_for_pygments,
256 check_for_sphinx, check_for_pygments,
256 check_for_nose, check_for_pexpect
257 check_for_nose, check_for_pexpect
257 )
258 )
258 print_line()
259 print_line()
259 print_raw("BUILDING IPYTHON")
260 print_raw("BUILDING IPYTHON")
260 print_status('python', sys.version)
261 print_status('python', sys.version)
261 print_status('platform', sys.platform)
262 print_status('platform', sys.platform)
262 if sys.platform == 'win32':
263 if sys.platform == 'win32':
263 print_status('Windows version', sys.getwindowsversion())
264 print_status('Windows version', sys.getwindowsversion())
264
265
265 print_raw("")
266 print_raw("")
266 print_raw("OPTIONAL DEPENDENCIES")
267 print_raw("OPTIONAL DEPENDENCIES")
267
268
268 check_for_zopeinterface()
269 check_for_zopeinterface()
269 check_for_twisted()
270 check_for_twisted()
270 check_for_foolscap()
271 check_for_foolscap()
271 check_for_pyopenssl()
272 check_for_pyopenssl()
272 check_for_sphinx()
273 check_for_sphinx()
273 check_for_pygments()
274 check_for_pygments()
274 check_for_nose()
275 check_for_nose()
275 check_for_pexpect()
276 check_for_pexpect()
General Comments 0
You need to be logged in to leave comments. Login now