-
Notifications
You must be signed in to change notification settings - Fork 0
/
trace.py
114 lines (85 loc) · 2.91 KB
/
trace.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
from __future__ import print_function
import sys
import os
import runpy
from traceback import format_exception, extract_tb
import pprint
import functools
stderr = functools.partial(print, file=sys.stderr)
# def stack_trace_here(exit=None):
def limited_repr(value, limit):
etc = ' (...)'
limit -= len(etc)
repr_ = repr(value)
if len(repr_) > limit:
return repr_[:limit] + etc
else:
return repr_
def _print_locals(frame):
locals = frame.f_locals
def is_not_dunder(name):
return not(name.startswith('__') and name.endswith('__'))
for name in filter(is_not_dunder, locals):
length = len(name)
padded_name = name + ((16 - length) * ' ' if length < 16 else '')
repr_ = limited_repr(locals[name], 70 - len(padded_name) - 1)
stderr(padded_name, repr_)
def _print_surrounding_lines(filename, lineno):
import linecache
for i in range(lineno - 3, lineno + 3):
line = linecache.getline(filename, i).rstrip()
if i == lineno:
stderr('%4d>%s' % (i, line))
else:
stderr(' %s' % line)
def _iterate_trace(trace):
while trace:
yield trace
trace = trace.tb_next
def _exception_handler(type_, exception, traceback):
frames = _iterate_trace(traceback)
formatted = format_exception(type_, exception, traceback)
exc_title, lines, exc_pretty = formatted[0], formatted[1:-1], formatted[-1]
exc_title, exc_pretty = exc_title.strip('\n'), exc_pretty.strip('\n')
lineids = ((filename, lineno) for filename, lineno, _, _ in extract_tb(traceback))
stderr(exc_title)
for frame, line, lineid in zip(frames, lines, lineids):
stderr('-> ', line.strip().splitlines()[0])
_print_surrounding_lines(*lineid)
#print '-' * 4, 'locals', '-' * 4
stderr('')
stderr('locals:')
_print_locals(frame.tb_frame)
stderr('-' * 70)
stderr(exc_pretty)
# from pdb
def main():
if not sys.argv[1:] or sys.argv[1] in ("--help", "-h"):
stderr("usage: trace.py scriptfile [arg] ...")
sys.exit(2)
filename = sys.argv[1] # Get script filename
if not os.path.exists(filename):
stderr('Error:', filename, 'does not exist')
sys.exit(1)
del sys.argv[0] # Hide "trace.py" from argument list
# Replace pdb's dir with script's dir in front of module search path.
sys.path[0] = os.path.dirname(filename)
globs = {
"__name__": "__main__",
"__file__": filename,
"__builtins__": __builtins__,
}
sys.excepthook = _exception_handler
runpy.run_path(
filename,
init_globals=globs,
run_name='__main__')
if __name__ == '__main__':
main()
def trace_here(f):
def w(*args, **kw):
oldhoook = sys.excepthook
sys.excepthook = _exception_handler
f(*args, **kw)
sys.excepthook = oldhook
return w