##// END OF EJS Templates
Introduce some classes necessary fro Pygments refactor.
Matthias Bussonnier -
Show More
@@ -0,0 +1,26 b''
1 #*****************************************************************************
2 # Copyright (C) 2016 The IPython Team <ipython-dev@scipy.org>
3 #
4 # Distributed under the terms of the BSD License. The full license is in
5 # the file COPYING, distributed as part of this software.
6 #*****************************************************************************
7 from __future__ import absolute_import
8
9 """
10 Color managing related utilities
11 """
12
13 import pygments
14
15 from traitlets.config import Configurable
16 from traitlets import Unicode
17
18
19 available_themes = lambda : [s for s in pygments.styles.get_all_styles()]+['NoColor','LightBG','Linux']
20
21 class Colorable(Configurable):
22 """
23 A subclass of configurable for all the classes that have a `default_scheme`
24 """
25 default_style=Unicode('lightbg', config=True)
26
@@ -1,921 +1,924 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tools for inspecting Python objects.
3 3
4 4 Uses syntax highlighting for presenting the various information elements.
5 5
6 6 Similar in spirit to the inspect module, but all calls take a name argument to
7 7 reference the name under which an object is being read.
8 8 """
9 9
10 10 # Copyright (c) IPython Development Team.
11 11 # Distributed under the terms of the Modified BSD License.
12 12
13 13 from __future__ import print_function
14 14
15 15 __all__ = ['Inspector','InspectColors']
16 16
17 17 # stdlib modules
18 18 import inspect
19 19 import linecache
20 20 import os
21 21 from textwrap import dedent
22 22 import types
23 23 import io as stdlib_io
24 24
25 25 try:
26 26 from itertools import izip_longest
27 27 except ImportError:
28 28 from itertools import zip_longest as izip_longest
29 29
30 30 # IPython's own
31 31 from IPython.core import page
32 32 from IPython.lib.pretty import pretty
33 33 from IPython.testing.skipdoctest import skip_doctest_py3
34 34 from IPython.utils import PyColorize
35 35 from IPython.utils import io
36 36 from IPython.utils import openpy
37 37 from IPython.utils import py3compat
38 38 from IPython.utils.dir2 import safe_hasattr
39 39 from IPython.utils.path import compress_user
40 40 from IPython.utils.text import indent
41 41 from IPython.utils.wildcard import list_namespace
42 42 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
43 43 from IPython.utils.py3compat import cast_unicode, string_types, PY3
44 44 from IPython.utils.signatures import signature
45 from IPython.utils.colorable import Colorable
45 46
46 47 # builtin docstrings to ignore
47 48 _func_call_docstring = types.FunctionType.__call__.__doc__
48 49 _object_init_docstring = object.__init__.__doc__
49 50 _builtin_type_docstrings = {
50 51 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
51 52 types.FunctionType, property)
52 53 }
53 54
54 55 _builtin_func_type = type(all)
55 56 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
56 57 #****************************************************************************
57 58 # Builtin color schemes
58 59
59 60 Colors = TermColors # just a shorthand
60 61
61 62 InspectColors = PyColorize.ANSICodeColors
62 63
63 64 #****************************************************************************
64 65 # Auxiliary functions and objects
65 66
66 67 # See the messaging spec for the definition of all these fields. This list
67 68 # effectively defines the order of display
68 69 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
69 70 'length', 'file', 'definition', 'docstring', 'source',
70 71 'init_definition', 'class_docstring', 'init_docstring',
71 72 'call_def', 'call_docstring',
72 73 # These won't be printed but will be used to determine how to
73 74 # format the object
74 75 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
75 76 ]
76 77
77 78
78 79 def object_info(**kw):
79 80 """Make an object info dict with all fields present."""
80 81 infodict = dict(izip_longest(info_fields, [None]))
81 82 infodict.update(kw)
82 83 return infodict
83 84
84 85
85 86 def get_encoding(obj):
86 87 """Get encoding for python source file defining obj
87 88
88 89 Returns None if obj is not defined in a sourcefile.
89 90 """
90 91 ofile = find_file(obj)
91 92 # run contents of file through pager starting at line where the object
92 93 # is defined, as long as the file isn't binary and is actually on the
93 94 # filesystem.
94 95 if ofile is None:
95 96 return None
96 97 elif ofile.endswith(('.so', '.dll', '.pyd')):
97 98 return None
98 99 elif not os.path.isfile(ofile):
99 100 return None
100 101 else:
101 102 # Print only text files, not extension binaries. Note that
102 103 # getsourcelines returns lineno with 1-offset and page() uses
103 104 # 0-offset, so we must adjust.
104 105 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
105 106 encoding, lines = openpy.detect_encoding(buffer.readline)
106 107 return encoding
107 108
108 109 def getdoc(obj):
109 110 """Stable wrapper around inspect.getdoc.
110 111
111 112 This can't crash because of attribute problems.
112 113
113 114 It also attempts to call a getdoc() method on the given object. This
114 115 allows objects which provide their docstrings via non-standard mechanisms
115 116 (like Pyro proxies) to still be inspected by ipython's ? system."""
116 117 # Allow objects to offer customized documentation via a getdoc method:
117 118 try:
118 119 ds = obj.getdoc()
119 120 except Exception:
120 121 pass
121 122 else:
122 123 # if we get extra info, we add it to the normal docstring.
123 124 if isinstance(ds, string_types):
124 125 return inspect.cleandoc(ds)
125 126
126 127 try:
127 128 docstr = inspect.getdoc(obj)
128 129 encoding = get_encoding(obj)
129 130 return py3compat.cast_unicode(docstr, encoding=encoding)
130 131 except Exception:
131 132 # Harden against an inspect failure, which can occur with
132 133 # SWIG-wrapped extensions.
133 134 raise
134 135 return None
135 136
136 137
137 138 def getsource(obj, oname=''):
138 139 """Wrapper around inspect.getsource.
139 140
140 141 This can be modified by other projects to provide customized source
141 142 extraction.
142 143
143 144 Parameters
144 145 ----------
145 146 obj : object
146 147 an object whose source code we will attempt to extract
147 148 oname : str
148 149 (optional) a name under which the object is known
149 150
150 151 Returns
151 152 -------
152 153 src : unicode or None
153 154
154 155 """
155 156
156 157 if isinstance(obj, property):
157 158 sources = []
158 159 for attrname in ['fget', 'fset', 'fdel']:
159 160 fn = getattr(obj, attrname)
160 161 if fn is not None:
161 162 encoding = get_encoding(fn)
162 163 oname_prefix = ('%s.' % oname) if oname else ''
163 164 sources.append(cast_unicode(
164 165 ''.join(('# ', oname_prefix, attrname)),
165 166 encoding=encoding))
166 167 if inspect.isfunction(fn):
167 168 sources.append(dedent(getsource(fn)))
168 169 else:
169 170 # Default str/repr only prints function name,
170 171 # pretty.pretty prints module name too.
171 172 sources.append(cast_unicode(
172 173 '%s%s = %s\n' % (
173 174 oname_prefix, attrname, pretty(fn)),
174 175 encoding=encoding))
175 176 if sources:
176 177 return '\n'.join(sources)
177 178 else:
178 179 return None
179 180
180 181 else:
181 182 # Get source for non-property objects.
182 183
183 184 obj = _get_wrapped(obj)
184 185
185 186 try:
186 187 src = inspect.getsource(obj)
187 188 except TypeError:
188 189 # The object itself provided no meaningful source, try looking for
189 190 # its class definition instead.
190 191 if hasattr(obj, '__class__'):
191 192 try:
192 193 src = inspect.getsource(obj.__class__)
193 194 except TypeError:
194 195 return None
195 196
196 197 encoding = get_encoding(obj)
197 198 return cast_unicode(src, encoding=encoding)
198 199
199 200
200 201 def is_simple_callable(obj):
201 202 """True if obj is a function ()"""
202 203 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
203 204 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
204 205
205 206
206 207 def getargspec(obj):
207 208 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
208 209 :func:inspect.getargspec` on Python 2.
209 210
210 211 In addition to functions and methods, this can also handle objects with a
211 212 ``__call__`` attribute.
212 213 """
213 214 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
214 215 obj = obj.__call__
215 216
216 217 return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
217 218
218 219
219 220 def format_argspec(argspec):
220 221 """Format argspect, convenience wrapper around inspect's.
221 222
222 223 This takes a dict instead of ordered arguments and calls
223 224 inspect.format_argspec with the arguments in the necessary order.
224 225 """
225 226 return inspect.formatargspec(argspec['args'], argspec['varargs'],
226 227 argspec['varkw'], argspec['defaults'])
227 228
228 229
229 230 def call_tip(oinfo, format_call=True):
230 231 """Extract call tip data from an oinfo dict.
231 232
232 233 Parameters
233 234 ----------
234 235 oinfo : dict
235 236
236 237 format_call : bool, optional
237 238 If True, the call line is formatted and returned as a string. If not, a
238 239 tuple of (name, argspec) is returned.
239 240
240 241 Returns
241 242 -------
242 243 call_info : None, str or (str, dict) tuple.
243 244 When format_call is True, the whole call information is formattted as a
244 245 single string. Otherwise, the object's name and its argspec dict are
245 246 returned. If no call information is available, None is returned.
246 247
247 248 docstring : str or None
248 249 The most relevant docstring for calling purposes is returned, if
249 250 available. The priority is: call docstring for callable instances, then
250 251 constructor docstring for classes, then main object's docstring otherwise
251 252 (regular functions).
252 253 """
253 254 # Get call definition
254 255 argspec = oinfo.get('argspec')
255 256 if argspec is None:
256 257 call_line = None
257 258 else:
258 259 # Callable objects will have 'self' as their first argument, prune
259 260 # it out if it's there for clarity (since users do *not* pass an
260 261 # extra first argument explicitly).
261 262 try:
262 263 has_self = argspec['args'][0] == 'self'
263 264 except (KeyError, IndexError):
264 265 pass
265 266 else:
266 267 if has_self:
267 268 argspec['args'] = argspec['args'][1:]
268 269
269 270 call_line = oinfo['name']+format_argspec(argspec)
270 271
271 272 # Now get docstring.
272 273 # The priority is: call docstring, constructor docstring, main one.
273 274 doc = oinfo.get('call_docstring')
274 275 if doc is None:
275 276 doc = oinfo.get('init_docstring')
276 277 if doc is None:
277 278 doc = oinfo.get('docstring','')
278 279
279 280 return call_line, doc
280 281
281 282
282 283 def _get_wrapped(obj):
283 284 """Get the original object if wrapped in one or more @decorators
284 285
285 286 Some objects automatically construct similar objects on any unrecognised
286 287 attribute access (e.g. unittest.mock.call). To protect against infinite loops,
287 288 this will arbitrarily cut off after 100 levels of obj.__wrapped__
288 289 attribute access. --TK, Jan 2016
289 290 """
290 291 orig_obj = obj
291 292 i = 0
292 293 while safe_hasattr(obj, '__wrapped__'):
293 294 obj = obj.__wrapped__
294 295 i += 1
295 296 if i > 100:
296 297 # __wrapped__ is probably a lie, so return the thing we started with
297 298 return orig_obj
298 299 return obj
299 300
300 301 def find_file(obj):
301 302 """Find the absolute path to the file where an object was defined.
302 303
303 304 This is essentially a robust wrapper around `inspect.getabsfile`.
304 305
305 306 Returns None if no file can be found.
306 307
307 308 Parameters
308 309 ----------
309 310 obj : any Python object
310 311
311 312 Returns
312 313 -------
313 314 fname : str
314 315 The absolute path to the file where the object was defined.
315 316 """
316 317 obj = _get_wrapped(obj)
317 318
318 319 fname = None
319 320 try:
320 321 fname = inspect.getabsfile(obj)
321 322 except TypeError:
322 323 # For an instance, the file that matters is where its class was
323 324 # declared.
324 325 if hasattr(obj, '__class__'):
325 326 try:
326 327 fname = inspect.getabsfile(obj.__class__)
327 328 except TypeError:
328 329 # Can happen for builtins
329 330 pass
330 331 except:
331 332 pass
332 333 return cast_unicode(fname)
333 334
334 335
335 336 def find_source_lines(obj):
336 337 """Find the line number in a file where an object was defined.
337 338
338 339 This is essentially a robust wrapper around `inspect.getsourcelines`.
339 340
340 341 Returns None if no file can be found.
341 342
342 343 Parameters
343 344 ----------
344 345 obj : any Python object
345 346
346 347 Returns
347 348 -------
348 349 lineno : int
349 350 The line number where the object definition starts.
350 351 """
351 352 obj = _get_wrapped(obj)
352 353
353 354 try:
354 355 try:
355 356 lineno = inspect.getsourcelines(obj)[1]
356 357 except TypeError:
357 358 # For instances, try the class object like getsource() does
358 359 if hasattr(obj, '__class__'):
359 360 lineno = inspect.getsourcelines(obj.__class__)[1]
360 361 else:
361 362 lineno = None
362 363 except:
363 364 return None
364 365
365 366 return lineno
366 367
367 368
368 class Inspector:
369 class Inspector(Colorable):
369 370 def __init__(self, color_table=InspectColors,
370 371 code_color_table=PyColorize.ANSICodeColors,
371 372 scheme='NoColor',
372 str_detail_level=0):
373 str_detail_level=0,
374 parent=None, config=None):
375 super(Inspector, self).__init__(parent=parent, config=config)
373 376 self.color_table = color_table
374 self.parser = PyColorize.Parser(code_color_table,out='str')
377 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
375 378 self.format = self.parser.format
376 379 self.str_detail_level = str_detail_level
377 380 self.set_active_scheme(scheme)
378 381
379 382 def _getdef(self,obj,oname=''):
380 383 """Return the call signature for any callable object.
381 384
382 385 If any exception is generated, None is returned instead and the
383 386 exception is suppressed."""
384 387 try:
385 388 hdef = oname + str(signature(obj))
386 389 return cast_unicode(hdef)
387 390 except:
388 391 return None
389 392
390 393 def __head(self,h):
391 394 """Return a header string with proper colors."""
392 395 return '%s%s%s' % (self.color_table.active_colors.header,h,
393 396 self.color_table.active_colors.normal)
394 397
395 398 def set_active_scheme(self, scheme):
396 399 self.color_table.set_active_scheme(scheme)
397 400 self.parser.color_table.set_active_scheme(scheme)
398 401
399 402 def noinfo(self, msg, oname):
400 403 """Generic message when no information is found."""
401 404 print('No %s found' % msg, end=' ')
402 405 if oname:
403 406 print('for %s' % oname)
404 407 else:
405 408 print()
406 409
407 410 def pdef(self, obj, oname=''):
408 411 """Print the call signature for any callable object.
409 412
410 413 If the object is a class, print the constructor information."""
411 414
412 415 if not callable(obj):
413 416 print('Object is not callable.')
414 417 return
415 418
416 419 header = ''
417 420
418 421 if inspect.isclass(obj):
419 422 header = self.__head('Class constructor information:\n')
420 423 obj = obj.__init__
421 424 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
422 425 obj = obj.__call__
423 426
424 427 output = self._getdef(obj,oname)
425 428 if output is None:
426 429 self.noinfo('definition header',oname)
427 430 else:
428 431 print(header,self.format(output), end=' ', file=io.stdout)
429 432
430 433 # In Python 3, all classes are new-style, so they all have __init__.
431 434 @skip_doctest_py3
432 435 def pdoc(self,obj,oname='',formatter = None):
433 436 """Print the docstring for any object.
434 437
435 438 Optional:
436 439 -formatter: a function to run the docstring through for specially
437 440 formatted docstrings.
438 441
439 442 Examples
440 443 --------
441 444
442 445 In [1]: class NoInit:
443 446 ...: pass
444 447
445 448 In [2]: class NoDoc:
446 449 ...: def __init__(self):
447 450 ...: pass
448 451
449 452 In [3]: %pdoc NoDoc
450 453 No documentation found for NoDoc
451 454
452 455 In [4]: %pdoc NoInit
453 456 No documentation found for NoInit
454 457
455 458 In [5]: obj = NoInit()
456 459
457 460 In [6]: %pdoc obj
458 461 No documentation found for obj
459 462
460 463 In [5]: obj2 = NoDoc()
461 464
462 465 In [6]: %pdoc obj2
463 466 No documentation found for obj2
464 467 """
465 468
466 469 head = self.__head # For convenience
467 470 lines = []
468 471 ds = getdoc(obj)
469 472 if formatter:
470 473 ds = formatter(ds)
471 474 if ds:
472 475 lines.append(head("Class docstring:"))
473 476 lines.append(indent(ds))
474 477 if inspect.isclass(obj) and hasattr(obj, '__init__'):
475 478 init_ds = getdoc(obj.__init__)
476 479 if init_ds is not None:
477 480 lines.append(head("Init docstring:"))
478 481 lines.append(indent(init_ds))
479 482 elif hasattr(obj,'__call__'):
480 483 call_ds = getdoc(obj.__call__)
481 484 if call_ds:
482 485 lines.append(head("Call docstring:"))
483 486 lines.append(indent(call_ds))
484 487
485 488 if not lines:
486 489 self.noinfo('documentation',oname)
487 490 else:
488 491 page.page('\n'.join(lines))
489 492
490 493 def psource(self, obj, oname=''):
491 494 """Print the source code for an object."""
492 495
493 496 # Flush the source cache because inspect can return out-of-date source
494 497 linecache.checkcache()
495 498 try:
496 499 src = getsource(obj, oname=oname)
497 500 except Exception:
498 501 src = None
499 502
500 503 if src is None:
501 504 self.noinfo('source', oname)
502 505 else:
503 506 page.page(self.format(src))
504 507
505 508 def pfile(self, obj, oname=''):
506 509 """Show the whole file where an object was defined."""
507 510
508 511 lineno = find_source_lines(obj)
509 512 if lineno is None:
510 513 self.noinfo('file', oname)
511 514 return
512 515
513 516 ofile = find_file(obj)
514 517 # run contents of file through pager starting at line where the object
515 518 # is defined, as long as the file isn't binary and is actually on the
516 519 # filesystem.
517 520 if ofile.endswith(('.so', '.dll', '.pyd')):
518 521 print('File %r is binary, not printing.' % ofile)
519 522 elif not os.path.isfile(ofile):
520 523 print('File %r does not exist, not printing.' % ofile)
521 524 else:
522 525 # Print only text files, not extension binaries. Note that
523 526 # getsourcelines returns lineno with 1-offset and page() uses
524 527 # 0-offset, so we must adjust.
525 528 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
526 529
527 530 def _format_fields(self, fields, title_width=0):
528 531 """Formats a list of fields for display.
529 532
530 533 Parameters
531 534 ----------
532 535 fields : list
533 536 A list of 2-tuples: (field_title, field_content)
534 537 title_width : int
535 538 How many characters to pad titles to. Default to longest title.
536 539 """
537 540 out = []
538 541 header = self.__head
539 542 if title_width == 0:
540 543 title_width = max(len(title) + 2 for title, _ in fields)
541 544 for title, content in fields:
542 545 if len(content.splitlines()) > 1:
543 546 title = header(title + ":") + "\n"
544 547 else:
545 548 title = header((title+":").ljust(title_width))
546 549 out.append(cast_unicode(title) + cast_unicode(content))
547 550 return "\n".join(out)
548 551
549 552 def _format_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
550 553 """Format an info dict as text"""
551 554 info = self.info(obj, oname=oname, formatter=formatter,
552 555 info=info, detail_level=detail_level)
553 556 displayfields = []
554 557 def add_fields(fields):
555 558 for title, key in fields:
556 559 field = info[key]
557 560 if field is not None:
558 561 if key == "source":
559 562 displayfields.append((title, self.format(cast_unicode(field.rstrip()))))
560 563 else:
561 564 displayfields.append((title, field.rstrip()))
562 565
563 566 if info['isalias']:
564 567 add_fields([('Repr', "string_form")])
565 568
566 569 elif info['ismagic']:
567 570 if detail_level > 0 and info['source'] is not None:
568 571 add_fields([("Source", "source")])
569 572 else:
570 573 add_fields([("Docstring", "docstring")])
571 574
572 575 add_fields([("File", "file"),
573 576 ])
574 577
575 578 elif info['isclass'] or is_simple_callable(obj):
576 579 # Functions, methods, classes
577 580 add_fields([("Signature", "definition"),
578 581 ("Init signature", "init_definition"),
579 582 ])
580 583 if detail_level > 0 and info['source'] is not None:
581 584 add_fields([("Source", "source")])
582 585 else:
583 586 add_fields([("Docstring", "docstring"),
584 587 ("Init docstring", "init_docstring"),
585 588 ])
586 589
587 590 add_fields([('File', 'file'),
588 591 ('Type', 'type_name'),
589 592 ])
590 593
591 594 else:
592 595 # General Python objects
593 596 add_fields([("Type", "type_name")])
594 597
595 598 # Base class for old-style instances
596 599 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
597 600 displayfields.append(("Base Class", info['base_class'].rstrip()))
598 601
599 602 add_fields([("String form", "string_form")])
600 603
601 604 # Namespace
602 605 if info['namespace'] != 'Interactive':
603 606 displayfields.append(("Namespace", info['namespace'].rstrip()))
604 607
605 608 add_fields([("Length", "length"),
606 609 ("File", "file"),
607 610 ("Signature", "definition"),
608 611 ])
609 612
610 613 # Source or docstring, depending on detail level and whether
611 614 # source found.
612 615 if detail_level > 0 and info['source'] is not None:
613 616 displayfields.append(("Source",
614 617 self.format(cast_unicode(info['source']))))
615 618 elif info['docstring'] is not None:
616 619 displayfields.append(("Docstring", info["docstring"]))
617 620
618 621 add_fields([("Class docstring", "class_docstring"),
619 622 ("Init docstring", "init_docstring"),
620 623 ("Call signature", "call_def"),
621 624 ("Call docstring", "call_docstring")])
622 625
623 626 if displayfields:
624 627 return self._format_fields(displayfields)
625 628 else:
626 629 return u''
627 630
628 631 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0):
629 632 """Show detailed information about an object.
630 633
631 634 Optional arguments:
632 635
633 636 - oname: name of the variable pointing to the object.
634 637
635 638 - formatter: special formatter for docstrings (see pdoc)
636 639
637 640 - info: a structure with some information fields which may have been
638 641 precomputed already.
639 642
640 643 - detail_level: if set to 1, more information is given.
641 644 """
642 645 text = self._format_info(obj, oname, formatter, info, detail_level)
643 646 if text:
644 647 page.page(text)
645 648
646 649 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
647 650 """Compute a dict with detailed information about an object.
648 651
649 652 Optional arguments:
650 653
651 654 - oname: name of the variable pointing to the object.
652 655
653 656 - formatter: special formatter for docstrings (see pdoc)
654 657
655 658 - info: a structure with some information fields which may have been
656 659 precomputed already.
657 660
658 661 - detail_level: if set to 1, more information is given.
659 662 """
660 663
661 664 obj_type = type(obj)
662 665
663 666 if info is None:
664 667 ismagic = 0
665 668 isalias = 0
666 669 ospace = ''
667 670 else:
668 671 ismagic = info.ismagic
669 672 isalias = info.isalias
670 673 ospace = info.namespace
671 674
672 675 # Get docstring, special-casing aliases:
673 676 if isalias:
674 677 if not callable(obj):
675 678 try:
676 679 ds = "Alias to the system command:\n %s" % obj[1]
677 680 except:
678 681 ds = "Alias: " + str(obj)
679 682 else:
680 683 ds = "Alias to " + str(obj)
681 684 if obj.__doc__:
682 685 ds += "\nDocstring:\n" + obj.__doc__
683 686 else:
684 687 ds = getdoc(obj)
685 688 if ds is None:
686 689 ds = '<no docstring>'
687 690 if formatter is not None:
688 691 ds = formatter(ds)
689 692
690 693 # store output in a dict, we initialize it here and fill it as we go
691 694 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
692 695
693 696 string_max = 200 # max size of strings to show (snipped if longer)
694 697 shalf = int((string_max -5)/2)
695 698
696 699 if ismagic:
697 700 obj_type_name = 'Magic function'
698 701 elif isalias:
699 702 obj_type_name = 'System alias'
700 703 else:
701 704 obj_type_name = obj_type.__name__
702 705 out['type_name'] = obj_type_name
703 706
704 707 try:
705 708 bclass = obj.__class__
706 709 out['base_class'] = str(bclass)
707 710 except: pass
708 711
709 712 # String form, but snip if too long in ? form (full in ??)
710 713 if detail_level >= self.str_detail_level:
711 714 try:
712 715 ostr = str(obj)
713 716 str_head = 'string_form'
714 717 if not detail_level and len(ostr)>string_max:
715 718 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
716 719 ostr = ("\n" + " " * len(str_head.expandtabs())).\
717 720 join(q.strip() for q in ostr.split("\n"))
718 721 out[str_head] = ostr
719 722 except:
720 723 pass
721 724
722 725 if ospace:
723 726 out['namespace'] = ospace
724 727
725 728 # Length (for strings and lists)
726 729 try:
727 730 out['length'] = str(len(obj))
728 731 except: pass
729 732
730 733 # Filename where object was defined
731 734 binary_file = False
732 735 fname = find_file(obj)
733 736 if fname is None:
734 737 # if anything goes wrong, we don't want to show source, so it's as
735 738 # if the file was binary
736 739 binary_file = True
737 740 else:
738 741 if fname.endswith(('.so', '.dll', '.pyd')):
739 742 binary_file = True
740 743 elif fname.endswith('<string>'):
741 744 fname = 'Dynamically generated function. No source code available.'
742 745 out['file'] = compress_user(fname)
743 746
744 747 # Original source code for a callable, class or property.
745 748 if detail_level:
746 749 # Flush the source cache because inspect can return out-of-date
747 750 # source
748 751 linecache.checkcache()
749 752 try:
750 753 if isinstance(obj, property) or not binary_file:
751 754 src = getsource(obj, oname)
752 755 if src is not None:
753 756 src = src.rstrip()
754 757 out['source'] = src
755 758
756 759 except Exception:
757 760 pass
758 761
759 762 # Add docstring only if no source is to be shown (avoid repetitions).
760 763 if ds and out.get('source', None) is None:
761 764 out['docstring'] = ds
762 765
763 766 # Constructor docstring for classes
764 767 if inspect.isclass(obj):
765 768 out['isclass'] = True
766 769 # reconstruct the function definition and print it:
767 770 try:
768 771 obj_init = obj.__init__
769 772 except AttributeError:
770 773 init_def = init_ds = None
771 774 else:
772 775 init_def = self._getdef(obj_init,oname)
773 776 init_ds = getdoc(obj_init)
774 777 # Skip Python's auto-generated docstrings
775 778 if init_ds == _object_init_docstring:
776 779 init_ds = None
777 780
778 781 if init_def or init_ds:
779 782 if init_def:
780 783 out['init_definition'] = self.format(init_def)
781 784 if init_ds:
782 785 out['init_docstring'] = init_ds
783 786
784 787 # and class docstring for instances:
785 788 else:
786 789 # reconstruct the function definition and print it:
787 790 defln = self._getdef(obj, oname)
788 791 if defln:
789 792 out['definition'] = self.format(defln)
790 793
791 794 # First, check whether the instance docstring is identical to the
792 795 # class one, and print it separately if they don't coincide. In
793 796 # most cases they will, but it's nice to print all the info for
794 797 # objects which use instance-customized docstrings.
795 798 if ds:
796 799 try:
797 800 cls = getattr(obj,'__class__')
798 801 except:
799 802 class_ds = None
800 803 else:
801 804 class_ds = getdoc(cls)
802 805 # Skip Python's auto-generated docstrings
803 806 if class_ds in _builtin_type_docstrings:
804 807 class_ds = None
805 808 if class_ds and ds != class_ds:
806 809 out['class_docstring'] = class_ds
807 810
808 811 # Next, try to show constructor docstrings
809 812 try:
810 813 init_ds = getdoc(obj.__init__)
811 814 # Skip Python's auto-generated docstrings
812 815 if init_ds == _object_init_docstring:
813 816 init_ds = None
814 817 except AttributeError:
815 818 init_ds = None
816 819 if init_ds:
817 820 out['init_docstring'] = init_ds
818 821
819 822 # Call form docstring for callable instances
820 823 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
821 824 call_def = self._getdef(obj.__call__, oname)
822 825 if call_def:
823 826 call_def = self.format(call_def)
824 827 # it may never be the case that call def and definition differ,
825 828 # but don't include the same signature twice
826 829 if call_def != out.get('definition'):
827 830 out['call_def'] = call_def
828 831 call_ds = getdoc(obj.__call__)
829 832 # Skip Python's auto-generated docstrings
830 833 if call_ds == _func_call_docstring:
831 834 call_ds = None
832 835 if call_ds:
833 836 out['call_docstring'] = call_ds
834 837
835 838 # Compute the object's argspec as a callable. The key is to decide
836 839 # whether to pull it from the object itself, from its __init__ or
837 840 # from its __call__ method.
838 841
839 842 if inspect.isclass(obj):
840 843 # Old-style classes need not have an __init__
841 844 callable_obj = getattr(obj, "__init__", None)
842 845 elif callable(obj):
843 846 callable_obj = obj
844 847 else:
845 848 callable_obj = None
846 849
847 850 if callable_obj is not None:
848 851 try:
849 852 argspec = getargspec(callable_obj)
850 853 except (TypeError, AttributeError):
851 854 # For extensions/builtins we can't retrieve the argspec
852 855 pass
853 856 else:
854 857 # named tuples' _asdict() method returns an OrderedDict, but we
855 858 # we want a normal
856 859 out['argspec'] = argspec_dict = dict(argspec._asdict())
857 860 # We called this varkw before argspec became a named tuple.
858 861 # With getfullargspec it's also called varkw.
859 862 if 'varkw' not in argspec_dict:
860 863 argspec_dict['varkw'] = argspec_dict.pop('keywords')
861 864
862 865 return object_info(**out)
863 866
864 867 def psearch(self,pattern,ns_table,ns_search=[],
865 868 ignore_case=False,show_all=False):
866 869 """Search namespaces with wildcards for objects.
867 870
868 871 Arguments:
869 872
870 873 - pattern: string containing shell-like wildcards to use in namespace
871 874 searches and optionally a type specification to narrow the search to
872 875 objects of that type.
873 876
874 877 - ns_table: dict of name->namespaces for search.
875 878
876 879 Optional arguments:
877 880
878 881 - ns_search: list of namespace names to include in search.
879 882
880 883 - ignore_case(False): make the search case-insensitive.
881 884
882 885 - show_all(False): show all names, including those starting with
883 886 underscores.
884 887 """
885 888 #print 'ps pattern:<%r>' % pattern # dbg
886 889
887 890 # defaults
888 891 type_pattern = 'all'
889 892 filter = ''
890 893
891 894 cmds = pattern.split()
892 895 len_cmds = len(cmds)
893 896 if len_cmds == 1:
894 897 # Only filter pattern given
895 898 filter = cmds[0]
896 899 elif len_cmds == 2:
897 900 # Both filter and type specified
898 901 filter,type_pattern = cmds
899 902 else:
900 903 raise ValueError('invalid argument string for psearch: <%s>' %
901 904 pattern)
902 905
903 906 # filter search namespaces
904 907 for name in ns_search:
905 908 if name not in ns_table:
906 909 raise ValueError('invalid namespace <%s>. Valid names: %s' %
907 910 (name,ns_table.keys()))
908 911
909 912 #print 'type_pattern:',type_pattern # dbg
910 913 search_result, namespaces_seen = set(), set()
911 914 for ns_name in ns_search:
912 915 ns = ns_table[ns_name]
913 916 # Normally, locals and globals are the same, so we just check one.
914 917 if id(ns) in namespaces_seen:
915 918 continue
916 919 namespaces_seen.add(id(ns))
917 920 tmp_res = list_namespace(ns, type_pattern, filter,
918 921 ignore_case=ignore_case, show_all=show_all)
919 922 search_result.update(tmp_res)
920 923
921 924 page.page('\n'.join(sorted(search_result)))
@@ -1,1479 +1,1483 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Verbose and colourful traceback formatting.
4 4
5 5 **ColorTB**
6 6
7 7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 8 ColorTB class is a solution to that problem. It colors the different parts of a
9 9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 10 text editor.
11 11
12 12 Installation instructions for ColorTB::
13 13
14 14 import sys,ultratb
15 15 sys.excepthook = ultratb.ColorTB()
16 16
17 17 **VerboseTB**
18 18
19 19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 21 and intended it for CGI programmers, but why should they have all the fun? I
22 22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 23 but kind of neat, and maybe useful for long-running programs that you believe
24 24 are bug-free. If a crash *does* occur in that type of program you want details.
25 25 Give it a shot--you'll love it or you'll hate it.
26 26
27 27 .. note::
28 28
29 29 The Verbose mode prints the variables currently visible where the exception
30 30 happened (shortening their strings if too long). This can potentially be
31 31 very slow, if you happen to have a huge data structure whose string
32 32 representation is complex to compute. Your computer may appear to freeze for
33 33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 34 with Ctrl-C (maybe hitting it more than once).
35 35
36 36 If you encounter this kind of situation often, you may want to use the
37 37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 38 variables (but otherwise includes the information and context given by
39 39 Verbose).
40 40
41 41 .. note::
42 42
43 43 The verbose mode print all variables in the stack, which means it can
44 44 potentially leak sensitive information like access keys, or unencryted
45 45 password.
46 46
47 47 Installation instructions for VerboseTB::
48 48
49 49 import sys,ultratb
50 50 sys.excepthook = ultratb.VerboseTB()
51 51
52 52 Note: Much of the code in this module was lifted verbatim from the standard
53 53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54 54
55 55 Color schemes
56 56 -------------
57 57
58 58 The colors are defined in the class TBTools through the use of the
59 59 ColorSchemeTable class. Currently the following exist:
60 60
61 61 - NoColor: allows all of this module to be used in any terminal (the color
62 62 escapes are just dummy blank strings).
63 63
64 64 - Linux: is meant to look good in a terminal like the Linux console (black
65 65 or very dark background).
66 66
67 67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 68 in light background terminals.
69 69
70 70 You can implement other color schemes easily, the syntax is fairly
71 71 self-explanatory. Please send back new schemes you develop to the author for
72 72 possible inclusion in future releases.
73 73
74 74 Inheritance diagram:
75 75
76 76 .. inheritance-diagram:: IPython.core.ultratb
77 77 :parts: 3
78 78 """
79 79
80 80 #*****************************************************************************
81 81 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
82 82 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
83 83 #
84 84 # Distributed under the terms of the BSD License. The full license is in
85 85 # the file COPYING, distributed as part of this software.
86 86 #*****************************************************************************
87 87
88 from __future__ import absolute_import
88 89 from __future__ import unicode_literals
89 90 from __future__ import print_function
90 91
91 92 import dis
92 93 import inspect
93 94 import keyword
94 95 import linecache
95 96 import os
96 97 import pydoc
97 98 import re
98 99 import sys
99 100 import time
100 101 import tokenize
101 102 import traceback
102 103 import types
103 104
104 105 try: # Python 2
105 106 generate_tokens = tokenize.generate_tokens
106 107 except AttributeError: # Python 3
107 108 generate_tokens = tokenize.tokenize
108 109
109 110 # For purposes of monkeypatching inspect to fix a bug in it.
110 111 from inspect import getsourcefile, getfile, getmodule, \
111 112 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
112 113
113 114 # IPython's own modules
114 115 # Modified pdb which doesn't damage IPython's readline handling
115 116 from IPython import get_ipython
116 117 from IPython.core import debugger
117 118 from IPython.core.display_trap import DisplayTrap
118 119 from IPython.core.excolors import exception_colors
119 120 from IPython.utils import PyColorize
120 121 from IPython.utils import io
121 122 from IPython.utils import openpy
122 123 from IPython.utils import path as util_path
123 124 from IPython.utils import py3compat
124 125 from IPython.utils import ulinecache
125 126 from IPython.utils.data import uniq_stable
126 127 from logging import info, error
127 128
129 import IPython.utils.colorable as colorable
130
128 131 # Globals
129 132 # amount of space to put line numbers before verbose tracebacks
130 133 INDENT_SIZE = 8
131 134
132 135 # Default color scheme. This is used, for example, by the traceback
133 136 # formatter. When running in an actual IPython instance, the user's rc.colors
134 137 # value is used, but having a module global makes this functionality available
135 138 # to users of ultratb who are NOT running inside ipython.
136 139 DEFAULT_SCHEME = 'NoColor'
137 140
138 141 # ---------------------------------------------------------------------------
139 142 # Code begins
140 143
141 144 # Utility functions
142 145 def inspect_error():
143 146 """Print a message about internal inspect errors.
144 147
145 148 These are unfortunately quite common."""
146 149
147 150 error('Internal Python error in the inspect module.\n'
148 151 'Below is the traceback from this internal error.\n')
149 152
150 153
151 154 # This function is a monkeypatch we apply to the Python inspect module. We have
152 155 # now found when it's needed (see discussion on issue gh-1456), and we have a
153 156 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
154 157 # the monkeypatch is not applied. TK, Aug 2012.
155 158 def findsource(object):
156 159 """Return the entire source file and starting line number for an object.
157 160
158 161 The argument may be a module, class, method, function, traceback, frame,
159 162 or code object. The source code is returned as a list of all the lines
160 163 in the file and the line number indexes a line in that list. An IOError
161 164 is raised if the source code cannot be retrieved.
162 165
163 166 FIXED version with which we monkeypatch the stdlib to work around a bug."""
164 167
165 168 file = getsourcefile(object) or getfile(object)
166 169 # If the object is a frame, then trying to get the globals dict from its
167 170 # module won't work. Instead, the frame object itself has the globals
168 171 # dictionary.
169 172 globals_dict = None
170 173 if inspect.isframe(object):
171 174 # XXX: can this ever be false?
172 175 globals_dict = object.f_globals
173 176 else:
174 177 module = getmodule(object, file)
175 178 if module:
176 179 globals_dict = module.__dict__
177 180 lines = linecache.getlines(file, globals_dict)
178 181 if not lines:
179 182 raise IOError('could not get source code')
180 183
181 184 if ismodule(object):
182 185 return lines, 0
183 186
184 187 if isclass(object):
185 188 name = object.__name__
186 189 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
187 190 # make some effort to find the best matching class definition:
188 191 # use the one with the least indentation, which is the one
189 192 # that's most probably not inside a function definition.
190 193 candidates = []
191 194 for i in range(len(lines)):
192 195 match = pat.match(lines[i])
193 196 if match:
194 197 # if it's at toplevel, it's already the best one
195 198 if lines[i][0] == 'c':
196 199 return lines, i
197 200 # else add whitespace to candidate list
198 201 candidates.append((match.group(1), i))
199 202 if candidates:
200 203 # this will sort by whitespace, and by line number,
201 204 # less whitespace first
202 205 candidates.sort()
203 206 return lines, candidates[0][1]
204 207 else:
205 208 raise IOError('could not find class definition')
206 209
207 210 if ismethod(object):
208 211 object = object.__func__
209 212 if isfunction(object):
210 213 object = object.__code__
211 214 if istraceback(object):
212 215 object = object.tb_frame
213 216 if isframe(object):
214 217 object = object.f_code
215 218 if iscode(object):
216 219 if not hasattr(object, 'co_firstlineno'):
217 220 raise IOError('could not find function definition')
218 221 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
219 222 pmatch = pat.match
220 223 # fperez - fix: sometimes, co_firstlineno can give a number larger than
221 224 # the length of lines, which causes an error. Safeguard against that.
222 225 lnum = min(object.co_firstlineno, len(lines)) - 1
223 226 while lnum > 0:
224 227 if pmatch(lines[lnum]):
225 228 break
226 229 lnum -= 1
227 230
228 231 return lines, lnum
229 232 raise IOError('could not find code object')
230 233
231 234
232 235 # This is a patched version of inspect.getargs that applies the (unmerged)
233 236 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
234 237 # https://github.com/ipython/ipython/issues/8205 and
235 238 # https://github.com/ipython/ipython/issues/8293
236 239 def getargs(co):
237 240 """Get information about the arguments accepted by a code object.
238 241
239 242 Three things are returned: (args, varargs, varkw), where 'args' is
240 243 a list of argument names (possibly containing nested lists), and
241 244 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
242 245 if not iscode(co):
243 246 raise TypeError('{!r} is not a code object'.format(co))
244 247
245 248 nargs = co.co_argcount
246 249 names = co.co_varnames
247 250 args = list(names[:nargs])
248 251 step = 0
249 252
250 253 # The following acrobatics are for anonymous (tuple) arguments.
251 254 for i in range(nargs):
252 255 if args[i][:1] in ('', '.'):
253 256 stack, remain, count = [], [], []
254 257 while step < len(co.co_code):
255 258 op = ord(co.co_code[step])
256 259 step = step + 1
257 260 if op >= dis.HAVE_ARGUMENT:
258 261 opname = dis.opname[op]
259 262 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
260 263 step = step + 2
261 264 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
262 265 remain.append(value)
263 266 count.append(value)
264 267 elif opname in ('STORE_FAST', 'STORE_DEREF'):
265 268 if op in dis.haslocal:
266 269 stack.append(co.co_varnames[value])
267 270 elif op in dis.hasfree:
268 271 stack.append((co.co_cellvars + co.co_freevars)[value])
269 272 # Special case for sublists of length 1: def foo((bar))
270 273 # doesn't generate the UNPACK_TUPLE bytecode, so if
271 274 # `remain` is empty here, we have such a sublist.
272 275 if not remain:
273 276 stack[0] = [stack[0]]
274 277 break
275 278 else:
276 279 remain[-1] = remain[-1] - 1
277 280 while remain[-1] == 0:
278 281 remain.pop()
279 282 size = count.pop()
280 283 stack[-size:] = [stack[-size:]]
281 284 if not remain:
282 285 break
283 286 remain[-1] = remain[-1] - 1
284 287 if not remain:
285 288 break
286 289 args[i] = stack[0]
287 290
288 291 varargs = None
289 292 if co.co_flags & inspect.CO_VARARGS:
290 293 varargs = co.co_varnames[nargs]
291 294 nargs = nargs + 1
292 295 varkw = None
293 296 if co.co_flags & inspect.CO_VARKEYWORDS:
294 297 varkw = co.co_varnames[nargs]
295 298 return inspect.Arguments(args, varargs, varkw)
296 299
297 300
298 301 # Monkeypatch inspect to apply our bugfix.
299 302 def with_patch_inspect(f):
300 303 """decorator for monkeypatching inspect.findsource"""
301 304
302 305 def wrapped(*args, **kwargs):
303 306 save_findsource = inspect.findsource
304 307 save_getargs = inspect.getargs
305 308 inspect.findsource = findsource
306 309 inspect.getargs = getargs
307 310 try:
308 311 return f(*args, **kwargs)
309 312 finally:
310 313 inspect.findsource = save_findsource
311 314 inspect.getargs = save_getargs
312 315
313 316 return wrapped
314 317
315 318
316 319 if py3compat.PY3:
317 320 fixed_getargvalues = inspect.getargvalues
318 321 else:
319 322 # Fixes for https://github.com/ipython/ipython/issues/8293
320 323 # and https://github.com/ipython/ipython/issues/8205.
321 324 # The relevant bug is caused by failure to correctly handle anonymous tuple
322 325 # unpacking, which only exists in Python 2.
323 326 fixed_getargvalues = with_patch_inspect(inspect.getargvalues)
324 327
325 328
326 329 def fix_frame_records_filenames(records):
327 330 """Try to fix the filenames in each record from inspect.getinnerframes().
328 331
329 332 Particularly, modules loaded from within zip files have useless filenames
330 333 attached to their code object, and inspect.getinnerframes() just uses it.
331 334 """
332 335 fixed_records = []
333 336 for frame, filename, line_no, func_name, lines, index in records:
334 337 # Look inside the frame's globals dictionary for __file__,
335 338 # which should be better. However, keep Cython filenames since
336 339 # we prefer the source filenames over the compiled .so file.
337 340 filename = py3compat.cast_unicode_py2(filename, "utf-8")
338 341 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
339 342 better_fn = frame.f_globals.get('__file__', None)
340 343 if isinstance(better_fn, str):
341 344 # Check the type just in case someone did something weird with
342 345 # __file__. It might also be None if the error occurred during
343 346 # import.
344 347 filename = better_fn
345 348 fixed_records.append((frame, filename, line_no, func_name, lines, index))
346 349 return fixed_records
347 350
348 351
349 352 @with_patch_inspect
350 353 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
351 354 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
352 355
353 356 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
354 357 # If the error is at the console, don't build any context, since it would
355 358 # otherwise produce 5 blank lines printed out (there is no file at the
356 359 # console)
357 360 rec_check = records[tb_offset:]
358 361 try:
359 362 rname = rec_check[0][1]
360 363 if rname == '<ipython console>' or rname.endswith('<string>'):
361 364 return rec_check
362 365 except IndexError:
363 366 pass
364 367
365 368 aux = traceback.extract_tb(etb)
366 369 assert len(records) == len(aux)
367 370 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
368 371 maybeStart = lnum - 1 - context // 2
369 372 start = max(maybeStart, 0)
370 373 end = start + context
371 374 lines = ulinecache.getlines(file)[start:end]
372 375 buf = list(records[i])
373 376 buf[LNUM_POS] = lnum
374 377 buf[INDEX_POS] = lnum - 1 - start
375 378 buf[LINES_POS] = lines
376 379 records[i] = tuple(buf)
377 380 return records[tb_offset:]
378 381
379 382 # Helper function -- largely belongs to VerboseTB, but we need the same
380 383 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
381 384 # can be recognized properly by ipython.el's py-traceback-line-re
382 385 # (SyntaxErrors have to be treated specially because they have no traceback)
383 386
384 387 _parser = PyColorize.Parser()
385 388
386 389
387 390 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
388 391 numbers_width = INDENT_SIZE - 1
389 392 res = []
390 393 i = lnum - index
391 394
392 395 # This lets us get fully syntax-highlighted tracebacks.
393 396 if scheme is None:
394 397 ipinst = get_ipython()
395 398 if ipinst is not None:
396 399 scheme = ipinst.colors
397 400 else:
398 401 scheme = DEFAULT_SCHEME
399 402
400 403 _line_format = _parser.format2
401 404
402 405 for line in lines:
403 406 line = py3compat.cast_unicode(line)
404 407
405 408 new_line, err = _line_format(line, 'str', scheme)
406 409 if not err: line = new_line
407 410
408 411 if i == lnum:
409 412 # This is the line with the error
410 413 pad = numbers_width - len(str(i))
411 414 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
412 415 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
413 416 Colors.line, line, Colors.Normal)
414 417 else:
415 418 num = '%*s' % (numbers_width, i)
416 419 line = '%s%s%s %s' % (Colors.lineno, num,
417 420 Colors.Normal, line)
418 421
419 422 res.append(line)
420 423 if lvals and i == lnum:
421 424 res.append(lvals + '\n')
422 425 i = i + 1
423 426 return res
424 427
425 428 def is_recursion_error(etype, value, records):
426 429 try:
427 430 # RecursionError is new in Python 3.5
428 431 recursion_error_type = RecursionError
429 432 except NameError:
430 433 recursion_error_type = RuntimeError
431 434
432 435 # The default recursion limit is 1000, but some of that will be taken up
433 436 # by stack frames in IPython itself. >500 frames probably indicates
434 437 # a recursion error.
435 438 return (etype is recursion_error_type) \
436 439 and "recursion" in str(value).lower() \
437 440 and len(records) > 500
438 441
439 442 def find_recursion(etype, value, records):
440 443 """Identify the repeating stack frames from a RecursionError traceback
441 444
442 445 'records' is a list as returned by VerboseTB.get_records()
443 446
444 447 Returns (last_unique, repeat_length)
445 448 """
446 449 # This involves a bit of guesswork - we want to show enough of the traceback
447 450 # to indicate where the recursion is occurring. We guess that the innermost
448 451 # quarter of the traceback (250 frames by default) is repeats, and find the
449 452 # first frame (from in to out) that looks different.
450 453 if not is_recursion_error(etype, value, records):
451 454 return len(records), 0
452 455
453 456 # Select filename, lineno, func_name to track frames with
454 457 records = [r[1:4] for r in records]
455 458 inner_frames = records[-(len(records)//4):]
456 459 frames_repeated = set(inner_frames)
457 460
458 461 last_seen_at = {}
459 462 longest_repeat = 0
460 463 i = len(records)
461 464 for frame in reversed(records):
462 465 i -= 1
463 466 if frame not in frames_repeated:
464 467 last_unique = i
465 468 break
466 469
467 470 if frame in last_seen_at:
468 471 distance = last_seen_at[frame] - i
469 472 longest_repeat = max(longest_repeat, distance)
470 473
471 474 last_seen_at[frame] = i
472 475 else:
473 476 last_unique = 0 # The whole traceback was recursion
474 477
475 478 return last_unique, longest_repeat
476 479
477 480 #---------------------------------------------------------------------------
478 481 # Module classes
479 class TBTools(object):
482 class TBTools(colorable.Colorable):
480 483 """Basic tools used by all traceback printer classes."""
481 484
482 485 # Number of frames to skip when reporting tracebacks
483 486 tb_offset = 0
484 487
485 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
488 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
486 489 # Whether to call the interactive pdb debugger after printing
487 490 # tracebacks or not
491 super(TBTools, self).__init__(parent=parent, config=config)
488 492 self.call_pdb = call_pdb
489 493
490 494 # Output stream to write to. Note that we store the original value in
491 495 # a private attribute and then make the public ostream a property, so
492 496 # that we can delay accessing io.stdout until runtime. The way
493 497 # things are written now, the io.stdout object is dynamically managed
494 498 # so a reference to it should NEVER be stored statically. This
495 499 # property approach confines this detail to a single location, and all
496 500 # subclasses can simply access self.ostream for writing.
497 501 self._ostream = ostream
498 502
499 503 # Create color table
500 504 self.color_scheme_table = exception_colors()
501 505
502 506 self.set_colors(color_scheme)
503 507 self.old_scheme = color_scheme # save initial value for toggles
504 508
505 509 if call_pdb:
506 510 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
507 511 else:
508 512 self.pdb = None
509 513
510 514 def _get_ostream(self):
511 515 """Output stream that exceptions are written to.
512 516
513 517 Valid values are:
514 518
515 519 - None: the default, which means that IPython will dynamically resolve
516 520 to io.stdout. This ensures compatibility with most tools, including
517 521 Windows (where plain stdout doesn't recognize ANSI escapes).
518 522
519 523 - Any object with 'write' and 'flush' attributes.
520 524 """
521 525 return io.stdout if self._ostream is None else self._ostream
522 526
523 527 def _set_ostream(self, val):
524 528 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
525 529 self._ostream = val
526 530
527 531 ostream = property(_get_ostream, _set_ostream)
528 532
529 533 def set_colors(self, *args, **kw):
530 534 """Shorthand access to the color table scheme selector method."""
531 535
532 536 # Set own color table
533 537 self.color_scheme_table.set_active_scheme(*args, **kw)
534 538 # for convenience, set Colors to the active scheme
535 539 self.Colors = self.color_scheme_table.active_colors
536 540 # Also set colors of debugger
537 541 if hasattr(self, 'pdb') and self.pdb is not None:
538 542 self.pdb.set_colors(*args, **kw)
539 543
540 544 def color_toggle(self):
541 545 """Toggle between the currently active color scheme and NoColor."""
542 546
543 547 if self.color_scheme_table.active_scheme_name == 'NoColor':
544 548 self.color_scheme_table.set_active_scheme(self.old_scheme)
545 549 self.Colors = self.color_scheme_table.active_colors
546 550 else:
547 551 self.old_scheme = self.color_scheme_table.active_scheme_name
548 552 self.color_scheme_table.set_active_scheme('NoColor')
549 553 self.Colors = self.color_scheme_table.active_colors
550 554
551 555 def stb2text(self, stb):
552 556 """Convert a structured traceback (a list) to a string."""
553 557 return '\n'.join(stb)
554 558
555 559 def text(self, etype, value, tb, tb_offset=None, context=5):
556 560 """Return formatted traceback.
557 561
558 562 Subclasses may override this if they add extra arguments.
559 563 """
560 564 tb_list = self.structured_traceback(etype, value, tb,
561 565 tb_offset, context)
562 566 return self.stb2text(tb_list)
563 567
564 568 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
565 569 context=5, mode=None):
566 570 """Return a list of traceback frames.
567 571
568 572 Must be implemented by each class.
569 573 """
570 574 raise NotImplementedError()
571 575
572 576
573 577 #---------------------------------------------------------------------------
574 578 class ListTB(TBTools):
575 579 """Print traceback information from a traceback list, with optional color.
576 580
577 581 Calling requires 3 arguments: (etype, evalue, elist)
578 582 as would be obtained by::
579 583
580 584 etype, evalue, tb = sys.exc_info()
581 585 if tb:
582 586 elist = traceback.extract_tb(tb)
583 587 else:
584 588 elist = None
585 589
586 590 It can thus be used by programs which need to process the traceback before
587 591 printing (such as console replacements based on the code module from the
588 592 standard library).
589 593
590 594 Because they are meant to be called without a full traceback (only a
591 595 list), instances of this class can't call the interactive pdb debugger."""
592 596
593 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
597 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None):
594 598 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
595 ostream=ostream)
599 ostream=ostream, parent=parent)
596 600
597 601 def __call__(self, etype, value, elist):
598 602 self.ostream.flush()
599 603 self.ostream.write(self.text(etype, value, elist))
600 604 self.ostream.write('\n')
601 605
602 606 def structured_traceback(self, etype, value, elist, tb_offset=None,
603 607 context=5):
604 608 """Return a color formatted string with the traceback info.
605 609
606 610 Parameters
607 611 ----------
608 612 etype : exception type
609 613 Type of the exception raised.
610 614
611 615 value : object
612 616 Data stored in the exception
613 617
614 618 elist : list
615 619 List of frames, see class docstring for details.
616 620
617 621 tb_offset : int, optional
618 622 Number of frames in the traceback to skip. If not given, the
619 623 instance value is used (set in constructor).
620 624
621 625 context : int, optional
622 626 Number of lines of context information to print.
623 627
624 628 Returns
625 629 -------
626 630 String with formatted exception.
627 631 """
628 632 tb_offset = self.tb_offset if tb_offset is None else tb_offset
629 633 Colors = self.Colors
630 634 out_list = []
631 635 if elist:
632 636
633 637 if tb_offset and len(elist) > tb_offset:
634 638 elist = elist[tb_offset:]
635 639
636 640 out_list.append('Traceback %s(most recent call last)%s:' %
637 641 (Colors.normalEm, Colors.Normal) + '\n')
638 642 out_list.extend(self._format_list(elist))
639 643 # The exception info should be a single entry in the list.
640 644 lines = ''.join(self._format_exception_only(etype, value))
641 645 out_list.append(lines)
642 646
643 647 # Note: this code originally read:
644 648
645 649 ## for line in lines[:-1]:
646 650 ## out_list.append(" "+line)
647 651 ## out_list.append(lines[-1])
648 652
649 653 # This means it was indenting everything but the last line by a little
650 654 # bit. I've disabled this for now, but if we see ugliness somewhere we
651 655 # can restore it.
652 656
653 657 return out_list
654 658
655 659 def _format_list(self, extracted_list):
656 660 """Format a list of traceback entry tuples for printing.
657 661
658 662 Given a list of tuples as returned by extract_tb() or
659 663 extract_stack(), return a list of strings ready for printing.
660 664 Each string in the resulting list corresponds to the item with the
661 665 same index in the argument list. Each string ends in a newline;
662 666 the strings may contain internal newlines as well, for those items
663 667 whose source text line is not None.
664 668
665 669 Lifted almost verbatim from traceback.py
666 670 """
667 671
668 672 Colors = self.Colors
669 673 list = []
670 674 for filename, lineno, name, line in extracted_list[:-1]:
671 675 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
672 676 (Colors.filename, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.Normal,
673 677 Colors.lineno, lineno, Colors.Normal,
674 678 Colors.name, py3compat.cast_unicode_py2(name, "utf-8"), Colors.Normal)
675 679 if line:
676 680 item += ' %s\n' % line.strip()
677 681 list.append(item)
678 682 # Emphasize the last entry
679 683 filename, lineno, name, line = extracted_list[-1]
680 684 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
681 685 (Colors.normalEm,
682 686 Colors.filenameEm, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.normalEm,
683 687 Colors.linenoEm, lineno, Colors.normalEm,
684 688 Colors.nameEm, py3compat.cast_unicode_py2(name, "utf-8"), Colors.normalEm,
685 689 Colors.Normal)
686 690 if line:
687 691 item += '%s %s%s\n' % (Colors.line, line.strip(),
688 692 Colors.Normal)
689 693 list.append(item)
690 694 return list
691 695
692 696 def _format_exception_only(self, etype, value):
693 697 """Format the exception part of a traceback.
694 698
695 699 The arguments are the exception type and value such as given by
696 700 sys.exc_info()[:2]. The return value is a list of strings, each ending
697 701 in a newline. Normally, the list contains a single string; however,
698 702 for SyntaxError exceptions, it contains several lines that (when
699 703 printed) display detailed information about where the syntax error
700 704 occurred. The message indicating which exception occurred is the
701 705 always last string in the list.
702 706
703 707 Also lifted nearly verbatim from traceback.py
704 708 """
705 709 have_filedata = False
706 710 Colors = self.Colors
707 711 list = []
708 712 stype = Colors.excName + etype.__name__ + Colors.Normal
709 713 if value is None:
710 714 # Not sure if this can still happen in Python 2.6 and above
711 715 list.append(py3compat.cast_unicode(stype) + '\n')
712 716 else:
713 717 if issubclass(etype, SyntaxError):
714 718 have_filedata = True
715 719 if not value.filename: value.filename = "<string>"
716 720 if value.lineno:
717 721 lineno = value.lineno
718 722 textline = ulinecache.getline(value.filename, value.lineno)
719 723 else:
720 724 lineno = 'unknown'
721 725 textline = ''
722 726 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
723 727 (Colors.normalEm,
724 728 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
725 729 Colors.linenoEm, lineno, Colors.Normal ))
726 730 if textline == '':
727 731 textline = py3compat.cast_unicode(value.text, "utf-8")
728 732
729 733 if textline is not None:
730 734 i = 0
731 735 while i < len(textline) and textline[i].isspace():
732 736 i += 1
733 737 list.append('%s %s%s\n' % (Colors.line,
734 738 textline.strip(),
735 739 Colors.Normal))
736 740 if value.offset is not None:
737 741 s = ' '
738 742 for c in textline[i:value.offset - 1]:
739 743 if c.isspace():
740 744 s += c
741 745 else:
742 746 s += ' '
743 747 list.append('%s%s^%s\n' % (Colors.caret, s,
744 748 Colors.Normal))
745 749
746 750 try:
747 751 s = value.msg
748 752 except Exception:
749 753 s = self._some_str(value)
750 754 if s:
751 755 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
752 756 Colors.Normal, s))
753 757 else:
754 758 list.append('%s\n' % str(stype))
755 759
756 760 # sync with user hooks
757 761 if have_filedata:
758 762 ipinst = get_ipython()
759 763 if ipinst is not None:
760 764 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
761 765
762 766 return list
763 767
764 768 def get_exception_only(self, etype, value):
765 769 """Only print the exception type and message, without a traceback.
766 770
767 771 Parameters
768 772 ----------
769 773 etype : exception type
770 774 value : exception value
771 775 """
772 776 return ListTB.structured_traceback(self, etype, value, [])
773 777
774 778 def show_exception_only(self, etype, evalue):
775 779 """Only print the exception type and message, without a traceback.
776 780
777 781 Parameters
778 782 ----------
779 783 etype : exception type
780 784 value : exception value
781 785 """
782 786 # This method needs to use __call__ from *this* class, not the one from
783 787 # a subclass whose signature or behavior may be different
784 788 ostream = self.ostream
785 789 ostream.flush()
786 790 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
787 791 ostream.flush()
788 792
789 793 def _some_str(self, value):
790 794 # Lifted from traceback.py
791 795 try:
792 796 return str(value)
793 797 except:
794 798 return '<unprintable %s object>' % type(value).__name__
795 799
796 800
797 801 #----------------------------------------------------------------------------
798 802 class VerboseTB(TBTools):
799 803 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
800 804 of HTML. Requires inspect and pydoc. Crazy, man.
801 805
802 806 Modified version which optionally strips the topmost entries from the
803 807 traceback, to be used with alternate interpreters (because their own code
804 808 would appear in the traceback)."""
805 809
806 810 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
807 811 tb_offset=0, long_header=False, include_vars=True,
808 812 check_cache=None):
809 813 """Specify traceback offset, headers and color scheme.
810 814
811 815 Define how many frames to drop from the tracebacks. Calling it with
812 816 tb_offset=1 allows use of this handler in interpreters which will have
813 817 their own code at the top of the traceback (VerboseTB will first
814 818 remove that frame before printing the traceback info)."""
815 819 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
816 820 ostream=ostream)
817 821 self.tb_offset = tb_offset
818 822 self.long_header = long_header
819 823 self.include_vars = include_vars
820 824 # By default we use linecache.checkcache, but the user can provide a
821 825 # different check_cache implementation. This is used by the IPython
822 826 # kernel to provide tracebacks for interactive code that is cached,
823 827 # by a compiler instance that flushes the linecache but preserves its
824 828 # own code cache.
825 829 if check_cache is None:
826 830 check_cache = linecache.checkcache
827 831 self.check_cache = check_cache
828 832
829 833 def format_records(self, records, last_unique, recursion_repeat):
830 834 """Format the stack frames of the traceback"""
831 835 frames = []
832 836 for r in records[:last_unique+recursion_repeat+1]:
833 837 #print '*** record:',file,lnum,func,lines,index # dbg
834 838 frames.append(self.format_record(*r))
835 839
836 840 if recursion_repeat:
837 841 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
838 842 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
839 843
840 844 return frames
841 845
842 846 def format_record(self, frame, file, lnum, func, lines, index):
843 847 """Format a single stack frame"""
844 848 Colors = self.Colors # just a shorthand + quicker name lookup
845 849 ColorsNormal = Colors.Normal # used a lot
846 850 col_scheme = self.color_scheme_table.active_scheme_name
847 851 indent = ' ' * INDENT_SIZE
848 852 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
849 853 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
850 854 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
851 855 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
852 856 ColorsNormal)
853 857 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
854 858 (Colors.vName, Colors.valEm, ColorsNormal)
855 859 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
856 860 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
857 861 Colors.vName, ColorsNormal)
858 862 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
859 863
860 864 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
861 865 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
862 866 ColorsNormal)
863 867
864 868 abspath = os.path.abspath
865 869
866 870
867 871 if not file:
868 872 file = '?'
869 873 elif file.startswith(str("<")) and file.endswith(str(">")):
870 874 # Not a real filename, no problem...
871 875 pass
872 876 elif not os.path.isabs(file):
873 877 # Try to make the filename absolute by trying all
874 878 # sys.path entries (which is also what linecache does)
875 879 for dirname in sys.path:
876 880 try:
877 881 fullname = os.path.join(dirname, file)
878 882 if os.path.isfile(fullname):
879 883 file = os.path.abspath(fullname)
880 884 break
881 885 except Exception:
882 886 # Just in case that sys.path contains very
883 887 # strange entries...
884 888 pass
885 889
886 890 file = py3compat.cast_unicode(file, util_path.fs_encoding)
887 891 link = tpl_link % file
888 892 args, varargs, varkw, locals = fixed_getargvalues(frame)
889 893
890 894 if func == '?':
891 895 call = ''
892 896 else:
893 897 # Decide whether to include variable details or not
894 898 var_repr = self.include_vars and eqrepr or nullrepr
895 899 try:
896 900 call = tpl_call % (func, inspect.formatargvalues(args,
897 901 varargs, varkw,
898 902 locals, formatvalue=var_repr))
899 903 except KeyError:
900 904 # This happens in situations like errors inside generator
901 905 # expressions, where local variables are listed in the
902 906 # line, but can't be extracted from the frame. I'm not
903 907 # 100% sure this isn't actually a bug in inspect itself,
904 908 # but since there's no info for us to compute with, the
905 909 # best we can do is report the failure and move on. Here
906 910 # we must *not* call any traceback construction again,
907 911 # because that would mess up use of %debug later on. So we
908 912 # simply report the failure and move on. The only
909 913 # limitation will be that this frame won't have locals
910 914 # listed in the call signature. Quite subtle problem...
911 915 # I can't think of a good way to validate this in a unit
912 916 # test, but running a script consisting of:
913 917 # dict( (k,v.strip()) for (k,v) in range(10) )
914 918 # will illustrate the error, if this exception catch is
915 919 # disabled.
916 920 call = tpl_call_fail % func
917 921
918 922 # Don't attempt to tokenize binary files.
919 923 if file.endswith(('.so', '.pyd', '.dll')):
920 924 return '%s %s\n' % (link, call)
921 925
922 926 elif file.endswith(('.pyc', '.pyo')):
923 927 # Look up the corresponding source file.
924 928 file = openpy.source_from_cache(file)
925 929
926 930 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
927 931 line = getline(file, lnum[0])
928 932 lnum[0] += 1
929 933 return line
930 934
931 935 # Build the list of names on this line of code where the exception
932 936 # occurred.
933 937 try:
934 938 names = []
935 939 name_cont = False
936 940
937 941 for token_type, token, start, end, line in generate_tokens(linereader):
938 942 # build composite names
939 943 if token_type == tokenize.NAME and token not in keyword.kwlist:
940 944 if name_cont:
941 945 # Continuation of a dotted name
942 946 try:
943 947 names[-1].append(token)
944 948 except IndexError:
945 949 names.append([token])
946 950 name_cont = False
947 951 else:
948 952 # Regular new names. We append everything, the caller
949 953 # will be responsible for pruning the list later. It's
950 954 # very tricky to try to prune as we go, b/c composite
951 955 # names can fool us. The pruning at the end is easy
952 956 # to do (or the caller can print a list with repeated
953 957 # names if so desired.
954 958 names.append([token])
955 959 elif token == '.':
956 960 name_cont = True
957 961 elif token_type == tokenize.NEWLINE:
958 962 break
959 963
960 964 except (IndexError, UnicodeDecodeError, SyntaxError):
961 965 # signals exit of tokenizer
962 966 # SyntaxError can occur if the file is not actually Python
963 967 # - see gh-6300
964 968 pass
965 969 except tokenize.TokenError as msg:
966 970 _m = ("An unexpected error occurred while tokenizing input\n"
967 971 "The following traceback may be corrupted or invalid\n"
968 972 "The error message is: %s\n" % msg)
969 973 error(_m)
970 974
971 975 # Join composite names (e.g. "dict.fromkeys")
972 976 names = ['.'.join(n) for n in names]
973 977 # prune names list of duplicates, but keep the right order
974 978 unique_names = uniq_stable(names)
975 979
976 980 # Start loop over vars
977 981 lvals = []
978 982 if self.include_vars:
979 983 for name_full in unique_names:
980 984 name_base = name_full.split('.', 1)[0]
981 985 if name_base in frame.f_code.co_varnames:
982 986 if name_base in locals:
983 987 try:
984 988 value = repr(eval(name_full, locals))
985 989 except:
986 990 value = undefined
987 991 else:
988 992 value = undefined
989 993 name = tpl_local_var % name_full
990 994 else:
991 995 if name_base in frame.f_globals:
992 996 try:
993 997 value = repr(eval(name_full, frame.f_globals))
994 998 except:
995 999 value = undefined
996 1000 else:
997 1001 value = undefined
998 1002 name = tpl_global_var % name_full
999 1003 lvals.append(tpl_name_val % (name, value))
1000 1004 if lvals:
1001 1005 lvals = '%s%s' % (indent, em_normal.join(lvals))
1002 1006 else:
1003 1007 lvals = ''
1004 1008
1005 1009 level = '%s %s\n' % (link, call)
1006 1010
1007 1011 if index is None:
1008 1012 return level
1009 1013 else:
1010 1014 return '%s%s' % (level, ''.join(
1011 1015 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1012 1016 col_scheme)))
1013 1017
1014 1018 def prepare_chained_exception_message(self, cause):
1015 1019 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1016 1020 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1017 1021
1018 1022 if cause:
1019 1023 message = [[direct_cause]]
1020 1024 else:
1021 1025 message = [[exception_during_handling]]
1022 1026 return message
1023 1027
1024 1028 def prepare_header(self, etype, long_version=False):
1025 1029 colors = self.Colors # just a shorthand + quicker name lookup
1026 1030 colorsnormal = colors.Normal # used a lot
1027 1031 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1028 1032 if long_version:
1029 1033 # Header with the exception type, python version, and date
1030 1034 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1031 1035 date = time.ctime(time.time())
1032 1036
1033 1037 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * 75, colorsnormal,
1034 1038 exc, ' ' * (75 - len(str(etype)) - len(pyver)),
1035 1039 pyver, date.rjust(75) )
1036 1040 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1037 1041 "\ncalls leading up to the error, with the most recent (innermost) call last."
1038 1042 else:
1039 1043 # Simplified header
1040 1044 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1041 1045 rjust(75 - len(str(etype))) )
1042 1046
1043 1047 return head
1044 1048
1045 1049 def format_exception(self, etype, evalue):
1046 1050 colors = self.Colors # just a shorthand + quicker name lookup
1047 1051 colorsnormal = colors.Normal # used a lot
1048 1052 indent = ' ' * INDENT_SIZE
1049 1053 # Get (safely) a string form of the exception info
1050 1054 try:
1051 1055 etype_str, evalue_str = map(str, (etype, evalue))
1052 1056 except:
1053 1057 # User exception is improperly defined.
1054 1058 etype, evalue = str, sys.exc_info()[:2]
1055 1059 etype_str, evalue_str = map(str, (etype, evalue))
1056 1060 # ... and format it
1057 1061 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
1058 1062 colorsnormal, py3compat.cast_unicode(evalue_str))]
1059 1063
1060 1064 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
1061 1065 try:
1062 1066 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
1063 1067 except:
1064 1068 # Every now and then, an object with funny internals blows up
1065 1069 # when dir() is called on it. We do the best we can to report
1066 1070 # the problem and continue
1067 1071 _m = '%sException reporting error (object with broken dir())%s:'
1068 1072 exception.append(_m % (colors.excName, colorsnormal))
1069 1073 etype_str, evalue_str = map(str, sys.exc_info()[:2])
1070 1074 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
1071 1075 colorsnormal, py3compat.cast_unicode(evalue_str)))
1072 1076 names = []
1073 1077 for name in names:
1074 1078 value = text_repr(getattr(evalue, name))
1075 1079 exception.append('\n%s%s = %s' % (indent, name, value))
1076 1080
1077 1081 return exception
1078 1082
1079 1083 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1080 1084 """Formats the header, traceback and exception message for a single exception.
1081 1085
1082 1086 This may be called multiple times by Python 3 exception chaining
1083 1087 (PEP 3134).
1084 1088 """
1085 1089 # some locals
1086 1090 orig_etype = etype
1087 1091 try:
1088 1092 etype = etype.__name__
1089 1093 except AttributeError:
1090 1094 pass
1091 1095
1092 1096 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1093 1097 head = self.prepare_header(etype, self.long_header)
1094 1098 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1095 1099
1096 1100 if records is None:
1097 1101 return ""
1098 1102
1099 1103 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1100 1104
1101 1105 frames = self.format_records(records, last_unique, recursion_repeat)
1102 1106
1103 1107 formatted_exception = self.format_exception(etype, evalue)
1104 1108 if records:
1105 1109 filepath, lnum = records[-1][1:3]
1106 1110 filepath = os.path.abspath(filepath)
1107 1111 ipinst = get_ipython()
1108 1112 if ipinst is not None:
1109 1113 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1110 1114
1111 1115 return [[head] + frames + [''.join(formatted_exception[0])]]
1112 1116
1113 1117 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1114 1118 try:
1115 1119 # Try the default getinnerframes and Alex's: Alex's fixes some
1116 1120 # problems, but it generates empty tracebacks for console errors
1117 1121 # (5 blanks lines) where none should be returned.
1118 1122 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1119 1123 except:
1120 1124 # FIXME: I've been getting many crash reports from python 2.3
1121 1125 # users, traceable to inspect.py. If I can find a small test-case
1122 1126 # to reproduce this, I should either write a better workaround or
1123 1127 # file a bug report against inspect (if that's the real problem).
1124 1128 # So far, I haven't been able to find an isolated example to
1125 1129 # reproduce the problem.
1126 1130 inspect_error()
1127 1131 traceback.print_exc(file=self.ostream)
1128 1132 info('\nUnfortunately, your original traceback can not be constructed.\n')
1129 1133 return None
1130 1134
1131 1135 def get_parts_of_chained_exception(self, evalue):
1132 1136 def get_chained_exception(exception_value):
1133 1137 cause = getattr(exception_value, '__cause__', None)
1134 1138 if cause:
1135 1139 return cause
1136 1140 if getattr(exception_value, '__suppress_context__', False):
1137 1141 return None
1138 1142 return getattr(exception_value, '__context__', None)
1139 1143
1140 1144 chained_evalue = get_chained_exception(evalue)
1141 1145
1142 1146 if chained_evalue:
1143 1147 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1144 1148
1145 1149 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1146 1150 number_of_lines_of_context=5):
1147 1151 """Return a nice text document describing the traceback."""
1148 1152
1149 1153 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1150 1154 tb_offset)
1151 1155
1152 1156 colors = self.Colors # just a shorthand + quicker name lookup
1153 1157 colorsnormal = colors.Normal # used a lot
1154 1158 head = '%s%s%s' % (colors.topline, '-' * 75, colorsnormal)
1155 1159 structured_traceback_parts = [head]
1156 1160 if py3compat.PY3:
1157 1161 chained_exceptions_tb_offset = 0
1158 1162 lines_of_context = 3
1159 1163 formatted_exceptions = formatted_exception
1160 1164 exception = self.get_parts_of_chained_exception(evalue)
1161 1165 if exception:
1162 1166 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1163 1167 etype, evalue, etb = exception
1164 1168 else:
1165 1169 evalue = None
1166 1170 chained_exc_ids = set()
1167 1171 while evalue:
1168 1172 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1169 1173 chained_exceptions_tb_offset)
1170 1174 exception = self.get_parts_of_chained_exception(evalue)
1171 1175
1172 1176 if exception and not id(exception[1]) in chained_exc_ids:
1173 1177 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1174 1178 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1175 1179 etype, evalue, etb = exception
1176 1180 else:
1177 1181 evalue = None
1178 1182
1179 1183 # we want to see exceptions in a reversed order:
1180 1184 # the first exception should be on top
1181 1185 for formatted_exception in reversed(formatted_exceptions):
1182 1186 structured_traceback_parts += formatted_exception
1183 1187 else:
1184 1188 structured_traceback_parts += formatted_exception[0]
1185 1189
1186 1190 return structured_traceback_parts
1187 1191
1188 1192 def debugger(self, force=False):
1189 1193 """Call up the pdb debugger if desired, always clean up the tb
1190 1194 reference.
1191 1195
1192 1196 Keywords:
1193 1197
1194 1198 - force(False): by default, this routine checks the instance call_pdb
1195 1199 flag and does not actually invoke the debugger if the flag is false.
1196 1200 The 'force' option forces the debugger to activate even if the flag
1197 1201 is false.
1198 1202
1199 1203 If the call_pdb flag is set, the pdb interactive debugger is
1200 1204 invoked. In all cases, the self.tb reference to the current traceback
1201 1205 is deleted to prevent lingering references which hamper memory
1202 1206 management.
1203 1207
1204 1208 Note that each call to pdb() does an 'import readline', so if your app
1205 1209 requires a special setup for the readline completers, you'll have to
1206 1210 fix that by hand after invoking the exception handler."""
1207 1211
1208 1212 if force or self.call_pdb:
1209 1213 if self.pdb is None:
1210 1214 self.pdb = debugger.Pdb(
1211 1215 self.color_scheme_table.active_scheme_name)
1212 1216 # the system displayhook may have changed, restore the original
1213 1217 # for pdb
1214 1218 display_trap = DisplayTrap(hook=sys.__displayhook__)
1215 1219 with display_trap:
1216 1220 self.pdb.reset()
1217 1221 # Find the right frame so we don't pop up inside ipython itself
1218 1222 if hasattr(self, 'tb') and self.tb is not None:
1219 1223 etb = self.tb
1220 1224 else:
1221 1225 etb = self.tb = sys.last_traceback
1222 1226 while self.tb is not None and self.tb.tb_next is not None:
1223 1227 self.tb = self.tb.tb_next
1224 1228 if etb and etb.tb_next:
1225 1229 etb = etb.tb_next
1226 1230 self.pdb.botframe = etb.tb_frame
1227 1231 self.pdb.interaction(self.tb.tb_frame, self.tb)
1228 1232
1229 1233 if hasattr(self, 'tb'):
1230 1234 del self.tb
1231 1235
1232 1236 def handler(self, info=None):
1233 1237 (etype, evalue, etb) = info or sys.exc_info()
1234 1238 self.tb = etb
1235 1239 ostream = self.ostream
1236 1240 ostream.flush()
1237 1241 ostream.write(self.text(etype, evalue, etb))
1238 1242 ostream.write('\n')
1239 1243 ostream.flush()
1240 1244
1241 1245 # Changed so an instance can just be called as VerboseTB_inst() and print
1242 1246 # out the right info on its own.
1243 1247 def __call__(self, etype=None, evalue=None, etb=None):
1244 1248 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1245 1249 if etb is None:
1246 1250 self.handler()
1247 1251 else:
1248 1252 self.handler((etype, evalue, etb))
1249 1253 try:
1250 1254 self.debugger()
1251 1255 except KeyboardInterrupt:
1252 1256 print("\nKeyboardInterrupt")
1253 1257
1254 1258
1255 1259 #----------------------------------------------------------------------------
1256 1260 class FormattedTB(VerboseTB, ListTB):
1257 1261 """Subclass ListTB but allow calling with a traceback.
1258 1262
1259 1263 It can thus be used as a sys.excepthook for Python > 2.1.
1260 1264
1261 1265 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1262 1266
1263 1267 Allows a tb_offset to be specified. This is useful for situations where
1264 1268 one needs to remove a number of topmost frames from the traceback (such as
1265 1269 occurs with python programs that themselves execute other python code,
1266 1270 like Python shells). """
1267 1271
1268 1272 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1269 1273 ostream=None,
1270 1274 tb_offset=0, long_header=False, include_vars=False,
1271 1275 check_cache=None):
1272 1276
1273 1277 # NEVER change the order of this list. Put new modes at the end:
1274 1278 self.valid_modes = ['Plain', 'Context', 'Verbose']
1275 1279 self.verbose_modes = self.valid_modes[1:3]
1276 1280
1277 1281 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1278 1282 ostream=ostream, tb_offset=tb_offset,
1279 1283 long_header=long_header, include_vars=include_vars,
1280 1284 check_cache=check_cache)
1281 1285
1282 1286 # Different types of tracebacks are joined with different separators to
1283 1287 # form a single string. They are taken from this dict
1284 1288 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1285 1289 # set_mode also sets the tb_join_char attribute
1286 1290 self.set_mode(mode)
1287 1291
1288 1292 def _extract_tb(self, tb):
1289 1293 if tb:
1290 1294 return traceback.extract_tb(tb)
1291 1295 else:
1292 1296 return None
1293 1297
1294 1298 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1295 1299 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1296 1300 mode = self.mode
1297 1301 if mode in self.verbose_modes:
1298 1302 # Verbose modes need a full traceback
1299 1303 return VerboseTB.structured_traceback(
1300 1304 self, etype, value, tb, tb_offset, number_of_lines_of_context
1301 1305 )
1302 1306 else:
1303 1307 # We must check the source cache because otherwise we can print
1304 1308 # out-of-date source code.
1305 1309 self.check_cache()
1306 1310 # Now we can extract and format the exception
1307 1311 elist = self._extract_tb(tb)
1308 1312 return ListTB.structured_traceback(
1309 1313 self, etype, value, elist, tb_offset, number_of_lines_of_context
1310 1314 )
1311 1315
1312 1316 def stb2text(self, stb):
1313 1317 """Convert a structured traceback (a list) to a string."""
1314 1318 return self.tb_join_char.join(stb)
1315 1319
1316 1320
1317 1321 def set_mode(self, mode=None):
1318 1322 """Switch to the desired mode.
1319 1323
1320 1324 If mode is not specified, cycles through the available modes."""
1321 1325
1322 1326 if not mode:
1323 1327 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1324 1328 len(self.valid_modes)
1325 1329 self.mode = self.valid_modes[new_idx]
1326 1330 elif mode not in self.valid_modes:
1327 1331 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1328 1332 'Valid modes: ' + str(self.valid_modes))
1329 1333 else:
1330 1334 self.mode = mode
1331 1335 # include variable details only in 'Verbose' mode
1332 1336 self.include_vars = (self.mode == self.valid_modes[2])
1333 1337 # Set the join character for generating text tracebacks
1334 1338 self.tb_join_char = self._join_chars[self.mode]
1335 1339
1336 1340 # some convenient shortcuts
1337 1341 def plain(self):
1338 1342 self.set_mode(self.valid_modes[0])
1339 1343
1340 1344 def context(self):
1341 1345 self.set_mode(self.valid_modes[1])
1342 1346
1343 1347 def verbose(self):
1344 1348 self.set_mode(self.valid_modes[2])
1345 1349
1346 1350
1347 1351 #----------------------------------------------------------------------------
1348 1352 class AutoFormattedTB(FormattedTB):
1349 1353 """A traceback printer which can be called on the fly.
1350 1354
1351 1355 It will find out about exceptions by itself.
1352 1356
1353 1357 A brief example::
1354 1358
1355 1359 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1356 1360 try:
1357 1361 ...
1358 1362 except:
1359 1363 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1360 1364 """
1361 1365
1362 1366 def __call__(self, etype=None, evalue=None, etb=None,
1363 1367 out=None, tb_offset=None):
1364 1368 """Print out a formatted exception traceback.
1365 1369
1366 1370 Optional arguments:
1367 1371 - out: an open file-like object to direct output to.
1368 1372
1369 1373 - tb_offset: the number of frames to skip over in the stack, on a
1370 1374 per-call basis (this overrides temporarily the instance's tb_offset
1371 1375 given at initialization time. """
1372 1376
1373 1377 if out is None:
1374 1378 out = self.ostream
1375 1379 out.flush()
1376 1380 out.write(self.text(etype, evalue, etb, tb_offset))
1377 1381 out.write('\n')
1378 1382 out.flush()
1379 1383 # FIXME: we should remove the auto pdb behavior from here and leave
1380 1384 # that to the clients.
1381 1385 try:
1382 1386 self.debugger()
1383 1387 except KeyboardInterrupt:
1384 1388 print("\nKeyboardInterrupt")
1385 1389
1386 1390 def structured_traceback(self, etype=None, value=None, tb=None,
1387 1391 tb_offset=None, number_of_lines_of_context=5):
1388 1392 if etype is None:
1389 1393 etype, value, tb = sys.exc_info()
1390 1394 self.tb = tb
1391 1395 return FormattedTB.structured_traceback(
1392 1396 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1393 1397
1394 1398
1395 1399 #---------------------------------------------------------------------------
1396 1400
1397 1401 # A simple class to preserve Nathan's original functionality.
1398 1402 class ColorTB(FormattedTB):
1399 1403 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1400 1404
1401 1405 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1402 1406 FormattedTB.__init__(self, color_scheme=color_scheme,
1403 1407 call_pdb=call_pdb, **kwargs)
1404 1408
1405 1409
1406 1410 class SyntaxTB(ListTB):
1407 1411 """Extension which holds some state: the last exception value"""
1408 1412
1409 1413 def __init__(self, color_scheme='NoColor'):
1410 1414 ListTB.__init__(self, color_scheme)
1411 1415 self.last_syntax_error = None
1412 1416
1413 1417 def __call__(self, etype, value, elist):
1414 1418 self.last_syntax_error = value
1415 1419
1416 1420 ListTB.__call__(self, etype, value, elist)
1417 1421
1418 1422 def structured_traceback(self, etype, value, elist, tb_offset=None,
1419 1423 context=5):
1420 1424 # If the source file has been edited, the line in the syntax error can
1421 1425 # be wrong (retrieved from an outdated cache). This replaces it with
1422 1426 # the current value.
1423 1427 if isinstance(value, SyntaxError) \
1424 1428 and isinstance(value.filename, py3compat.string_types) \
1425 1429 and isinstance(value.lineno, int):
1426 1430 linecache.checkcache(value.filename)
1427 1431 newtext = ulinecache.getline(value.filename, value.lineno)
1428 1432 if newtext:
1429 1433 value.text = newtext
1430 1434 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1431 1435 tb_offset=tb_offset, context=context)
1432 1436
1433 1437 def clear_err_state(self):
1434 1438 """Return the current error state and clear it"""
1435 1439 e = self.last_syntax_error
1436 1440 self.last_syntax_error = None
1437 1441 return e
1438 1442
1439 1443 def stb2text(self, stb):
1440 1444 """Convert a structured traceback (a list) to a string."""
1441 1445 return ''.join(stb)
1442 1446
1443 1447
1444 1448 # some internal-use functions
1445 1449 def text_repr(value):
1446 1450 """Hopefully pretty robust repr equivalent."""
1447 1451 # this is pretty horrible but should always return *something*
1448 1452 try:
1449 1453 return pydoc.text.repr(value)
1450 1454 except KeyboardInterrupt:
1451 1455 raise
1452 1456 except:
1453 1457 try:
1454 1458 return repr(value)
1455 1459 except KeyboardInterrupt:
1456 1460 raise
1457 1461 except:
1458 1462 try:
1459 1463 # all still in an except block so we catch
1460 1464 # getattr raising
1461 1465 name = getattr(value, '__name__', None)
1462 1466 if name:
1463 1467 # ick, recursion
1464 1468 return text_repr(name)
1465 1469 klass = getattr(value, '__class__', None)
1466 1470 if klass:
1467 1471 return '%s instance' % text_repr(klass)
1468 1472 except KeyboardInterrupt:
1469 1473 raise
1470 1474 except:
1471 1475 return 'UNRECOVERABLE REPR FAILURE'
1472 1476
1473 1477
1474 1478 def eqrepr(value, repr=text_repr):
1475 1479 return '=%s' % repr(value)
1476 1480
1477 1481
1478 1482 def nullrepr(value, repr=text_repr):
1479 1483 return ''
@@ -1,342 +1,347 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Class and program to colorize python source code for ANSI terminals.
4 4
5 5 Based on an HTML code highlighter by Jurgen Hermann found at:
6 6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
7 7
8 8 Modifications by Fernando Perez (fperez@colorado.edu).
9 9
10 10 Information on the original HTML highlighter follows:
11 11
12 12 MoinMoin - Python Source Parser
13 13
14 14 Title: Colorize Python source using the built-in tokenizer
15 15
16 16 Submitter: Jurgen Hermann
17 17 Last Updated:2001/04/06
18 18
19 19 Version no:1.2
20 20
21 21 Description:
22 22
23 23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
24 24 Python source code to HTML markup, rendering comments, keywords,
25 25 operators, numeric and string literals in different colors.
26 26
27 27 It shows how to use the built-in keyword, token and tokenize modules to
28 28 scan Python source code and re-emit it with no changes to its original
29 29 formatting (which is the hard part).
30 30 """
31 31 from __future__ import print_function
32 32 from __future__ import absolute_import
33 33 from __future__ import unicode_literals
34 34
35 35 __all__ = ['ANSICodeColors','Parser']
36 36
37 37 _scheme_default = 'Linux'
38 38
39 39
40 40 # Imports
41 41 import keyword
42 42 import os
43 43 import sys
44 44 import token
45 45 import tokenize
46 46
47 47 try:
48 48 generate_tokens = tokenize.generate_tokens
49 49 except AttributeError:
50 50 # Python 3. Note that we use the undocumented _tokenize because it expects
51 51 # strings, not bytes. See also Python issue #9969.
52 52 generate_tokens = tokenize._tokenize
53 53
54 54 from IPython.utils.coloransi import TermColors, InputTermColors ,ColorScheme, ColorSchemeTable
55 55 from IPython.utils.py3compat import PY3
56 56
57 from .colorable import Colorable
58
57 59 if PY3:
58 60 from io import StringIO
59 61 else:
60 62 from StringIO import StringIO
61 63
62 64 #############################################################################
63 65 ### Python Source Parser (does Hilighting)
64 66 #############################################################################
65 67
66 68 _KEYWORD = token.NT_OFFSET + 1
67 69 _TEXT = token.NT_OFFSET + 2
68 70
69 71 #****************************************************************************
70 72 # Builtin color schemes
71 73
72 74 Colors = TermColors # just a shorthand
73 75
74 76 # Build a few color schemes
75 77 NoColor = ColorScheme(
76 78 'NoColor',{
77 79 'header' : Colors.NoColor,
78 80 token.NUMBER : Colors.NoColor,
79 81 token.OP : Colors.NoColor,
80 82 token.STRING : Colors.NoColor,
81 83 tokenize.COMMENT : Colors.NoColor,
82 84 token.NAME : Colors.NoColor,
83 85 token.ERRORTOKEN : Colors.NoColor,
84 86
85 87 _KEYWORD : Colors.NoColor,
86 88 _TEXT : Colors.NoColor,
87 89
88 90 'in_prompt' : InputTermColors.NoColor, # Input prompt
89 91 'in_number' : InputTermColors.NoColor, # Input prompt number
90 92 'in_prompt2' : InputTermColors.NoColor, # Continuation prompt
91 93 'in_normal' : InputTermColors.NoColor, # color off (usu. Colors.Normal)
92 94
93 95 'out_prompt' : Colors.NoColor, # Output prompt
94 96 'out_number' : Colors.NoColor, # Output prompt number
95 97
96 98 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
97 99 } )
98 100
99 101 LinuxColors = ColorScheme(
100 102 'Linux',{
101 103 'header' : Colors.LightRed,
102 104 token.NUMBER : Colors.LightCyan,
103 105 token.OP : Colors.Yellow,
104 106 token.STRING : Colors.LightBlue,
105 107 tokenize.COMMENT : Colors.LightRed,
106 108 token.NAME : Colors.Normal,
107 109 token.ERRORTOKEN : Colors.Red,
108 110
109 111 _KEYWORD : Colors.LightGreen,
110 112 _TEXT : Colors.Yellow,
111 113
112 114 'in_prompt' : InputTermColors.Green,
113 115 'in_number' : InputTermColors.LightGreen,
114 116 'in_prompt2' : InputTermColors.Green,
115 117 'in_normal' : InputTermColors.Normal, # color off (usu. Colors.Normal)
116 118
117 119 'out_prompt' : Colors.Red,
118 120 'out_number' : Colors.LightRed,
119 121
120 122 'normal' : Colors.Normal # color off (usu. Colors.Normal)
121 123 } )
122 124
123 125 LightBGColors = ColorScheme(
124 126 'LightBG',{
125 127 'header' : Colors.Red,
126 128 token.NUMBER : Colors.Cyan,
127 129 token.OP : Colors.Blue,
128 130 token.STRING : Colors.Blue,
129 131 tokenize.COMMENT : Colors.Red,
130 132 token.NAME : Colors.Normal,
131 133 token.ERRORTOKEN : Colors.Red,
132 134
133 135 _KEYWORD : Colors.Green,
134 136 _TEXT : Colors.Blue,
135 137
136 138 'in_prompt' : InputTermColors.Blue,
137 139 'in_number' : InputTermColors.LightBlue,
138 140 'in_prompt2' : InputTermColors.Blue,
139 141 'in_normal' : InputTermColors.Normal, # color off (usu. Colors.Normal)
140 142
141 143 'out_prompt' : Colors.Red,
142 144 'out_number' : Colors.LightRed,
143 145
144 146 'normal' : Colors.Normal # color off (usu. Colors.Normal)
145 147 } )
146 148
147 149 # Build table of color schemes (needed by the parser)
148 150 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
149 151 _scheme_default)
150 152
151 class Parser:
153 class Parser(Colorable):
152 154 """ Format colored Python source.
153 155 """
154 156
155 def __init__(self, color_table=None,out = sys.stdout):
157 def __init__(self, color_table=None, out = sys.stdout, parent=None, style=None):
156 158 """ Create a parser with a specified color table and output channel.
157 159
158 160 Call format() to process code.
159 161 """
162
163 super(Parser, self).__init__(parent=parent)
164
160 165 self.color_table = color_table and color_table or ANSICodeColors
161 166 self.out = out
162 167
163 168 def format(self, raw, out = None, scheme = ''):
164 169 return self.format2(raw, out, scheme)[0]
165 170
166 171 def format2(self, raw, out = None, scheme = ''):
167 172 """ Parse and send the colored source.
168 173
169 174 If out and scheme are not specified, the defaults (given to
170 175 constructor) are used.
171 176
172 177 out should be a file-type object. Optionally, out can be given as the
173 178 string 'str' and the parser will automatically return the output in a
174 179 string."""
175 180
176 181 string_output = 0
177 182 if out == 'str' or self.out == 'str' or \
178 183 isinstance(self.out,StringIO):
179 184 # XXX - I don't really like this state handling logic, but at this
180 185 # point I don't want to make major changes, so adding the
181 186 # isinstance() check is the simplest I can do to ensure correct
182 187 # behavior.
183 188 out_old = self.out
184 189 self.out = StringIO()
185 190 string_output = 1
186 191 elif out is not None:
187 192 self.out = out
188 193
189 194 # Fast return of the unmodified input for NoColor scheme
190 195 if scheme == 'NoColor':
191 196 error = False
192 197 self.out.write(raw)
193 198 if string_output:
194 199 return raw,error
195 200 else:
196 201 return None,error
197 202
198 203 # local shorthands
199 204 colors = self.color_table[scheme].colors
200 205 self.colors = colors # put in object so __call__ sees it
201 206
202 207 # Remove trailing whitespace and normalize tabs
203 208 self.raw = raw.expandtabs().rstrip()
204 209
205 210 # store line offsets in self.lines
206 211 self.lines = [0, 0]
207 212 pos = 0
208 213 raw_find = self.raw.find
209 214 lines_append = self.lines.append
210 215 while 1:
211 216 pos = raw_find('\n', pos) + 1
212 217 if not pos: break
213 218 lines_append(pos)
214 219 lines_append(len(self.raw))
215 220
216 221 # parse the source and write it
217 222 self.pos = 0
218 223 text = StringIO(self.raw)
219 224
220 225 error = False
221 226 try:
222 227 for atoken in generate_tokens(text.readline):
223 228 self(*atoken)
224 229 except tokenize.TokenError as ex:
225 230 msg = ex.args[0]
226 231 line = ex.args[1][0]
227 232 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
228 233 (colors[token.ERRORTOKEN],
229 234 msg, self.raw[self.lines[line]:],
230 235 colors.normal)
231 236 )
232 237 error = True
233 238 self.out.write(colors.normal+'\n')
234 239 if string_output:
235 240 output = self.out.getvalue()
236 241 self.out = out_old
237 242 return (output, error)
238 243 return (None, error)
239 244
240 245 def __call__(self, toktype, toktext, start_pos, end_pos, line):
241 246 """ Token handler, with syntax highlighting."""
242 247 (srow,scol) = start_pos
243 248 (erow,ecol) = end_pos
244 249 colors = self.colors
245 250 owrite = self.out.write
246 251
247 252 # line separator, so this works across platforms
248 253 linesep = os.linesep
249 254
250 255 # calculate new positions
251 256 oldpos = self.pos
252 257 newpos = self.lines[srow] + scol
253 258 self.pos = newpos + len(toktext)
254 259
255 260 # send the original whitespace, if needed
256 261 if newpos > oldpos:
257 262 owrite(self.raw[oldpos:newpos])
258 263
259 264 # skip indenting tokens
260 265 if toktype in [token.INDENT, token.DEDENT]:
261 266 self.pos = newpos
262 267 return
263 268
264 269 # map token type to a color group
265 270 if token.LPAR <= toktype <= token.OP:
266 271 toktype = token.OP
267 272 elif toktype == token.NAME and keyword.iskeyword(toktext):
268 273 toktype = _KEYWORD
269 274 color = colors.get(toktype, colors[_TEXT])
270 275
271 276 #print '<%s>' % toktext, # dbg
272 277
273 278 # Triple quoted strings must be handled carefully so that backtracking
274 279 # in pagers works correctly. We need color terminators on _each_ line.
275 280 if linesep in toktext:
276 281 toktext = toktext.replace(linesep, '%s%s%s' %
277 282 (colors.normal,linesep,color))
278 283
279 284 # send text
280 285 owrite('%s%s%s' % (color,toktext,colors.normal))
281 286
282 287 def main(argv=None):
283 288 """Run as a command-line script: colorize a python file or stdin using ANSI
284 289 color escapes and print to stdout.
285 290
286 291 Inputs:
287 292
288 293 - argv(None): a list of strings like sys.argv[1:] giving the command-line
289 294 arguments. If None, use sys.argv[1:].
290 295 """
291 296
292 297 usage_msg = """%prog [options] [filename]
293 298
294 299 Colorize a python file or stdin using ANSI color escapes and print to stdout.
295 300 If no filename is given, or if filename is -, read standard input."""
296 301
297 302 import optparse
298 303 parser = optparse.OptionParser(usage=usage_msg)
299 304 newopt = parser.add_option
300 305 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
301 306 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
302 307 help="give the color scheme to use. Currently only 'Linux'\
303 308 (default) and 'LightBG' and 'NoColor' are implemented (give without\
304 309 quotes)")
305 310
306 311 opts,args = parser.parse_args(argv)
307 312
308 313 if len(args) > 1:
309 314 parser.error("you must give at most one filename.")
310 315
311 316 if len(args) == 0:
312 317 fname = '-' # no filename given; setup to read from stdin
313 318 else:
314 319 fname = args[0]
315 320
316 321 if fname == '-':
317 322 stream = sys.stdin
318 323 else:
319 324 try:
320 325 stream = open(fname)
321 326 except IOError as msg:
322 327 print(msg, file=sys.stderr)
323 328 sys.exit(1)
324 329
325 330 parser = Parser()
326 331
327 332 # we need nested try blocks because pre-2.5 python doesn't support unified
328 333 # try-except-finally
329 334 try:
330 335 try:
331 336 # write colorized version to stdout
332 337 parser.format(stream.read(),scheme=opts.scheme_name)
333 338 except IOError as msg:
334 339 # if user reads through a pager and quits, don't print traceback
335 340 if msg.args != (32,'Broken pipe'):
336 341 raise
337 342 finally:
338 343 if stream is not sys.stdin:
339 344 stream.close() # in case a non-handled exception happened above
340 345
341 346 if __name__ == "__main__":
342 347 main()
General Comments 0
You need to be logged in to leave comments. Login now