1
1
from __future__ import absolute_import
2
2
3
+ import linecache
3
4
import os
4
5
import platform
5
6
import sys
6
7
from dataclasses import dataclass , field
7
- from pathlib import Path
8
8
from traceback import walk_tb
9
9
from types import ModuleType , TracebackType
10
- from typing import Any , Callable , Dict , Iterable , List , Optional , Sequence , Type , Union
10
+ from typing import (
11
+ Any ,
12
+ Callable ,
13
+ Dict ,
14
+ Iterable ,
15
+ List ,
16
+ Optional ,
17
+ Sequence ,
18
+ Tuple ,
19
+ Type ,
20
+ Union ,
21
+ )
11
22
12
23
from pygments .lexers import guess_lexer_for_filename
13
24
from pygments .token import Comment , Keyword , Name , Number , Operator , String
@@ -42,6 +53,10 @@ def install(
42
53
theme : Optional [str ] = None ,
43
54
word_wrap : bool = False ,
44
55
show_locals : bool = False ,
56
+ locals_max_length : int = LOCALS_MAX_LENGTH ,
57
+ locals_max_string : int = LOCALS_MAX_STRING ,
58
+ locals_hide_dunder : bool = True ,
59
+ locals_hide_sunder : Optional [bool ] = None ,
45
60
indent_guides : bool = True ,
46
61
suppress : Iterable [Union [str , ModuleType ]] = (),
47
62
max_frames : int = 100 ,
@@ -59,6 +74,11 @@ def install(
59
74
a theme appropriate for the platform.
60
75
word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False.
61
76
show_locals (bool, optional): Enable display of local variables. Defaults to False.
77
+ locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.
78
+ Defaults to 10.
79
+ locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.
80
+ locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True.
81
+ locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False.
62
82
indent_guides (bool, optional): Enable indent guides in code and locals. Defaults to True.
63
83
suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.
64
84
@@ -68,6 +88,12 @@ def install(
68
88
"""
69
89
traceback_console = Console (file = sys .stderr ) if console is None else console
70
90
91
+ locals_hide_sunder = (
92
+ True
93
+ if (traceback_console .is_jupyter and locals_hide_sunder is None )
94
+ else locals_hide_sunder
95
+ )
96
+
71
97
def excepthook (
72
98
type_ : Type [BaseException ],
73
99
value : BaseException ,
@@ -83,6 +109,10 @@ def excepthook(
83
109
theme = theme ,
84
110
word_wrap = word_wrap ,
85
111
show_locals = show_locals ,
112
+ locals_max_length = locals_max_length ,
113
+ locals_max_string = locals_max_string ,
114
+ locals_hide_dunder = locals_hide_dunder ,
115
+ locals_hide_sunder = bool (locals_hide_sunder ),
86
116
indent_guides = indent_guides ,
87
117
suppress = suppress ,
88
118
max_frames = max_frames ,
@@ -193,6 +223,8 @@ class Traceback:
193
223
locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.
194
224
Defaults to 10.
195
225
locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.
226
+ locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True.
227
+ locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False.
196
228
suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.
197
229
max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100.
198
230
@@ -209,14 +241,17 @@ class Traceback:
209
241
def __init__ (
210
242
self ,
211
243
trace : Optional [Trace ] = None ,
244
+ * ,
212
245
width : Optional [int ] = 100 ,
213
246
extra_lines : int = 3 ,
214
247
theme : Optional [str ] = None ,
215
248
word_wrap : bool = False ,
216
249
show_locals : bool = False ,
217
- indent_guides : bool = True ,
218
250
locals_max_length : int = LOCALS_MAX_LENGTH ,
219
251
locals_max_string : int = LOCALS_MAX_STRING ,
252
+ locals_hide_dunder : bool = True ,
253
+ locals_hide_sunder : bool = False ,
254
+ indent_guides : bool = True ,
220
255
suppress : Iterable [Union [str , ModuleType ]] = (),
221
256
max_frames : int = 100 ,
222
257
):
@@ -238,6 +273,8 @@ def __init__(
238
273
self .indent_guides = indent_guides
239
274
self .locals_max_length = locals_max_length
240
275
self .locals_max_string = locals_max_string
276
+ self .locals_hide_dunder = locals_hide_dunder
277
+ self .locals_hide_sunder = locals_hide_sunder
241
278
242
279
self .suppress : Sequence [str ] = []
243
280
for suppress_entity in suppress :
@@ -258,14 +295,17 @@ def from_exception(
258
295
exc_type : Type [Any ],
259
296
exc_value : BaseException ,
260
297
traceback : Optional [TracebackType ],
298
+ * ,
261
299
width : Optional [int ] = 100 ,
262
300
extra_lines : int = 3 ,
263
301
theme : Optional [str ] = None ,
264
302
word_wrap : bool = False ,
265
303
show_locals : bool = False ,
266
- indent_guides : bool = True ,
267
304
locals_max_length : int = LOCALS_MAX_LENGTH ,
268
305
locals_max_string : int = LOCALS_MAX_STRING ,
306
+ locals_hide_dunder : bool = True ,
307
+ locals_hide_sunder : bool = False ,
308
+ indent_guides : bool = True ,
269
309
suppress : Iterable [Union [str , ModuleType ]] = (),
270
310
max_frames : int = 100 ,
271
311
) -> "Traceback" :
@@ -284,6 +324,8 @@ def from_exception(
284
324
locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.
285
325
Defaults to 10.
286
326
locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.
327
+ locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True.
328
+ locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False.
287
329
suppress (Iterable[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.
288
330
max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100.
289
331
@@ -297,6 +339,8 @@ def from_exception(
297
339
show_locals = show_locals ,
298
340
locals_max_length = locals_max_length ,
299
341
locals_max_string = locals_max_string ,
342
+ locals_hide_dunder = locals_hide_dunder ,
343
+ locals_hide_sunder = locals_hide_sunder ,
300
344
)
301
345
return cls (
302
346
rich_traceback ,
@@ -308,6 +352,8 @@ def from_exception(
308
352
indent_guides = indent_guides ,
309
353
locals_max_length = locals_max_length ,
310
354
locals_max_string = locals_max_string ,
355
+ locals_hide_dunder = locals_hide_dunder ,
356
+ locals_hide_sunder = locals_hide_sunder ,
311
357
suppress = suppress ,
312
358
max_frames = max_frames ,
313
359
)
@@ -318,9 +364,12 @@ def extract(
318
364
exc_type : Type [BaseException ],
319
365
exc_value : BaseException ,
320
366
traceback : Optional [TracebackType ],
367
+ * ,
321
368
show_locals : bool = False ,
322
369
locals_max_length : int = LOCALS_MAX_LENGTH ,
323
370
locals_max_string : int = LOCALS_MAX_STRING ,
371
+ locals_hide_dunder : bool = True ,
372
+ locals_hide_sunder : bool = False ,
324
373
) -> Trace :
325
374
"""Extract traceback information.
326
375
@@ -332,6 +381,8 @@ def extract(
332
381
locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.
333
382
Defaults to 10.
334
383
locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.
384
+ locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True.
385
+ locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False.
335
386
336
387
Returns:
337
388
Trace: A Trace instance which you can use to construct a `Traceback`.
@@ -368,13 +419,28 @@ def safe_str(_object: Any) -> str:
368
419
stacks .append (stack )
369
420
append = stack .frames .append
370
421
422
+ def get_locals (
423
+ iter_locals : Iterable [Tuple [str , object ]]
424
+ ) -> Iterable [Tuple [str , object ]]:
425
+ """Extract locals from an iterator of key pairs."""
426
+ if not (locals_hide_dunder or locals_hide_sunder ):
427
+ yield from iter_locals
428
+ return
429
+ for key , value in iter_locals :
430
+ if locals_hide_dunder and key .startswith ("__" ):
431
+ continue
432
+ if locals_hide_sunder and key .startswith ("_" ):
433
+ continue
434
+ yield key , value
435
+
371
436
for frame_summary , line_no in walk_tb (traceback ):
372
437
filename = frame_summary .f_code .co_filename
373
438
if filename and not filename .startswith ("<" ):
374
439
if not os .path .isabs (filename ):
375
440
filename = os .path .join (_IMPORT_CWD , filename )
376
441
if frame_summary .f_locals .get ("_rich_traceback_omit" , False ):
377
442
continue
443
+
378
444
frame = Frame (
379
445
filename = filename or "?" ,
380
446
lineno = line_no ,
@@ -385,7 +451,7 @@ def safe_str(_object: Any) -> str:
385
451
max_length = locals_max_length ,
386
452
max_string = locals_max_string ,
387
453
)
388
- for key , value in frame_summary .f_locals .items ()
454
+ for key , value in get_locals ( frame_summary .f_locals .items () )
389
455
}
390
456
if show_locals
391
457
else None ,
@@ -500,13 +566,14 @@ def _render_syntax_error(self, syntax_error: _SyntaxError) -> RenderResult:
500
566
highlighter = ReprHighlighter ()
501
567
path_highlighter = PathHighlighter ()
502
568
if syntax_error .filename != "<stdin>" :
503
- text = Text .assemble (
504
- (f" { syntax_error .filename } " , "pygments.string" ),
505
- (":" , "pygments.text" ),
506
- (str (syntax_error .lineno ), "pygments.number" ),
507
- style = "pygments.text" ,
508
- )
509
- yield path_highlighter (text )
569
+ if os .path .exists (syntax_error .filename ):
570
+ text = Text .assemble (
571
+ (f" { syntax_error .filename } " , "pygments.string" ),
572
+ (":" , "pygments.text" ),
573
+ (str (syntax_error .lineno ), "pygments.number" ),
574
+ style = "pygments.text" ,
575
+ )
576
+ yield path_highlighter (text )
510
577
syntax_error_text = highlighter (syntax_error .line .rstrip ())
511
578
syntax_error_text .no_wrap = True
512
579
offset = min (syntax_error .offset - 1 , len (syntax_error_text ))
@@ -537,7 +604,6 @@ def _guess_lexer(cls, filename: str, code: str) -> str:
537
604
def _render_stack (self , stack : Stack ) -> RenderResult :
538
605
path_highlighter = PathHighlighter ()
539
606
theme = self .theme
540
- code_cache : Dict [str , str ] = {}
541
607
542
608
def read_code (filename : str ) -> str :
543
609
"""Read files, and cache results on filename.
@@ -548,11 +614,7 @@ def read_code(filename: str) -> str:
548
614
Returns:
549
615
str: Contents of file
550
616
"""
551
- code = code_cache .get (filename )
552
- if code is None :
553
- code = Path (filename ).read_text (encoding = "utf-8" , errors = "replace" )
554
- code_cache [filename ] = code
555
- return code
617
+ return "" .join (linecache .getlines (filename ))
556
618
557
619
def render_locals (frame : Frame ) -> Iterable [ConsoleRenderable ]:
558
620
if frame .locals :
@@ -591,14 +653,17 @@ def render_locals(frame: Frame) -> Iterable[ConsoleRenderable]:
591
653
frame_filename = frame .filename
592
654
suppressed = any (frame_filename .startswith (path ) for path in self .suppress )
593
655
594
- text = Text .assemble (
595
- path_highlighter (Text (frame .filename , style = "pygments.string" )),
596
- (":" , "pygments.text" ),
597
- (str (frame .lineno ), "pygments.number" ),
598
- " in " ,
599
- (frame .name , "pygments.function" ),
600
- style = "pygments.text" ,
601
- )
656
+ if os .path .exists (frame .filename ):
657
+ text = Text .assemble (
658
+ path_highlighter (Text (frame .filename , style = "pygments.string" )),
659
+ (":" , "pygments.text" ),
660
+ (str (frame .lineno ), "pygments.number" ),
661
+ " in " ,
662
+ (frame .name , "pygments.function" ),
663
+ style = "pygments.text" ,
664
+ )
665
+ else :
666
+ text = Text .assemble ("in " , (frame .name , "pygments.function" ))
602
667
if not frame .filename .startswith ("<" ) and not first :
603
668
yield ""
604
669
yield text
0 commit comments