Skip to content

Commit 01ddc3d

Browse files
committed
Initial commit.
0 parents  commit 01ddc3d

File tree

5 files changed

+189
-0
lines changed

5 files changed

+189
-0
lines changed

.gitignore

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Deployment files
2+
*.egg-info
3+
dist
4+
5+
# Environment files
6+
site-packages
7+
*.py[cod]
8+
9+
# OS-specific files
10+
.DS_Store
11+
Desktop.ini
12+
Thumbs.db

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Glance
2+
======
3+
4+
Highlight stack traces so you can glance at logs or the terminal
5+
to quickly get to the root of an issue.

glanceback.py

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import os
2+
import re
3+
import sys
4+
5+
from colorama import Fore, Style, init
6+
7+
8+
LOCATION_PATTERN = 'File "{}", line {}, in {}'
9+
LOCATION_RE = re.compile(LOCATION_PATTERN.format(
10+
r'(.*)', r'(\d+)', r'(.*)'))
11+
12+
13+
EXAMPLE = """
14+
..Some output text.
15+
..Traceback (most recent call last):
16+
.. File "C:\Users\Joe\Development\Repositories\glance\glanceback.py", line 12, in <module>
17+
.. highlight_traceback()
18+
..TypeError: highlight_traceback() takes exactly 1 argument (0 given)
19+
"""
20+
21+
22+
def main(args=None):
23+
if args is None:
24+
args = sys.argv[1:]
25+
26+
init()
27+
28+
# Read input
29+
if args and args[0] == '--':
30+
s = ' '.join(args[1:])
31+
elif args:
32+
# TODO: system call
33+
pass
34+
else:
35+
s = sys.stdin.read()
36+
37+
# Highlight output
38+
print(highlight_traceback(s))
39+
40+
41+
def highlight(s, style='', start=0, end=None, bright=True, reset=None):
42+
# TODO: Background highlighting spanning the terminal length?
43+
if bright:
44+
style = Style.BRIGHT + style
45+
if end is None:
46+
end = len(s)
47+
if reset is None:
48+
reset = Style.RESET_ALL
49+
return s[:start] + style + s[start:end] + reset + s[end:]
50+
51+
52+
def highlight_traceback(s, cwd=None):
53+
if cwd is None:
54+
cwd = os.getcwd()
55+
56+
# Find traceback string
57+
index = s.find('Traceback (most recent call last):')
58+
if index == -1:
59+
return s
60+
61+
# Remove left column
62+
lastnewline = s.rfind('\n', 0, index)
63+
linestart = index - lastnewline - 1 if lastnewline != -1 else 0
64+
tracebackstart = index - linestart
65+
66+
pre = s[:tracebackstart - 1]
67+
lines = s[tracebackstart:].split('\n')
68+
69+
# Highlight header
70+
header = lines.pop(0)
71+
header = header[:linestart] + highlight(header[linestart:], Fore.RED)
72+
73+
# Highlight frames
74+
frames = []
75+
iterlines = iter(lines[:-1])
76+
try:
77+
while True:
78+
line = iterlines.next()
79+
column, text = line[:linestart], line[linestart:]
80+
match = LOCATION_RE.search(text)
81+
if not match:
82+
break
83+
84+
path, ln, module = match.group(1), match.group(2), match.group(3)
85+
86+
included = path.startswith(cwd)
87+
if included:
88+
if path.startswith(cwd):
89+
pathindex = len(cwd)
90+
if path[pathindex] == os.path.sep:
91+
pathindex += 1
92+
else:
93+
pathindex = len(path)
94+
lo, hi, br = (Style.BRIGHT + Fore.BLACK,
95+
Style.DIM + Fore.WHITE,
96+
Style.BRIGHT + Fore.WHITE)
97+
lopath, hipath = path[:pathindex], path[pathindex:]
98+
# Highlight text
99+
text = LOCATION_PATTERN.format(
100+
lopath + br + hipath + lo, # Path
101+
br + ln + lo, # Line number
102+
module) # Module name
103+
frames.append(column + lo + text + Style.RESET_ALL)
104+
# Highlight following line too
105+
line = iterlines.next()
106+
column, text = line[:linestart], line[linestart:]
107+
frames.append(column + hi + text + Style.RESET_ALL)
108+
else:
109+
# Lowlight text
110+
frames.append(column + highlight(text, Fore.RED, bright=False))
111+
# Lowlight following line too
112+
line = iterlines.next()
113+
column, text = line[:linestart], line[linestart:]
114+
frames.append(column + highlight(text, Fore.RED, bright=False))
115+
except StopIteration:
116+
pass
117+
118+
# Highlight error message
119+
column, text = lines[-1][:linestart], lines[-1][linestart:]
120+
#footer = column + highlight(text, Fore.MAGENTA)
121+
# TODO: Split the colors on the last line?
122+
footer = column + highlight(text, Fore.MAGENTA)
123+
if ':' in footer:
124+
footer = highlight(footer, Fore.WHITE, footer.find(':') + 1)
125+
126+
# TODO: Look for color escape codes in 'pre' and restore to them
127+
post = ''
128+
129+
return '\n'.join([pre, header] + frames + [footer, post])
130+
131+
132+
if __name__ == '__main__':
133+
main(['--', EXAMPLE.strip()])

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
colorama==0.3.3

setup.py

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
Glance
3+
------
4+
5+
Highlight stack traces in the terminal for easier glancing.
6+
7+
8+
Links
9+
`````
10+
11+
* `Website <http://github.com/joeyespo/glance>`_
12+
13+
"""
14+
15+
import os
16+
from setuptools import setup, find_packages
17+
18+
19+
def read(filename):
20+
with open(os.path.join(os.path.dirname(__file__), filename)) as f:
21+
return f.read()
22+
23+
24+
setup(
25+
name='glance',
26+
version='0.0.1',
27+
description='Highlight stack traces in the terminal for easier glancing.',
28+
long_description=__doc__,
29+
author='Joe Esposito',
30+
author_email='[email protected]',
31+
url='http://github.com/joeyespo/glance',
32+
license='MIT',
33+
platforms='any',
34+
packages=find_packages(),
35+
install_requires=read('requirements.txt').splitlines(),
36+
zip_safe=False,
37+
entry_points={'console_scripts': ['glance = glanceback:main']},
38+
)

0 commit comments

Comments
 (0)