-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathSublimePythonCoverage.py
More file actions
142 lines (101 loc) · 4.43 KB
/
SublimePythonCoverage.py
File metadata and controls
142 lines (101 loc) · 4.43 KB
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# bootstrap
import os
plugin_path = os.path.dirname(__file__)
if not os.path.exists(os.path.join(plugin_path, 'coverage')):
# Fetch coverage.py
print 'SublimePythonCoverage installing coverage.py.'
from StringIO import StringIO
import tarfile
import urllib
from hashlib import md5
SOURCE = 'http://pypi.python.org/packages/source/c/coverage/coverage-3.5.2.tar.gz'
MD5SUM = '28c43d41b13f8987ea14d7b1d4a4e3ec'
payload = urllib.urlopen(SOURCE).read()
if md5(payload).hexdigest() != MD5SUM:
raise ImportError('Invalid checksum.')
tar = tarfile.open(mode='r:gz', fileobj=StringIO(payload))
for m in tar.getmembers():
if not m.name.startswith('coverage-3.5.2/coverage/'):
continue
m.name = '/'.join(m.name.split('/')[2:])
tar.extract(m, os.path.join(plugin_path, 'coverage'))
print 'SublimePythonCoverage successfully installed coverage.py.'
# end bootstrap
import sublime
import sublime_plugin
from utils import get_missing_coverage_lines, find, find_cmd, find_tests
PLUGIN_FILE = os.path.abspath(__file__)
class SublimePythonCoverageListener(sublime_plugin.EventListener):
"""Event listener to highlight uncovered lines when a Python file is loaded."""
def on_load(self, view):
if 'source.python' not in view.scope_name(0):
return
view.run_command('show_python_coverage')
class ShowPythonCoverageCommand(sublime_plugin.TextCommand):
"""Highlight uncovered lines in the current file based on a previous coverage run."""
def run(self, edit):
def get_setting(key, default):
return user_settings.get(key, settings.get(key, default))
user_settings = sublime.load_settings('Python Coverage.sublime-settings')
settings = sublime.load_settings('Preferences.sublime-settings')
use_shell = get_setting('use_shell', False)
python_path = get_setting('python_path', '')
view = self.view
fname = view.file_name()
if not fname:
return
cov_file = find(fname, '.coverage')
if not cov_file:
print 'Could not find .coverage file.'
return
outlines = []
missing_coverage_lines = get_missing_coverage_lines(
fname, cov_file, PLUGIN_FILE,
quiet=False, use_shell=use_shell, python_path=python_path
)
for line in missing_coverage_lines:
outlines.append(view.full_line(view.text_point(line - 1, 0)))
# update highlighted regions
view.erase_regions('SublimePythonCoverage')
if outlines:
view.add_regions('SublimePythonCoverage', outlines,
'markup.inserted', 'bookmark', sublime.HIDDEN)
# manually import the module containing ST2's default build command,
# since it's in a module whose name is a Python keyword :-s
ExecCommand = __import__('exec').ExecCommand
class TestExecCommand(ExecCommand):
"""An generic extension of the default build system which shows coverage at the end."""
runner = None
def cmd(self, runner, testpath):
NotImplemented
def run(self, **kw):
if 'cmd' not in kw:
fname = self.window.active_view().file_name()
# look for a virtualenv with nosetests, py.test etc
runner = find_cmd(fname, self.runner)
if runner is None:
# no virtualenv; maybe there's a global one
runner = self.runner
testpath = find_tests(fname)
if os.path.isdir(testpath):
kw['working_dir'] = testpath
else:
kw['working_dir'] = os.path.dirname(testpath)
kw['cmd'] = self.cmd(runner, testpath)
super(TestExecCommand, self).run(**kw)
def finish(self, proc):
super(TestExecCommand, self).finish(proc)
for view in self.window.views():
view.run_command('show_python_coverage')
class NoseExecCommand(TestExecCommand):
"""An extension of the default build system using the Python Nose test
runner to generate coverage information."""
runner = 'nosetests'
def cmd(self, runner, testpath):
return [runner, '--with-coverage', testpath]
class PytestExecCommand(TestExecCommand):
"""An extension of the default build system using the py.test test
runner to generate coverage information."""
runner = 'py.test'
def cmd(self, runner, testpath):
return [runner]