Skip to content

Commit f3f1904

Browse files
cpenningtonddfisher
authored andcommitted
Add coverage reporting (#2293)
Adds coverage reporting to CI, uploaded to codecov.io. To get coverage locally, use `./runtests.py --coverage`.
1 parent 50163d6 commit f3f1904

File tree

7 files changed

+47
-12
lines changed

7 files changed

+47
-12
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,7 @@ docs/build/
2323

2424
# Operating Systems
2525
.DS_store
26+
27+
# Coverage Files
28+
htmlcov
29+
.coverage*

.travis.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,9 @@ install:
1313
- python setup.py install
1414

1515
script:
16-
- python runtests.py
16+
- coverage erase
17+
- python runtests.py --coverage
18+
- coverage combine
19+
20+
after_success:
21+
- bash <(curl -s https://codecov.io/bash)

conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pytest_plugins = [
22
'mypy.test.data',
3+
'pytest_cov',
34
]

pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ python_classes =
1111
python_functions =
1212

1313
# always run in parallel (requires pytest-xdist, see test-requirements.txt)
14-
addopts = -nauto
14+
addopts = -nauto --cov-append --cov-report=

runtests.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class Driver:
4040

4141
def __init__(self, whitelist: List[str], blacklist: List[str],
4242
arglist: List[str], verbosity: int, parallel_limit: int,
43-
xfail: List[str]) -> None:
43+
xfail: List[str], coverage: bool) -> None:
4444
self.whitelist = whitelist
4545
self.blacklist = blacklist
4646
self.arglist = arglist
@@ -50,6 +50,7 @@ def __init__(self, whitelist: List[str], blacklist: List[str],
5050
self.cwd = os.getcwd()
5151
self.mypy = os.path.join(self.cwd, 'scripts', 'mypy')
5252
self.env = dict(os.environ)
53+
self.coverage = coverage
5354

5455
def prepend_path(self, name: str, paths: List[str]) -> None:
5556
old_val = self.env.get(name)
@@ -94,11 +95,15 @@ def add_mypy_package(self, name: str, packagename: str, *flags: str) -> None:
9495
def add_mypy_string(self, name: str, *args: str, cwd: Optional[str] = None) -> None:
9596
self.add_mypy_cmd(name, ['-c'] + list(args), cwd=cwd)
9697

97-
def add_pytest(self, name: str, pytest_args: List[str]) -> None:
98+
def add_pytest(self, name: str, pytest_args: List[str], coverage: bool = False) -> None:
9899
full_name = 'pytest %s' % name
99100
if not self.allow(full_name):
100101
return
101-
args = [sys.executable, '-m', 'pytest'] + pytest_args
102+
if coverage and self.coverage:
103+
args = [sys.executable, '-m', 'pytest', '--cov=mypy'] + pytest_args
104+
else:
105+
args = [sys.executable, '-m', 'pytest'] + pytest_args
106+
102107
self.waiter.add(LazySubprocess(full_name, args, env=self.env))
103108

104109
def add_python(self, name: str, *args: str, cwd: Optional[str] = None) -> None:
@@ -110,12 +115,16 @@ def add_python(self, name: str, *args: str, cwd: Optional[str] = None) -> None:
110115
env = self.env
111116
self.waiter.add(LazySubprocess(name, largs, cwd=cwd, env=env))
112117

113-
def add_python_mod(self, name: str, *args: str, cwd: Optional[str] = None) -> None:
118+
def add_python_mod(self, name: str, *args: str, cwd: Optional[str] = None,
119+
coverage: bool = False) -> None:
114120
name = 'run %s' % name
115121
if not self.allow(name):
116122
return
117123
largs = list(args)
118-
largs[0:0] = [sys.executable, '-m']
124+
if coverage and self.coverage:
125+
largs[0:0] = ['coverage', 'run', '-m']
126+
else:
127+
largs[0:0] = [sys.executable, '-m']
119128
env = self.env
120129
self.waiter.add(LazySubprocess(name, largs, cwd=cwd, env=env))
121130

@@ -203,7 +212,7 @@ def add_imports(driver: Driver) -> None:
203212

204213
def add_pytest(driver: Driver) -> None:
205214
for f in PYTEST_FILES:
206-
driver.add_pytest(f, [f] + driver.arglist)
215+
driver.add_pytest(f, [f] + driver.arglist, True)
207216

208217

209218
def add_myunit(driver: Driver) -> None:
@@ -218,17 +227,20 @@ def add_myunit(driver: Driver) -> None:
218227
# This module has been converted to pytest; don't try to use myunit.
219228
pass
220229
else:
221-
driver.add_python_mod('unit-test %s' % mod, 'mypy.myunit', '-m', mod, *driver.arglist)
230+
driver.add_python_mod('unit-test %s' % mod, 'mypy.myunit', '-m', mod,
231+
*driver.arglist, coverage=True)
222232

223233

224234
def add_pythoneval(driver: Driver) -> None:
225235
driver.add_python_mod('eval-test', 'mypy.myunit',
226-
'-m', 'mypy.test.testpythoneval', *driver.arglist)
236+
'-m', 'mypy.test.testpythoneval', *driver.arglist,
237+
coverage=True)
227238

228239

229240
def add_cmdline(driver: Driver) -> None:
230241
driver.add_python_mod('cmdline-test', 'mypy.myunit',
231-
'-m', 'mypy.test.testcmdline', *driver.arglist)
242+
'-m', 'mypy.test.testcmdline', *driver.arglist,
243+
coverage=True)
232244

233245

234246
def add_stubs(driver: Driver) -> None:
@@ -288,6 +300,7 @@ def usage(status: int) -> None:
288300
print(' -l, --list list included tasks (after filtering) and exit')
289301
print(' FILTER include tasks matching FILTER')
290302
print(' -x, --exclude FILTER exclude tasks matching FILTER')
303+
print(' -c, --coverage calculate code coverage while running tests')
291304
print(' -- treat all remaining arguments as positional')
292305
sys.exit(status)
293306

@@ -316,6 +329,7 @@ def main() -> None:
316329
blacklist = [] # type: List[str]
317330
arglist = [] # type: List[str]
318331
list_only = False
332+
coverage = False
319333

320334
allow_opts = True
321335
curlist = whitelist
@@ -340,6 +354,8 @@ def main() -> None:
340354
curlist = arglist
341355
elif a == '-l' or a == '--list':
342356
list_only = True
357+
elif a == '-c' or a == '--coverage':
358+
coverage = True
343359
elif a == '-h' or a == '--help':
344360
usage(0)
345361
else:
@@ -356,7 +372,7 @@ def main() -> None:
356372
whitelist.append('')
357373

358374
driver = Driver(whitelist=whitelist, blacklist=blacklist, arglist=arglist,
359-
verbosity=verbosity, parallel_limit=parallel_limit, xfail=[])
375+
verbosity=verbosity, parallel_limit=parallel_limit, xfail=[], coverage=coverage)
360376

361377
driver.prepend_path('PATH', [join(driver.cwd, 'scripts')])
362378
driver.prepend_path('MYPYPATH', [driver.cwd])

setup.cfg

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,11 @@ exclude = mypy/codec/*
1111
# E704: multiple statements on one line (def)
1212
# E402: module level import not at top of file
1313
ignore = E251,E128,F401,W601,E701,W503,E704,E402
14+
15+
[coverage:run]
16+
branch = true
17+
source = mypy
18+
parallel = true
19+
20+
[coverage:report]
21+
show_missing = true

test-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ flake8
22
typed-ast
33
pytest>=2.8
44
pytest-xdist>=1.13
5+
pytest-cov>=2.4.0

0 commit comments

Comments
 (0)