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