summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorreybog90 <reybog90@o2.pl>2019-10-30 20:04:20 +0100
committerNed Batchelder <ned@nedbatchelder.com>2019-11-01 06:36:13 -0400
commit9b11268c358040abf7384702c3bc0e863ab753c5 (patch)
treee657af6f7eb583354f41c455bee639aaaf9a39fa
parent49e06d33ea63d8e3e44ab5b69d713783551dfaa9 (diff)
downloadpython-coveragepy-git-9b11268c358040abf7384702c3bc0e863ab753c5.tar.gz
Optionally skip empty files in reports
-rw-r--r--coverage/cmdline.py9
-rw-r--r--coverage/config.py2
-rw-r--r--coverage/control.py11
-rw-r--r--coverage/html.py6
-rw-r--r--coverage/summary.py9
-rw-r--r--doc/config.rst5
-rw-r--r--tests/test_api.py3
-rw-r--r--tests/test_cmdline.py9
-rw-r--r--tests/test_config.py2
-rw-r--r--tests/test_html.py14
-rw-r--r--tests/test_summary.py45
11 files changed, 110 insertions, 5 deletions
diff --git a/coverage/cmdline.py b/coverage/cmdline.py
index 66d4dc3c..ef1184d0 100644
--- a/coverage/cmdline.py
+++ b/coverage/cmdline.py
@@ -93,6 +93,10 @@ class Opts(object):
'--skip-covered', action='store_true',
help="Skip files with 100% coverage.",
)
+ skip_empty = optparse.make_option(
+ '--skip-empty', action='store_true',
+ help="Skip empty files.",
+ )
show_contexts = optparse.make_option(
'--show-contexts', action='store_true',
help="Show contexts for covered lines.",
@@ -203,6 +207,7 @@ class CoverageOptionParser(optparse.OptionParser, object):
rcfile=True,
show_missing=None,
skip_covered=None,
+ skip_empty=None,
show_contexts=None,
source=None,
timid=None,
@@ -354,6 +359,7 @@ CMDS = {
Opts.omit,
Opts.title,
Opts.skip_covered,
+ Opts.skip_empty,
Opts.show_contexts,
Opts.contexts,
] + GLOBAL_ARGS,
@@ -375,6 +381,7 @@ CMDS = {
Opts.contexts,
Opts.show_missing,
Opts.skip_covered,
+ Opts.skip_empty,
] + GLOBAL_ARGS,
usage="[options] [modules]",
description="Report coverage statistics on modules."
@@ -575,6 +582,7 @@ class CoverageScript(object):
total = self.coverage.report(
show_missing=options.show_missing,
skip_covered=options.skip_covered,
+ skip_empty=options.skip_empty,
**report_args
)
elif options.action == "annotate":
@@ -584,6 +592,7 @@ class CoverageScript(object):
directory=options.directory,
title=options.title,
skip_covered=options.skip_covered,
+ skip_empty=options.skip_empty,
show_contexts=options.show_contexts,
**report_args
)
diff --git a/coverage/config.py b/coverage/config.py
index 7d691145..c6689d2d 100644
--- a/coverage/config.py
+++ b/coverage/config.py
@@ -205,6 +205,7 @@ class CoverageConfig(object):
self.report_contexts = None
self.show_missing = False
self.skip_covered = False
+ self.skip_empty = False
# Defaults for [html]
self.extra_css = None
@@ -362,6 +363,7 @@ class CoverageConfig(object):
('report_omit', 'report:omit', 'list'),
('show_missing', 'report:show_missing', 'boolean'),
('skip_covered', 'report:skip_covered', 'boolean'),
+ ('skip_empty', 'report:skip_empty', 'boolean'),
('sort', 'report:sort'),
# [html]
diff --git a/coverage/control.py b/coverage/control.py
index 7be28413..ff015882 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -774,7 +774,7 @@ class Coverage(object):
def report(
self, morfs=None, show_missing=None, ignore_errors=None,
file=None, omit=None, include=None, skip_covered=None,
- contexts=None,
+ contexts=None, skip_empty=None,
):
"""Write a textual summary report to `file`.
@@ -794,6 +794,9 @@ class Coverage(object):
If `skip_covered` is true, don't report on files with 100% coverage.
+ If `skip_empty` is true, don't report on empty files (those that have
+ no statements).
+
`contexts` is a list of regular expressions. Only data from
:ref:`dynamic contexts <dynamic_contexts>` that match one of those
expressions (using :func:`re.search <python:re.search>`) will be
@@ -815,7 +818,7 @@ class Coverage(object):
self,
ignore_errors=ignore_errors, report_omit=omit, report_include=include,
show_missing=show_missing, skip_covered=skip_covered,
- report_contexts=contexts,
+ report_contexts=contexts, skip_empty=skip_empty,
):
reporter = SummaryReporter(self)
return reporter.report(morfs, outfile=file)
@@ -843,7 +846,8 @@ class Coverage(object):
def html_report(self, morfs=None, directory=None, ignore_errors=None,
omit=None, include=None, extra_css=None, title=None,
- skip_covered=None, show_contexts=None, contexts=None):
+ skip_covered=None, show_contexts=None, contexts=None,
+ skip_empty=None):
"""Generate an HTML report.
The HTML is written to `directory`. The file "index.html" is the
@@ -871,6 +875,7 @@ class Coverage(object):
ignore_errors=ignore_errors, report_omit=omit, report_include=include,
html_dir=directory, extra_css=extra_css, html_title=title,
skip_covered=skip_covered, show_contexts=show_contexts, report_contexts=contexts,
+ skip_empty=skip_empty,
):
reporter = HtmlReporter(self)
return reporter.report(morfs)
diff --git a/coverage/html.py b/coverage/html.py
index 4a0e1a33..e3b814c5 100644
--- a/coverage/html.py
+++ b/coverage/html.py
@@ -282,6 +282,12 @@ class HtmlReporter(object):
file_be_gone(html_path)
return
+ if self.config.skip_empty:
+ # Don't report on empty files.
+ if nums.n_statements == 0:
+ file_be_gone(html_path)
+ return
+
# Find out if the file on disk is already correct.
if self.incr.can_skip_file(self.data, fr, rootname):
self.file_summaries.append(self.incr.index_info(rootname))
diff --git a/coverage/summary.py b/coverage/summary.py
index 08c8a947..97d9fff0 100644
--- a/coverage/summary.py
+++ b/coverage/summary.py
@@ -21,6 +21,7 @@ class SummaryReporter(object):
self.outfile = None
self.fr_analysis = []
self.skipped_count = 0
+ self.empty_count = 0
self.total = Numbers()
self.fmt_err = u"%s %s: %s"
@@ -48,6 +49,7 @@ class SummaryReporter(object):
max_name = max([len(fr.relative_filename()) for (fr, analysis) in self.fr_analysis] + [5])
fmt_name = u"%%- %ds " % max_name
fmt_skip_covered = u"\n%s file%s skipped due to complete coverage."
+ fmt_skip_empty = u"\n%s empty file%s skipped."
header = (fmt_name % "Name") + u" Stmts Miss"
fmt_coverage = fmt_name + u"%6d %6d"
@@ -129,6 +131,10 @@ class SummaryReporter(object):
self.writeout(
fmt_skip_covered % (self.skipped_count, 's' if self.skipped_count > 1 else '')
)
+ if self.config.skip_empty and self.empty_count:
+ self.writeout(
+ fmt_skip_empty % (self.empty_count, 's' if self.empty_count > 1 else '')
+ )
return self.total.n_statements and self.total.pc_covered
@@ -142,5 +148,8 @@ class SummaryReporter(object):
if self.config.skip_covered and no_missing_lines and no_missing_branches:
# Don't report on 100% files.
self.skipped_count += 1
+ elif self.config.skip_empty and nums.n_statements == 0:
+ # Don't report on empty files.
+ self.empty_count += 1
else:
self.fr_analysis.append((fr, analysis))
diff --git a/doc/config.rst b/doc/config.rst
index e332f50a..d7623532 100644
--- a/doc/config.rst
+++ b/doc/config.rst
@@ -294,6 +294,11 @@ missing lines. See :ref:`cmd_summary` for more information.
``skip_covered`` (boolean, default False): Don't include files in the report
that are 100% covered files. See :ref:`cmd_summary` for more information.
+.. _config_report_skip_empty:
+
+``skip_empty`` (boolean, default False): Don't include empty files (those that
+have 0 statements) in the report. See :ref:`cmd_summary` for more information.
+
.. _config_report_sort:
``sort`` (string, default "Name"): Sort the text report by the named column.
diff --git a/tests/test_api.py b/tests/test_api.py
index b2143548..6455d097 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -904,7 +904,8 @@ class TestRunnerPluginTest(CoverageTest):
cov.combine()
cov.save()
report = StringIO()
- cov.report(show_missing=None, ignore_errors=True, file=report, skip_covered=None)
+ cov.report(show_missing=None, ignore_errors=True, file=report, skip_covered=None,
+ skip_empty=None)
self.assertEqual(report.getvalue(), textwrap.dedent("""\
Name Stmts Miss Cover
-----------------------------
diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py
index 26624b19..666327c8 100644
--- a/tests/test_cmdline.py
+++ b/tests/test_cmdline.py
@@ -37,10 +37,11 @@ class BaseCmdLineTest(CoverageTest):
_defaults.Coverage().html_report(
directory=None, ignore_errors=None, include=None, omit=None, morfs=[],
skip_covered=None, show_contexts=None, title=None, contexts=None,
+ skip_empty=None,
)
_defaults.Coverage().report(
ignore_errors=None, include=None, omit=None, morfs=[],
- show_missing=None, skip_covered=None, contexts=None,
+ show_missing=None, skip_covered=None, contexts=None, skip_empty=None,
)
_defaults.Coverage().xml_report(
ignore_errors=None, include=None, omit=None, morfs=[], outfile=None,
@@ -261,6 +262,7 @@ class CmdLineTest(BaseCmdLineTest):
out = self.stdout()
self.assertIn("cover_pylib:", out)
self.assertIn("skip_covered:", out)
+ self.assertIn("skip_empty:", out)
def test_erase(self):
# coverage erase
@@ -370,6 +372,11 @@ class CmdLineTest(BaseCmdLineTest):
cov.load()
cov.report(skip_covered=True)
""")
+ self.cmd_executes("report --skip-empty", """\
+ cov = Coverage()
+ cov.load()
+ cov.report(skip_empty=True)
+ """)
self.cmd_executes("report --contexts=foo,bar", """\
cov = Coverage()
cov.load()
diff --git a/tests/test_config.py b/tests/test_config.py
index ebea18a7..fcbac816 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -311,6 +311,7 @@ class ConfigFileTest(UsingModulesMixin, CoverageTest):
show_missing= TruE
skip_covered = TruE
+ skip_empty =TruE
[{section}html]
@@ -386,6 +387,7 @@ class ConfigFileTest(UsingModulesMixin, CoverageTest):
self.assertEqual(cov.config.plugins, ["plugins.a_plugin", "plugins.another"])
self.assertTrue(cov.config.show_missing)
self.assertTrue(cov.config.skip_covered)
+ self.assertTrue(cov.config.skip_empty)
self.assertEqual(cov.config.html_dir, r"c:\tricky\dir.somewhere")
self.assertEqual(cov.config.extra_css, "something/extra.css")
self.assertEqual(cov.config.html_title, "Title & nums # nums!")
diff --git a/tests/test_html.py b/tests/test_html.py
index 77e068d0..74cc15d9 100644
--- a/tests/test_html.py
+++ b/tests/test_html.py
@@ -533,6 +533,20 @@ class HtmlTest(HtmlTestHelpers, CoverageTest):
self.assert_doesnt_exist("htmlcov/main_file_py.html")
self.assert_exists("htmlcov/not_covered_py.html")
+ def test_report_skip_empty_files(self):
+ self.make_file("submodule/__init__.py", "")
+ self.make_file("main_file.py", """
+ import submodule
+
+ def normal():
+ print("z")
+ normal()
+ """)
+ self.run_coverage(htmlargs=dict(skip_empty=True))
+ self.assert_exists("htmlcov/index.html")
+ self.assert_exists("htmlcov/main_file_py.html")
+ self.assert_doesnt_exist("htmlcov/submodule___init___py.html")
+
class HtmlStaticFileTest(CoverageTest):
"""Tests of the static file copying for the HTML report."""
diff --git a/tests/test_summary.py b/tests/test_summary.py
index b25c7764..01b6f9d0 100644
--- a/tests/test_summary.py
+++ b/tests/test_summary.py
@@ -431,6 +431,51 @@ class SummaryTest(UsingModulesMixin, CoverageTest):
squeezed = self.squeezed_lines(report)
self.assertEqual(squeezed[0], "No data to report.")
+ def test_report_skip_empty(self):
+ self.make_file("main.py", """
+ import submodule
+
+ def normal():
+ print("z")
+ normal()
+ """)
+ self.make_file("submodule/__init__.py", "")
+ self.omit_site_packages()
+ out = self.run_command("coverage run main.py")
+ self.assertEqual(out, "z\n")
+ report = self.report_from_command("coverage report --skip-empty")
+
+ # Name Stmts Miss Cover
+ # ------------------------------------
+ # main.py 4 0 100%
+ # ------------------------------------
+ # TOTAL 4 0 100%
+ #
+ # 1 empty file skipped.
+
+ self.assertEqual(self.line_count(report), 7, report)
+ squeezed = self.squeezed_lines(report)
+ self.assertEqual(squeezed[2], "main.py 4 0 100%")
+ self.assertEqual(squeezed[4], "TOTAL 4 0 100%")
+ self.assertEqual(squeezed[6], "1 empty file skipped.")
+ self.assertEqual(self.last_command_status, 0)
+
+ def test_report_skip_empty_no_data(self):
+ self.make_file("__init__.py", "")
+ self.omit_site_packages()
+ out = self.run_command("coverage run __init__.py")
+ self.assertEqual(out, "")
+ report = self.report_from_command("coverage report --skip-empty")
+
+ # Name Stmts Miss Cover
+ # ------------------------------------
+ #
+ # 1 empty file skipped.
+
+ self.assertEqual(self.line_count(report), 4, report)
+ lines = self.report_lines(report)
+ self.assertEqual(lines[3], "1 empty file skipped.")
+
def test_report_precision(self):
self.make_file(".coveragerc", """\
[report]