pytest-coverage-commentator
pytest-coverage-commentator copied to clipboard
Support --cov-report=xml:DEST reports
Currently, the commentator only supports parsing term
coverage reports (the default report type), which do not support a destination file. As a result, you must redirect your test output to a file for the commentator to be able to load that report. This is a pain if you also rely on the output being visible in your GH action (but you can use pytest | tee coverage.txt
to avoid having to run the tests twice).
But, pytest-cov
lets you set the type of report it generates (more than once to produce multple outputs), and the annotate
, html
and xml
reports all support a destination. E.g. pytest --cov-report=xml:coverage.xml
will generate a coverage.xml
file.
The XML output is the most suitable to parsing; the downside is that there is no platform
information in that output. I don't think that's really a big problem. You'll have to run the file through an XML parser, of course.
You can otherwise produce the exact same output as the default term
report if you parse the XML file by iterating over all packages
-> package
-> classes
-> class
tags. For the Name
, Stmts
, Miss
, Branch
, BrPart
and Cover
columns, you need to collect the following information:
-
Name
: thefilename
attribute of theclass
element -
Stmts
: count the number of childline
elements under theclass
element. -
Miss
: count the number of childline
elements with thehits
attribute set to0
, or alternatively, withhits
not set to1
(hits
is always1
or0
). -
Branch
: for all childline
elements withbranch="true"
, parse thecondition-coverage
tag string, using the regex^\d+% \((?P<brachhits>:\d+)/(?P<branches>\d+)\)$
, and sum thebranches
numbers. E.g. for the value100% (2/2)
,branches
is2
. -
BrPart
: for all childline
elements withbranch="true"
, parse thecondition-coverage
tag string, using the regex^\d*% \((?P<brachhits>:\d+)/(?P<branches>\d+)$
, and only ifbranchhits
is not equal tobranches
, sum thebranchhits
value (these are partial branch hits). E.g. for the value50% (1/2)
,branchhits
is1
, and not equal tobranches=2
, so count1
partial branch hit. For0% (0/2)
or100% (2/2)
, you ignore thebranchhits
value. -
Cover
: when processing all childline
elements, the coverage is calculated across 4 different numbers:- total lines (the
Stmts
value) - total branches (the
Branch
value) - total hits (
Stmts
-Miss
, all lines withhits="1"
) - total branch hits (all
branchhits
values. This differs from theBrPart
value which only sums non-zerobranchhits
values that are not equal tobranches
).
The percentage is then calculated using
(total hits + total branch hits) / (total lines + total branches) * 100
. This is a fraction between 0 and 100. If the value is not exactly 0 but below 1, display1
. If the value is not exactly 100, but above 99, display 99. All other values are rounded to the nearest whole number. The extra rules for1
and99
there prevent0.5
becoming0
and99.5
becoming100
.This is detailed in the coverage FAQ and verified by reading the
results.py
source code (specifically theratio_covered
anddisplay_covered
methods). - total lines (the
The term
report can be configured to show missing line numbers too, I didn't search for how those are summarised (look for the format_lines()
function). The coverage percentage precision is also adjustable, altering the near-0 and near-100 rules. I used the default rules above.
The advantage of all this work is that you can then display any Cobertura-compatible XML coverage report in this way.
Have the same issue. Found solution on similar GitHub Action: Pytest Coverage Comment
There are possibilities to generate a coverage report
or junit.xml
report, also there are coverage-percentage
calculations.
You can check it, maybe it will solve your issue.