coverage 7.6.10__cp312-cp312-musllinux_1_2_aarch64.whl → 7.12.0__cp312-cp312-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. coverage/__init__.py +3 -1
  2. coverage/__main__.py +3 -1
  3. coverage/annotate.py +2 -3
  4. coverage/bytecode.py +178 -4
  5. coverage/cmdline.py +330 -155
  6. coverage/collector.py +32 -43
  7. coverage/config.py +167 -63
  8. coverage/context.py +5 -6
  9. coverage/control.py +165 -86
  10. coverage/core.py +71 -34
  11. coverage/data.py +4 -5
  12. coverage/debug.py +113 -57
  13. coverage/disposition.py +2 -1
  14. coverage/env.py +29 -78
  15. coverage/exceptions.py +29 -7
  16. coverage/execfile.py +19 -14
  17. coverage/files.py +24 -19
  18. coverage/html.py +118 -75
  19. coverage/htmlfiles/coverage_html.js +12 -10
  20. coverage/htmlfiles/index.html +45 -10
  21. coverage/htmlfiles/pyfile.html +2 -2
  22. coverage/htmlfiles/style.css +54 -6
  23. coverage/htmlfiles/style.scss +85 -3
  24. coverage/inorout.py +62 -45
  25. coverage/jsonreport.py +22 -9
  26. coverage/lcovreport.py +16 -18
  27. coverage/misc.py +51 -47
  28. coverage/multiproc.py +12 -7
  29. coverage/numbits.py +4 -5
  30. coverage/parser.py +150 -251
  31. coverage/patch.py +166 -0
  32. coverage/phystokens.py +25 -26
  33. coverage/plugin.py +14 -14
  34. coverage/plugin_support.py +37 -36
  35. coverage/python.py +13 -14
  36. coverage/pytracer.py +31 -33
  37. coverage/regions.py +3 -2
  38. coverage/report.py +60 -44
  39. coverage/report_core.py +7 -10
  40. coverage/results.py +152 -68
  41. coverage/sqldata.py +261 -211
  42. coverage/sqlitedb.py +37 -29
  43. coverage/sysmon.py +237 -162
  44. coverage/templite.py +19 -7
  45. coverage/tomlconfig.py +13 -13
  46. coverage/tracer.cpython-312-aarch64-linux-musl.so +0 -0
  47. coverage/tracer.pyi +3 -1
  48. coverage/types.py +26 -23
  49. coverage/version.py +4 -19
  50. coverage/xmlreport.py +17 -14
  51. {coverage-7.6.10.dist-info → coverage-7.12.0.dist-info}/METADATA +50 -28
  52. coverage-7.12.0.dist-info/RECORD +59 -0
  53. {coverage-7.6.10.dist-info → coverage-7.12.0.dist-info}/WHEEL +1 -1
  54. coverage-7.6.10.dist-info/RECORD +0 -58
  55. {coverage-7.6.10.dist-info → coverage-7.12.0.dist-info}/entry_points.txt +0 -0
  56. {coverage-7.6.10.dist-info → coverage-7.12.0.dist-info/licenses}/LICENSE.txt +0 -0
  57. {coverage-7.6.10.dist-info → coverage-7.12.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  @charset "UTF-8";
2
2
  /* Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 */
3
- /* For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt */
3
+ /* For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt */
4
4
  /* Don't edit this .css file. Edit the .scss file instead! */
5
5
  html, body, h1, h2, h3, p, table, td, th { margin: 0; padding: 0; border: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; }
6
6
 
@@ -200,9 +200,9 @@ kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em
200
200
 
201
201
  #source p .t .key { font-weight: bold; line-height: 1px; }
202
202
 
203
- #source p .t .str { color: #0451a5; }
203
+ #source p .t .str, #source p .t .fst { color: #0451a5; }
204
204
 
205
- @media (prefers-color-scheme: dark) { #source p .t .str { color: #9cdcfe; } }
205
+ @media (prefers-color-scheme: dark) { #source p .t .str, #source p .t .fst { color: #9cdcfe; } }
206
206
 
207
207
  #source p.mis .t { border-left: 0.2em solid #ff0000; }
208
208
 
@@ -214,6 +214,16 @@ kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em
214
214
 
215
215
  @media (prefers-color-scheme: dark) { #source p.mis.show_mis .t:hover { background: #532323; } }
216
216
 
217
+ #source p.mis.mis2 .t { border-left: 0.2em dotted #ff0000; }
218
+
219
+ #source p.mis.mis2.show_mis .t { background: #ffeeee; }
220
+
221
+ @media (prefers-color-scheme: dark) { #source p.mis.mis2.show_mis .t { background: #351b1b; } }
222
+
223
+ #source p.mis.mis2.show_mis .t:hover { background: #f2d2d2; }
224
+
225
+ @media (prefers-color-scheme: dark) { #source p.mis.mis2.show_mis .t:hover { background: #532323; } }
226
+
217
227
  #source p.run .t { border-left: 0.2em solid #00dd00; }
218
228
 
219
229
  #source p.run.show_run .t { background: #dfd; }
@@ -224,6 +234,16 @@ kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em
224
234
 
225
235
  @media (prefers-color-scheme: dark) { #source p.run.show_run .t:hover { background: #404633; } }
226
236
 
237
+ #source p.run.run2 .t { border-left: 0.2em dotted #00dd00; }
238
+
239
+ #source p.run.run2.show_run .t { background: #eeffee; }
240
+
241
+ @media (prefers-color-scheme: dark) { #source p.run.run2.show_run .t { background: #2b2e24; } }
242
+
243
+ #source p.run.run2.show_run .t:hover { background: #d2f2d2; }
244
+
245
+ @media (prefers-color-scheme: dark) { #source p.run.run2.show_run .t:hover { background: #404633; } }
246
+
227
247
  #source p.exc .t { border-left: 0.2em solid #808080; }
228
248
 
229
249
  #source p.exc.show_exc .t { background: #eee; }
@@ -234,6 +254,16 @@ kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em
234
254
 
235
255
  @media (prefers-color-scheme: dark) { #source p.exc.show_exc .t:hover { background: #3c3c3c; } }
236
256
 
257
+ #source p.exc.exc2 .t { border-left: 0.2em dotted #808080; }
258
+
259
+ #source p.exc.exc2.show_exc .t { background: #f7f7f7; }
260
+
261
+ @media (prefers-color-scheme: dark) { #source p.exc.exc2.show_exc .t { background: #292929; } }
262
+
263
+ #source p.exc.exc2.show_exc .t:hover { background: #e2e2e2; }
264
+
265
+ @media (prefers-color-scheme: dark) { #source p.exc.exc2.show_exc .t:hover { background: #3c3c3c; } }
266
+
237
267
  #source p.par .t { border-left: 0.2em solid #bbbb00; }
238
268
 
239
269
  #source p.par.show_par .t { background: #ffa; }
@@ -244,6 +274,16 @@ kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em
244
274
 
245
275
  @media (prefers-color-scheme: dark) { #source p.par.show_par .t:hover { background: #6d5d0c; } }
246
276
 
277
+ #source p.par.par2 .t { border-left: 0.2em dotted #bbbb00; }
278
+
279
+ #source p.par.par2.show_par .t { background: #ffffd5; }
280
+
281
+ @media (prefers-color-scheme: dark) { #source p.par.par2.show_par .t { background: #423a0f; } }
282
+
283
+ #source p.par.par2.show_par .t:hover { background: #f2f2a2; }
284
+
285
+ @media (prefers-color-scheme: dark) { #source p.par.par2.show_par .t:hover { background: #6d5d0c; } }
286
+
247
287
  #source p .r { position: absolute; top: 0; right: 2.5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; }
248
288
 
249
289
  #source p .annotate { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; color: #666; padding-right: .5em; }
@@ -288,13 +328,19 @@ kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em
288
328
 
289
329
  #index table.index { margin-left: -.5em; }
290
330
 
291
- #index td, #index th { text-align: right; padding: .25em .5em; border-bottom: 1px solid #eee; }
331
+ #index td, #index th { text-align: right; vertical-align: baseline; padding: .25em .5em; border-bottom: 1px solid #eee; }
292
332
 
293
333
  @media (prefers-color-scheme: dark) { #index td, #index th { border-color: #333; } }
294
334
 
295
335
  #index td.name, #index th.name { text-align: left; width: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; min-width: 15em; }
296
336
 
297
- #index th { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-style: italic; color: #333; cursor: pointer; }
337
+ #index td.left, #index th.left { text-align: left; }
338
+
339
+ #index td.spacer, #index th.spacer { border: none; padding: 0; }
340
+
341
+ #index td.spacer:hover, #index th.spacer:hover { background: inherit; }
342
+
343
+ #index th { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-style: italic; color: #333; border-color: #ccc; cursor: pointer; }
298
344
 
299
345
  @media (prefers-color-scheme: dark) { #index th { color: #ddd; } }
300
346
 
@@ -312,13 +358,15 @@ kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em
312
358
 
313
359
  #index th[aria-sort="descending"] .arrows::after { content: " ▼"; }
314
360
 
361
+ #index tr.grouphead th { cursor: default; font-style: normal; border-color: #999; }
362
+
315
363
  #index td.name { font-size: 1.15em; }
316
364
 
317
365
  #index td.name a { text-decoration: none; color: inherit; }
318
366
 
319
367
  #index td.name .no-noun { font-style: italic; }
320
368
 
321
- #index tr.total td, #index tr.total_dynamic td { font-weight: bold; border-top: 1px solid #ccc; border-bottom: none; }
369
+ #index tr.total td, #index tr.total_dynamic td { font-weight: bold; border-bottom: none; }
322
370
 
323
371
  #index tr.region:hover { background: #eee; }
324
372
 
@@ -1,5 +1,5 @@
1
1
  /* Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 */
2
- /* For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt */
2
+ /* For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt */
3
3
 
4
4
  // CSS styles for coverage.py HTML reports.
5
5
 
@@ -27,6 +27,7 @@ $font-code: SFMono-Regular, Menlo, Monaco, Consolas, monospace;
27
27
 
28
28
  $off-button-lighten: 50%;
29
29
  $hover-dark-amt: 95%;
30
+ $multi-dim-amt: 50%;
30
31
 
31
32
  $focus-color: #007acc;
32
33
 
@@ -501,7 +502,7 @@ $border-indicator-width: .2em;
501
502
  font-weight: bold;
502
503
  line-height: 1px;
503
504
  }
504
- .str {
505
+ .str, .fst {
505
506
  color: $light-token-str;
506
507
  @include color-dark($dark-token-str);
507
508
  }
@@ -521,6 +522,22 @@ $border-indicator-width: .2em;
521
522
  @include background-dark(mix($dark-mis-bg, $dark-fg, $hover-dark-amt));
522
523
  }
523
524
  }
525
+
526
+ &.mis2 {
527
+ .t {
528
+ border-left: $border-indicator-width dotted $mis-color;
529
+ }
530
+
531
+ &.show_mis .t {
532
+ background: mix($light-mis-bg, $light-bg, $multi-dim-amt);
533
+ @include background-dark(mix($dark-mis-bg, $dark-bg, $multi-dim-amt));
534
+
535
+ &:hover {
536
+ background: mix($light-mis-bg, $light-fg, $hover-dark-amt);
537
+ @include background-dark(mix($dark-mis-bg, $dark-fg, $hover-dark-amt));
538
+ }
539
+ }
540
+ }
524
541
  }
525
542
 
526
543
  &.run {
@@ -537,6 +554,22 @@ $border-indicator-width: .2em;
537
554
  @include background-dark(mix($dark-run-bg, $dark-fg, $hover-dark-amt));
538
555
  }
539
556
  }
557
+
558
+ &.run2 {
559
+ .t {
560
+ border-left: $border-indicator-width dotted $run-color;
561
+ }
562
+
563
+ &.show_run .t {
564
+ background: mix($light-run-bg, $light-bg, $multi-dim-amt);
565
+ @include background-dark(mix($dark-run-bg, $dark-bg, $multi-dim-amt));
566
+
567
+ &:hover {
568
+ background: mix($light-run-bg, $light-fg, $hover-dark-amt);
569
+ @include background-dark(mix($dark-run-bg, $dark-fg, $hover-dark-amt));
570
+ }
571
+ }
572
+ }
540
573
  }
541
574
 
542
575
  &.exc {
@@ -553,6 +586,22 @@ $border-indicator-width: .2em;
553
586
  @include background-dark(mix($dark-exc-bg, $dark-fg, $hover-dark-amt));
554
587
  }
555
588
  }
589
+
590
+ &.exc2 {
591
+ .t {
592
+ border-left: $border-indicator-width dotted $exc-color;
593
+ }
594
+
595
+ &.show_exc .t {
596
+ background: mix($light-exc-bg, $light-bg, $multi-dim-amt);
597
+ @include background-dark(mix($dark-exc-bg, $dark-bg, $multi-dim-amt));
598
+
599
+ &:hover {
600
+ background: mix($light-exc-bg, $light-fg, $hover-dark-amt);
601
+ @include background-dark(mix($dark-exc-bg, $dark-fg, $hover-dark-amt));
602
+ }
603
+ }
604
+ }
556
605
  }
557
606
 
558
607
  &.par {
@@ -570,6 +619,21 @@ $border-indicator-width: .2em;
570
619
  }
571
620
  }
572
621
 
622
+ &.par2 {
623
+ .t {
624
+ border-left: $border-indicator-width dotted $par-color;
625
+ }
626
+
627
+ &.show_par .t {
628
+ background: mix($light-par-bg, $light-bg, $multi-dim-amt);
629
+ @include background-dark(mix($dark-par-bg, $dark-bg, $multi-dim-amt));
630
+
631
+ &:hover {
632
+ background: mix($light-par-bg, $light-fg, $hover-dark-amt);
633
+ @include background-dark(mix($dark-par-bg, $dark-fg, $hover-dark-amt));
634
+ }
635
+ }
636
+ }
573
637
  }
574
638
 
575
639
  .r {
@@ -669,6 +733,7 @@ $border-indicator-width: .2em;
669
733
  }
670
734
  td, th {
671
735
  text-align: right;
736
+ vertical-align: baseline;
672
737
  padding: .25em .5em;
673
738
  border-bottom: 1px solid $light-gray2;
674
739
  @include border-color-dark($dark-gray2);
@@ -678,12 +743,23 @@ $border-indicator-width: .2em;
678
743
  font-family: $font-normal;
679
744
  min-width: 15em;
680
745
  }
746
+ &.left {
747
+ text-align: left;
748
+ }
749
+ &.spacer {
750
+ border: none;
751
+ padding: 0;
752
+ &:hover {
753
+ background: inherit;
754
+ }
755
+ }
681
756
  }
682
757
  th {
683
758
  font-family: $font-normal;
684
759
  font-style: italic;
685
760
  color: $light-gray6;
686
761
  @include color-dark($dark-gray6);
762
+ border-color: #ccc;
687
763
  cursor: pointer;
688
764
  &:hover {
689
765
  background: $light-gray2;
@@ -709,6 +785,13 @@ $border-indicator-width: .2em;
709
785
  content: " ▼";
710
786
  }
711
787
  }
788
+ tr.grouphead {
789
+ th {
790
+ cursor: default;
791
+ font-style: normal;
792
+ border-color: #999;
793
+ }
794
+ }
712
795
  td.name {
713
796
  font-size: 1.15em;
714
797
  a {
@@ -723,7 +806,6 @@ $border-indicator-width: .2em;
723
806
  tr.total td,
724
807
  tr.total_dynamic td {
725
808
  font-weight: bold;
726
- border-top: 1px solid #ccc;
727
809
  border-bottom: none;
728
810
  }
729
811
  tr.region:hover {
coverage/inorout.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2
- # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
2
+ # For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
3
3
 
4
4
  """Determining whether files are being measured/reported or not."""
5
5
 
@@ -15,51 +15,54 @@ import re
15
15
  import sys
16
16
  import sysconfig
17
17
  import traceback
18
-
19
- from types import FrameType, ModuleType
20
- from typing import (
21
- cast, Any, TYPE_CHECKING,
22
- )
23
18
  from collections.abc import Iterable
19
+ from types import FrameType, ModuleType
20
+ from typing import TYPE_CHECKING, Any, cast
24
21
 
25
22
  from coverage import env
26
23
  from coverage.disposition import FileDisposition, disposition_init
27
- from coverage.exceptions import CoverageException, PluginError
28
- from coverage.files import TreeMatcher, GlobMatcher, ModuleMatcher
29
- from coverage.files import prep_patterns, find_python_files, canonical_filename
24
+ from coverage.exceptions import ConfigError, CoverageException, PluginError
25
+ from coverage.files import (
26
+ GlobMatcher,
27
+ ModuleMatcher,
28
+ TreeMatcher,
29
+ canonical_filename,
30
+ find_python_files,
31
+ prep_patterns,
32
+ )
30
33
  from coverage.misc import isolate_module, sys_modules_saved
31
34
  from coverage.python import source_for_file, source_for_morf
32
- from coverage.types import TFileDisposition, TMorf, TWarnFn, TDebugCtl
35
+ from coverage.types import TDebugCtl, TFileDisposition, TMorf, TWarnFn
33
36
 
34
37
  if TYPE_CHECKING:
35
38
  from coverage.config import CoverageConfig
36
39
  from coverage.plugin_support import Plugins
37
40
 
38
41
 
39
- # Pypy has some unusual stuff in the "stdlib". Consider those locations
40
- # when deciding where the stdlib is. These modules are not used for anything,
41
- # they are modules importable from the pypy lib directories, so that we can
42
- # find those directories.
43
42
  modules_we_happen_to_have: list[ModuleType] = [
44
- inspect, itertools, os, platform, re, sysconfig, traceback,
43
+ inspect,
44
+ itertools,
45
+ os,
46
+ platform,
47
+ re,
48
+ sysconfig,
49
+ traceback,
45
50
  ]
46
51
 
47
52
  if env.PYPY:
48
- try:
49
- import _structseq
50
- modules_we_happen_to_have.append(_structseq)
51
- except ImportError:
52
- pass
53
+ # Pypy has some unusual stuff in the "stdlib". Consider those locations
54
+ # when deciding where the stdlib is. These modules are not used for anything,
55
+ # they are modules importable from the pypy lib directories, so that we can
56
+ # find those directories.
57
+ import _pypy_irc_topic # pylint: disable=import-error
58
+ import _structseq # pylint: disable=import-error
53
59
 
54
- try:
55
- import _pypy_irc_topic
56
- modules_we_happen_to_have.append(_pypy_irc_topic)
57
- except ImportError:
58
- pass
60
+ modules_we_happen_to_have.extend([_structseq, _pypy_irc_topic])
59
61
 
60
62
 
61
63
  os = isolate_module(os)
62
64
 
65
+
63
66
  def canonical_path(morf: TMorf, directory: bool = False) -> str:
64
67
  """Return the canonical path of the module or file `morf`.
65
68
 
@@ -74,7 +77,7 @@ def canonical_path(morf: TMorf, directory: bool = False) -> str:
74
77
  return morf_path
75
78
 
76
79
 
77
- def name_for_module(filename: str, frame: FrameType | None) -> str:
80
+ def name_for_module(filename: str, frame: FrameType | None) -> str | None:
78
81
  """Get the name of the module for a filename and frame.
79
82
 
80
83
  For configurability's sake, we allow __main__ modules to be matched by
@@ -87,7 +90,7 @@ def name_for_module(filename: str, frame: FrameType | None) -> str:
87
90
 
88
91
  """
89
92
  module_globals = frame.f_globals if frame is not None else {}
90
- dunder_name: str = module_globals.get("__name__", None)
93
+ dunder_name: str | None = module_globals.get("__name__", None)
91
94
 
92
95
  if isinstance(dunder_name, str) and dunder_name != "__main__":
93
96
  # This is the usual case: an imported module.
@@ -191,14 +194,23 @@ class InOrOut:
191
194
  self.debug = debug
192
195
  self.include_namespace_packages = include_namespace_packages
193
196
 
194
- self.source: list[str] = []
195
197
  self.source_pkgs: list[str] = []
196
198
  self.source_pkgs.extend(config.source_pkgs)
199
+ self.source_dirs: list[str] = []
200
+ self.source_dirs.extend(config.source_dirs)
197
201
  for src in config.source or []:
198
202
  if os.path.isdir(src):
199
- self.source.append(canonical_filename(src))
203
+ self.source_dirs.append(src)
200
204
  else:
201
205
  self.source_pkgs.append(src)
206
+
207
+ # Canonicalize everything in `source_dirs`.
208
+ # Also confirm that they actually are directories.
209
+ for i, src in enumerate(self.source_dirs):
210
+ if not os.path.isdir(src):
211
+ raise ConfigError(f"Source dir is not a directory: {src!r}")
212
+ self.source_dirs[i] = canonical_filename(src)
213
+
202
214
  self.source_pkgs_unmatched = self.source_pkgs[:]
203
215
 
204
216
  self.include = prep_patterns(config.run_include)
@@ -233,10 +245,10 @@ class InOrOut:
233
245
  self.pylib_match = None
234
246
  self.include_match = self.omit_match = None
235
247
 
236
- if self.source or self.source_pkgs:
248
+ if self.source_dirs or self.source_pkgs:
237
249
  against = []
238
- if self.source:
239
- self.source_match = TreeMatcher(self.source, "source")
250
+ if self.source_dirs:
251
+ self.source_match = TreeMatcher(self.source_dirs, "source")
240
252
  against.append(f"trees {self.source_match!r}")
241
253
  if self.source_pkgs:
242
254
  self.source_pkgs_match = ModuleMatcher(self.source_pkgs, "source_pkgs")
@@ -285,7 +297,7 @@ class InOrOut:
285
297
  )
286
298
  self.source_in_third_paths.add(pathdir)
287
299
 
288
- for src in self.source:
300
+ for src in self.source_dirs:
289
301
  if self.third_match.match(src):
290
302
  _debug(f"Source in third-party: source directory {src!r}")
291
303
  self.source_in_third_paths.add(src)
@@ -410,7 +422,7 @@ class InOrOut:
410
422
  extra = ""
411
423
  ok = False
412
424
  if self.source_pkgs_match:
413
- if self.source_pkgs_match.match(modulename):
425
+ if isinstance(modulename, str) and self.source_pkgs_match.match(modulename):
414
426
  ok = True
415
427
  if modulename in self.source_pkgs_unmatched:
416
428
  self.source_pkgs_unmatched.remove(modulename)
@@ -457,12 +469,12 @@ class InOrOut:
457
469
  def warn_conflicting_settings(self) -> None:
458
470
  """Warn if there are settings that conflict."""
459
471
  if self.include:
460
- if self.source or self.source_pkgs:
472
+ if self.source_dirs or self.source_pkgs:
461
473
  self.warn("--include is ignored because --source is set", slug="include-ignored")
462
474
 
463
475
  def warn_already_imported_files(self) -> None:
464
476
  """Warn if files have already been imported that we will be measuring."""
465
- if self.include or self.source or self.source_pkgs:
477
+ if self.include or self.source_dirs or self.source_pkgs:
466
478
  warned = set()
467
479
  for mod in list(sys.modules.values()):
468
480
  filename = getattr(mod, "__file__", None)
@@ -488,7 +500,8 @@ class InOrOut:
488
500
  elif self.debug and self.debug.should("trace"):
489
501
  self.debug.write(
490
502
  "Didn't trace already imported file {!r}: {}".format(
491
- disp.original_filename, disp.reason,
503
+ disp.original_filename,
504
+ disp.reason,
492
505
  ),
493
506
  )
494
507
 
@@ -529,13 +542,12 @@ class InOrOut:
529
542
  Yields pairs: file path, and responsible plug-in name.
530
543
  """
531
544
  for pkg in self.source_pkgs:
532
- if (pkg not in sys.modules or
533
- not module_has_file(sys.modules[pkg])):
545
+ if pkg not in sys.modules or not module_has_file(sys.modules[pkg]):
534
546
  continue
535
547
  pkg_file = source_for_file(cast(str, sys.modules[pkg].__file__))
536
548
  yield from self._find_executable_files(canonical_path(pkg_file))
537
549
 
538
- for src in self.source:
550
+ for src in self.source_dirs:
539
551
  yield from self._find_executable_files(src)
540
552
 
541
553
  def _find_plugin_files(self, src_dir: str) -> Iterable[tuple[str, str]]:
@@ -555,8 +567,8 @@ class InOrOut:
555
567
 
556
568
  """
557
569
  py_files = (
558
- (py_file, None) for py_file in
559
- find_python_files(src_dir, self.include_namespace_packages)
570
+ (py_file, None)
571
+ for py_file in find_python_files(src_dir, self.include_namespace_packages)
560
572
  )
561
573
  plugin_files = self._find_plugin_files(src_dir)
562
574
 
@@ -581,9 +593,14 @@ class InOrOut:
581
593
  ]
582
594
 
583
595
  matcher_names = [
584
- "source_match", "source_pkgs_match",
585
- "include_match", "omit_match",
586
- "cover_match", "pylib_match", "third_match", "source_in_third_match",
596
+ "source_match",
597
+ "source_pkgs_match",
598
+ "include_match",
599
+ "omit_match",
600
+ "cover_match",
601
+ "pylib_match",
602
+ "third_match",
603
+ "source_in_third_match",
587
604
  ]
588
605
 
589
606
  for matcher_name in matcher_names:
coverage/jsonreport.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2
- # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
2
+ # For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
3
3
 
4
4
  """Json reporting for coverage.py"""
5
5
 
@@ -8,14 +8,13 @@ from __future__ import annotations
8
8
  import datetime
9
9
  import json
10
10
  import sys
11
-
12
11
  from collections.abc import Iterable
13
- from typing import Any, IO, TYPE_CHECKING
12
+ from typing import IO, TYPE_CHECKING, Any
14
13
 
15
14
  from coverage import __version__
16
15
  from coverage.report_core import get_analysis_to_report
17
- from coverage.results import Analysis, Numbers
18
- from coverage.types import TMorf, TLineNo
16
+ from coverage.results import Analysis, AnalysisNarrower, Numbers
17
+ from coverage.types import TLineNo, TMorf
19
18
 
20
19
  if TYPE_CHECKING:
21
20
  from coverage import Coverage
@@ -31,6 +30,7 @@ JsonObj = dict[str, Any]
31
30
  # 3: add region information (functions, classes)
32
31
  FORMAT_VERSION = 3
33
32
 
33
+
34
34
  class JsonReporter:
35
35
  """A reporter for writing JSON coverage results."""
36
36
 
@@ -51,6 +51,8 @@ class JsonReporter:
51
51
  "percent_covered_display": nums.pc_covered_str,
52
52
  "missing_lines": nums.n_missing,
53
53
  "excluded_lines": nums.n_excluded,
54
+ "percent_statements_covered": nums.pc_statements,
55
+ "percent_statements_covered_display": nums.pc_statements_str,
54
56
  }
55
57
 
56
58
  def make_branch_summary(self, nums: Numbers) -> JsonObj:
@@ -60,6 +62,8 @@ class JsonReporter:
60
62
  "num_partial_branches": nums.n_partial_branches,
61
63
  "covered_branches": nums.n_executed_branches,
62
64
  "missing_branches": nums.n_missing_branches,
65
+ "percent_branches_covered": nums.pc_branches,
66
+ "percent_branches_covered_display": nums.pc_branches_str,
63
67
  }
64
68
 
65
69
  def report(self, morfs: Iterable[TMorf] | None, outfile: IO[str]) -> float:
@@ -128,21 +132,30 @@ class JsonReporter:
128
132
  )
129
133
 
130
134
  num_lines = len(file_reporter.source().splitlines())
135
+ regions = file_reporter.code_regions()
131
136
  for noun, plural in file_reporter.code_region_kinds():
132
- reported_file[plural] = region_data = {}
133
137
  outside_lines = set(range(1, num_lines + 1))
134
- for region in file_reporter.code_regions():
138
+ for region in regions:
135
139
  if region.kind != noun:
136
140
  continue
137
141
  outside_lines -= region.lines
142
+
143
+ narrower = AnalysisNarrower(analysis)
144
+ narrower.add_regions(r.lines for r in regions if r.kind == noun)
145
+ narrower.add_regions([outside_lines])
146
+
147
+ reported_file[plural] = region_data = {}
148
+ for region in regions:
149
+ if region.kind != noun:
150
+ continue
138
151
  region_data[region.name] = self.make_region_data(
139
152
  coverage_data,
140
- analysis.narrow(region.lines),
153
+ narrower.narrow(region.lines),
141
154
  )
142
155
 
143
156
  region_data[""] = self.make_region_data(
144
157
  coverage_data,
145
- analysis.narrow(outside_lines),
158
+ narrower.narrow(outside_lines),
146
159
  )
147
160
  return reported_file
148
161
 
coverage/lcovreport.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2
- # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
2
+ # For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
3
3
 
4
4
  """LCOV reporting for coverage.py."""
5
5
 
@@ -8,13 +8,12 @@ from __future__ import annotations
8
8
  import base64
9
9
  import hashlib
10
10
  import sys
11
-
12
- from typing import IO, TYPE_CHECKING
13
11
  from collections.abc import Iterable
12
+ from typing import IO, TYPE_CHECKING
14
13
 
15
14
  from coverage.plugin import FileReporter
16
15
  from coverage.report_core import get_analysis_to_report
17
- from coverage.results import Analysis, Numbers
16
+ from coverage.results import Analysis, AnalysisNarrower, Numbers
18
17
  from coverage.types import TMorf
19
18
 
20
19
  if TYPE_CHECKING:
@@ -43,7 +42,7 @@ def lcov_lines(
43
42
  hash_suffix = ""
44
43
  for line in lines:
45
44
  if source_lines:
46
- hash_suffix = "," + line_hash(source_lines[line-1])
45
+ hash_suffix = "," + line_hash(source_lines[line - 1])
47
46
  # Q: can we get info about the number of times a statement is
48
47
  # executed? If so, that should be recorded here.
49
48
  hit = int(line not in analysis.missing)
@@ -71,21 +70,26 @@ def lcov_functions(
71
70
 
72
71
  # suppressions because of https://github.com/pylint-dev/pylint/issues/9923
73
72
  functions = [
74
- (min(region.start, min(region.lines)), #pylint: disable=nested-min-max
75
- max(region.start, max(region.lines)), #pylint: disable=nested-min-max
76
- region)
73
+ (
74
+ min(region.start, min(region.lines)), # pylint: disable=nested-min-max
75
+ max(region.start, max(region.lines)), # pylint: disable=nested-min-max
76
+ region,
77
+ )
77
78
  for region in fr.code_regions()
78
79
  if region.kind == "function" and region.lines
79
80
  ]
80
81
  if not functions:
81
82
  return
82
83
 
84
+ narrower = AnalysisNarrower(file_analysis)
85
+ narrower.add_regions(r.lines for _, _, r in functions)
86
+
83
87
  functions.sort()
84
88
  functions_hit = 0
85
89
  for first_line, last_line, region in functions:
86
90
  # A function counts as having been executed if any of it has been
87
91
  # executed.
88
- analysis = file_analysis.narrow(region.lines)
92
+ analysis = narrower.narrow(region.lines)
89
93
  hit = int(analysis.numbers.n_executed > 0)
90
94
  functions_hit += hit
91
95
 
@@ -120,19 +124,13 @@ def lcov_arcs(
120
124
  # When _none_ of the out arcs from 'line' were executed,
121
125
  # it can mean the line always raised an exception.
122
126
  assert len(executed_arcs[line]) == 0
123
- destinations = [
124
- (dst, "-") for dst in missing_arcs[line]
125
- ]
127
+ destinations = [(dst, "-") for dst in missing_arcs[line]]
126
128
  else:
127
129
  # Q: can we get counts of the number of times each arc was executed?
128
130
  # branch_stats has "total" and "taken" counts for each branch,
129
131
  # but it doesn't have "taken" broken down by destination.
130
- destinations = [
131
- (dst, "1") for dst in executed_arcs[line]
132
- ]
133
- destinations.extend(
134
- (dst, "0") for dst in missing_arcs[line]
135
- )
132
+ destinations = [(dst, "1") for dst in executed_arcs[line]]
133
+ destinations.extend((dst, "0") for dst in missing_arcs[line])
136
134
 
137
135
  # Sort exit arcs after normal arcs. Exit arcs typically come from
138
136
  # an if statement, at the end of a function, with no else clause.