nedbat / coveragepy

@@ -1325,7 +1325,7 @@
Loading
1325 1325
1326 1326
        # The XML report is always UTF8-encoded.
1327 1327
        out = self.run_command("coverage xml")
1328 -
        assert out == ""
1328 +
        assert out == "Wrote XML report to coverage.xml\n"
1329 1329
        with open("coverage.xml", "rb") as xmlf:
1330 1330
            xml = xmlf.read()
1331 1331
        assert ' filename="h\xe2t.py"'.encode() in xml
@@ -1358,7 +1358,7 @@
Loading
1358 1358
        assert expected % os.sep in index
1359 1359
1360 1360
        # The XML report is always UTF8-encoded.
1361 -
        out = self.run_command("coverage xml")
1361 +
        out = self.run_command("coverage xml -q")
1362 1362
        assert out == ""
1363 1363
        with open("coverage.xml", "rb") as xmlf:
1364 1364
            xml = xmlf.read()

@@ -146,6 +146,10 @@
Loading
146 146
            "reported coverage percentages."
147 147
        ),
148 148
    )
149 +
    quiet = optparse.make_option(
150 +
        '-q', '--quiet', action='store_true',
151 +
        help="Don't print messages about what is happening.",
152 +
    )
149 153
    rcfile = optparse.make_option(
150 154
        '', '--rcfile', action='store',
151 155
        help=(
@@ -227,6 +231,7 @@
Loading
227 231
            parallel_mode=None,
228 232
            precision=None,
229 233
            pylib=None,
234 +
            quiet=None,
230 235
            rcfile=True,
231 236
            show_contexts=None,
232 237
            show_missing=None,
@@ -340,6 +345,7 @@
Loading
340 345
        [
341 346
            Opts.append,
342 347
            Opts.keep,
348 +
            Opts.quiet,
343 349
            ] + GLOBAL_ARGS,
344 350
        usage="[options] <path1> <path2> ... <pathN>",
345 351
        description=(
@@ -387,6 +393,7 @@
Loading
387 393
            Opts.include,
388 394
            Opts.omit,
389 395
            Opts.precision,
396 +
            Opts.quiet,
390 397
            Opts.show_contexts,
391 398
            Opts.skip_covered,
392 399
            Opts.no_skip_covered,
@@ -411,6 +418,7 @@
Loading
411 418
            Opts.omit,
412 419
            Opts.output_json,
413 420
            Opts.json_pretty_print,
421 +
            Opts.quiet,
414 422
            Opts.show_contexts,
415 423
            ] + GLOBAL_ARGS,
416 424
        usage="[options] [modules]",
@@ -463,6 +471,7 @@
Loading
463 471
            Opts.include,
464 472
            Opts.omit,
465 473
            Opts.output_xml,
474 +
            Opts.quiet,
466 475
            Opts.skip_empty,
467 476
            ] + GLOBAL_ARGS,
468 477
        usage="[options] [modules]",
@@ -576,7 +585,7 @@
Loading
576 585
            concurrency=options.concurrency,
577 586
            check_preimported=True,
578 587
            context=options.context,
579 -
            messages=True,
588 +
            messages=not options.quiet,
580 589
            )
581 590
582 591
        if options.action == "debug":

@@ -450,13 +450,8 @@
Loading
450 450
            out = self.run_command(f"coverage run --rcfile=multi.rc multi.py {start_method}")
451 451
            assert out.rstrip() == expected_out
452 452
453 -
            out = self.run_command("coverage combine")
454 -
            out_lines = out.splitlines()
455 -
            assert len(out_lines) == nprocs + 1
456 -
            assert all(
457 -
                re.fullmatch(r"Combined data file \.coverage\..*\.\d+\.\d+", line)
458 -
                for line in out_lines
459 -
            )
453 +
            out = self.run_command("coverage combine -q")   # sneak in a test of -q
454 +
            assert out == ""
460 455
            out = self.run_command("coverage report -m")
461 456
462 457
            last_line = self.squeezed_lines(out)[-1]

@@ -14,6 +14,8 @@
Loading
14 14
class JsonReporter:
15 15
    """A reporter for writing JSON coverage results."""
16 16
17 +
    report_type = "JSON report"
18 +
17 19
    def __init__(self, coverage):
18 20
        self.coverage = coverage
19 21
        self.config = self.coverage.config

@@ -30,6 +30,8 @@
Loading
30 30
class XmlReporter:
31 31
    """A reporter for writing Cobertura-style XML coverage results."""
32 32
33 +
    report_type = "XML report"
34 +
33 35
    def __init__(self, coverage):
34 36
        self.coverage = coverage
35 37
        self.config = self.coverage.config

@@ -13,6 +13,8 @@
Loading
13 13
class FakeReporter:
14 14
    """A fake implementation of a one-file reporter."""
15 15
16 +
    report_type = "fake report file"
17 +
16 18
    def __init__(self, output="", error=False):
17 19
        self.output = output
18 20
        self.error = error
@@ -31,20 +33,26 @@
Loading
31 33
32 34
    def test_stdout(self):
33 35
        fake = FakeReporter(output="Hello!\n")
34 -
        render_report("-", fake, [pytest, "coverage"])
36 +
        msgs = []
37 +
        render_report("-", fake, [pytest, "coverage"], msgs.append)
35 38
        assert fake.morfs == [pytest, "coverage"]
36 39
        assert self.stdout() == "Hello!\n"
40 +
        assert msgs == []
37 41
38 42
    def test_file(self):
39 43
        fake = FakeReporter(output="Gréètings!\n")
40 -
        render_report("output.txt", fake, [])
44 +
        msgs = []
45 +
        render_report("output.txt", fake, [], msgs.append)
41 46
        assert self.stdout() == ""
42 47
        with open("output.txt", "rb") as f:
43 -
            assert f.read() == b"Gr\xc3\xa9\xc3\xa8tings!\n"
48 +
            assert f.read().rstrip() == b"Gr\xc3\xa9\xc3\xa8tings!"
49 +
        assert msgs == ["Wrote fake report file to output.txt"]
44 50
45 51
    def test_exception(self):
46 52
        fake = FakeReporter(error=True)
53 +
        msgs = []
47 54
        with pytest.raises(CoverageException, match="You asked for it!"):
48 -
            render_report("output.txt", fake, [])
55 +
            render_report("output.txt", fake, [], msgs.append)
49 56
        assert self.stdout() == ""
50 57
        self.assert_doesnt_exist("output.txt")
58 +
        assert msgs == []

@@ -234,6 +234,17 @@
Loading
234 234
            cov.combine(None, strict=True, keep=False)
235 235
            cov.save()
236 236
            """)
237 +
        # coverage combine quietly
238 +
        self.cmd_executes("combine -q", """\
239 +
            cov = Coverage(messages=False)
240 +
            cov.combine(None, strict=True, keep=False)
241 +
            cov.save()
242 +
            """)
243 +
        self.cmd_executes("combine --quiet", """\
244 +
            cov = Coverage(messages=False)
245 +
            cov.combine(None, strict=True, keep=False)
246 +
            cov.save()
247 +
            """)
237 248
238 249
    def test_combine_doesnt_confuse_options_with_args(self):
239 250
        # https://github.com/nedbat/coveragepy/issues/385
@@ -335,6 +346,16 @@
Loading
335 346
            cov.load()
336 347
            cov.html_report(title='Hello_there')
337 348
            """)
349 +
        self.cmd_executes("html -q", """\
350 +
            cov = Coverage(messages=False)
351 +
            cov.load()
352 +
            cov.html_report()
353 +
            """)
354 +
        self.cmd_executes("html --quiet", """\
355 +
            cov = Coverage(messages=False)
356 +
            cov.load()
357 +
            cov.html_report()
358 +
            """)
338 359
339 360
    def test_json(self):
340 361
        # coverage json [-i] [--omit DIR,...] [FILE1 FILE2 ...]
@@ -388,6 +409,16 @@
Loading
388 409
            cov.load()
389 410
            cov.json_report(morfs=["mod1", "mod2", "mod3"])
390 411
            """)
412 +
        self.cmd_executes("json -q", """\
413 +
            cov = Coverage(messages=False)
414 +
            cov.load()
415 +
            cov.json_report()
416 +
            """)
417 +
        self.cmd_executes("json --quiet", """\
418 +
            cov = Coverage(messages=False)
419 +
            cov.load()
420 +
            cov.json_report()
421 +
            """)
391 422
392 423
    def test_report(self):
393 424
        # coverage report [-m] [-i] [-o DIR,...] [FILE1 FILE2 ...]
@@ -753,6 +784,16 @@
Loading
753 784
            cov.load()
754 785
            cov.xml_report(morfs=["mod1", "mod2", "mod3"])
755 786
            """)
787 +
        self.cmd_executes("xml -q", """\
788 +
            cov = Coverage(messages=False)
789 +
            cov.load()
790 +
            cov.xml_report()
791 +
            """)
792 +
        self.cmd_executes("xml --quiet", """\
793 +
            cov = Coverage(messages=False)
794 +
            cov.load()
795 +
            cov.xml_report()
796 +
            """)
756 797
757 798
    def test_no_arguments_at_all(self):
758 799
        self.cmd_help("", topic="minimum_help", ret=OK)

@@ -6,7 +6,6 @@
Loading
6 6
import inspect
7 7
import io
8 8
import os.path
9 -
import re
10 9
from xml.etree import ElementTree
11 10
12 11
import pytest
@@ -256,8 +255,8 @@
Loading
256 255
257 256
        out = self.run_command("coverage run main_file.py")
258 257
        assert out == "MAIN\n"
259 -
        out = self.run_command("coverage html")
260 -
        assert re.fullmatch(r"Wrote HTML report to htmlcov[/\\]index.html\n", out)
258 +
        out = self.run_command("coverage html -q")  # sneak in a test of -q
259 +
        assert out == ""
261 260
262 261
263 262
@pytest.mark.skipif(env.C_TRACER, reason="This test is only about PyTracer.")

@@ -1006,7 +1006,7 @@
Loading
1006 1006
            ignore_errors=ignore_errors, report_omit=omit, report_include=include,
1007 1007
            xml_output=outfile, report_contexts=contexts, skip_empty=skip_empty,
1008 1008
        ):
1009 -
            return render_report(self.config.xml_output, XmlReporter(self), morfs)
1009 +
            return render_report(self.config.xml_output, XmlReporter(self), morfs, self._message)
1010 1010
1011 1011
    def json_report(
1012 1012
        self, morfs=None, outfile=None, ignore_errors=None,
@@ -1030,7 +1030,7 @@
Loading
1030 1030
            json_output=outfile, report_contexts=contexts, json_pretty_print=pretty_print,
1031 1031
            json_show_contexts=show_contexts
1032 1032
        ):
1033 -
            return render_report(self.config.json_output, JsonReporter(self), morfs)
1033 +
            return render_report(self.config.json_output, JsonReporter(self), morfs, self._message)
1034 1034
1035 1035
    def sys_info(self):
1036 1036
        """Return a list of (key, value) pairs showing internal information."""

@@ -2,6 +2,7 @@
Loading
2 2
# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
3 3
4 4
"""Reporter foundation for coverage.py."""
5 +
5 6
import sys
6 7
7 8
from coverage.exceptions import CoverageException, NoSource, NotPython
@@ -9,7 +10,7 @@
Loading
9 10
from coverage.misc import ensure_dir_for_file, file_be_gone
10 11
11 12
12 -
def render_report(output_path, reporter, morfs):
13 +
def render_report(output_path, reporter, morfs, msgfn):
13 14
    """Run a one-file report generator, managing the output file.
14 15
15 16
    This function ensures the output file is ready to be written to. Then writes
@@ -40,6 +41,8 @@
Loading
40 41
            file_to_close.close()
41 42
            if delete_file:
42 43
                file_be_gone(output_path)           # pragma: part covered (doesn't return)
44 +
            else:
45 +
                msgfn(f"Wrote {reporter.report_type} to {output_path}")
43 46
44 47
45 48
def get_analysis_to_report(coverage, morfs):
Files Coverage
coverage 90.92%
tests 99.62%
__main__.py 100.00%
Project Totals (90 files) 96.14%

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading