diff-cover 9.7.1


pip install diff-cover

  Latest version

Released: Sep 26, 2025


Meta
Author: See Contributors
Requires Python: >=3.9

Classifiers

Development Status
  • 5 - Production/Stable

Environment
  • Console

Intended Audience
  • Developers

License
  • OSI Approved :: Apache Software License

Operating System
  • OS Independent

Programming Language
  • Python
  • Python :: 3
  • Python :: 3.9
  • Python :: 3.10
  • Python :: 3.11
  • Python :: 3.12
  • Python :: 3.13
  • Python :: Implementation :: CPython

Topic
  • Software Development :: Quality Assurance
  • Software Development :: Testing

Automatically find diff lines that need test coverage. Also finds diff lines that have violations (according to tools such as pycodestyle, pyflakes, flake8, or pylint). This is used as a code quality metric during code reviews.

Overview

Diff coverage is the percentage of new or modified lines that are covered by tests. This provides a clear and achievable standard for code review: If you touch a line of code, that line should be covered. Code coverage is every developer’s responsibility!

The diff-cover command line tool compares an XML coverage report with the output of git diff. It then reports coverage information for lines in the diff.

Currently, diff-cover requires that:

  • You are using git for version control.

  • Your test runner generates coverage reports in Cobertura, Clover or JaCoCo XML format, or LCov format.

Supported XML or LCov coverage reports can be generated with many coverage tools, including:

diff-cover is designed to be extended. If you are interested in adding support for other version control systems or coverage report formats, see below for information on how to contribute!

Installation

To install the latest release:

pip install diff_cover

To install the development version:

git clone https://github.com/Bachmann1234/diff-cover.git
cd diff-cover
poetry install
poetry shell

Getting Started

  1. Set the current working directory to a git repository.

  2. Run your test suite under coverage and generate a [Cobertura, Clover or JaCoCo] XML report. For example, using pytest-cov:

pytest --cov --cov-report=xml

This will create a coverage.xml file in the current working directory.

NOTE: If you are using a different coverage generator, you will need to use different commands to generate the coverage XML report.

  1. Run diff-cover:

diff-cover coverage.xml

This will compare the current git branch to origin/main and print the diff coverage report to the console.

You can also generate an HTML, JSON or Markdown version of the report:

diff-cover coverage.xml --format html:report.html
diff-cover coverage.xml --format json:report.json
diff-cover coverage.xml --format markdown:report.md
diff-cover coverage.xml --format html:report.html,markdown:report.md

Multiple XML Coverage Reports

In the case that one has multiple xml reports form multiple test suites, you can get a combined coverage report (a line is counted as covered if it is covered in ANY of the xml reports) by running diff-cover with multiple coverage reports as arguments. You may specify any arbitrary number of coverage reports:

diff-cover coverage1.xml coverage2.xml

Quality Coverage

You can use diff-cover to see quality reports on the diff as well by running diff-quality.

diff-quality --violations=<tool>

Where tool is the quality checker to use. Currently pycodestyle, pyflakes, flake8, pylint, checkstyle, checkstylexml, ruff.check, clang are supported, but more checkers can (and should!) be supported. See the section “Adding diff-quality` Support for a New Quality Checker”.

NOTE: There’s no way to run findbugs from diff-quality as it operating over the generated java bytecode and should be integrated into the build framework.

Like diff-cover, HTML, JSON or Markdown reports can be generated with

diff-quality --violations=<tool> --format html:report.html
diff-quality --violations=<tool> --format json:report.json
diff-quality --violations=<tool> --format markdown:report.md
diff-quality --violations=<tool> --format html:report.html,markdown:report.md

If you have already generated a report using pycodestyle, pyflakes, flake8, pylint, checkstyle, checkstylexml, or findbugs you can pass the report to diff-quality. This is more efficient than letting diff-quality re-run pycodestyle, pyflakes, flake8, pylint, checkstyle, or checkstylexml.

# For pylint < 1.0
pylint -f parseable > pylint_report.txt

# For pylint >= 1.0
pylint --msg-template="{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}" > pylint_report.txt

# Use the generated pylint report when running diff-quality
diff-quality --violations=pylint pylint_report.txt

# Use a generated pycodestyle report when running diff-quality.
pycodestyle > pycodestyle_report.txt
diff-quality --violations=pycodestyle pycodestyle_report.txt

Note that you must use the -f parseable option to generate the pylint report for pylint versions less than 1.0 and the --msg-template option for versions >= 1.0.

diff-quality will also accept multiple pycodestyle, pyflakes, flake8, or pylint reports:

diff-quality --violations=pylint report_1.txt report_2.txt

If you need to pass in additional options you can with the options flag

diff-quality --violations=pycodestyle --options="--exclude='*/migrations*' --statistics" pycodestyle_report.txt

Compare Branch

By default, diff-cover compares the current branch to origin/main. To specify a different compare branch:

diff-cover coverage.xml --compare-branch=origin/release

Diff File

You may provide a file containing the output of git diff to diff-cover instead of using a branch name.

For example, Say you have 2 branches main and feature. Lets say after creating and checking out the feature branch, you make commits A, B, and C in that order.

If you want to see all changes between the feature and main branch, you can generate a diff file like this:

git diff main..feature > diff.txt

If you want to see the changes between the feature branch and the commit A, you can generate a diff file using the following command:

git diff A..feature > diff.txt

You can then run diff-cover with the diff file as an argument:

diff-cover coverage.xml --diff-file=diff.txt

Fail Under

To have diff-cover and diff-quality return a non zero status code if the report quality/coverage percentage is below a certain threshold specify the fail-under parameter

diff-cover coverage.xml --fail-under=80
diff-quality --violations=pycodestyle --fail-under=80

The above will return a non zero status if the coverage or quality score was below 80%.

Exclude/Include paths

Explicit exclusion of paths is possible for both diff-cover and diff-quality, while inclusion is only supported for diff-quality (since 5.1.0).

The exclude option works with fnmatch, include with glob. Both options can consume multiple values. Include options should be wrapped in double quotes to prevent shell globbing. Also they should be relative to the current git directory.

diff-cover coverage.xml --exclude setup.py
diff-quality --violations=pycodestyle --exclude setup.py

diff-quality --violations=pycodestyle --include project/foo/**

The following is executed for every changed file:

  1. check if any include pattern was specified

  2. if yes, check if the changed file is part of at least one include pattern

  3. check if the file is part of any exclude pattern

Ignore/Include based on file status in git

Both diff-cover and diff-quality allow users to ignore and include files based on the git status: staged, unstaged, untracked:

  • --ignore-staged: ignore all staged files (by default include them)

  • --ignore-unstaged: ignore all unstaged files (by default include them)

  • --include-untracked: include all untracked files (by default ignore them)

Quiet mode

Both diff-cover and diff-quality support a quiet mode which is disable by default. It can be enabled by using the -q/--quiet flag:

diff-cover coverage.xml -q
diff-quality --violations=pycodestyle -q

If enabled, the tool will only print errors and failures but no information or warning messages.

Compatibility with multi-line statements

diff-cover relies on the comparison of diff reports and coverage reports, and does not report lines that appear in one and not in the other. While diff reports list all lines that changed, coverage reports usually list code statements. As a result, a change in a multi-line statement may not be analyzed by diff-cover.

As a workaround, you can use the argument --expand-coverage-report: lines not appearing in the coverage reports will be added to them with the same number of hits as the previously reported line. diff-cover will then perform diff coverage analysis on all changed lines.

Notes: - This argument is only available for XML coverage reports. - This workaround is designed under the assumption that the coverage tool reports untested statements with hits set to 0, and it reports statements based on the opening line.

Configuration files

Both tools allow users to specify the options in a configuration file with –config-file/-c:

diff-cover coverage.xml --config-file myconfig.toml
diff-quality --violations=pycodestyle --config-file myconfig.toml

Currently, only TOML files are supported. Please note, that only non-mandatory options are supported. If an option is specified in the configuration file and over the command line, the value of the command line is used.

TOML configuration

The parser will only react to configuration files ending with .toml. To use it, install diff-cover with the extra requirement toml.

The option names are the same as on the command line, but all dashes should be underscores. If an option can be specified multiple times, the configuration value should be specified as a list.

[tool.diff_cover]
compare_branch = "origin/feature"
quiet = true

[tool.diff_quality]
compare_branch = "origin/feature"
ignore_staged = true

Troubleshooting

Issue: diff-cover always reports: “No lines with coverage information in this diff.”

Solution: diff-cover matches source files in the coverage XML report with source files in the git diff. For this reason, it’s important that the relative paths to the files match. If you are using coverage.py to generate the coverage XML report, then make sure you run diff-cover from the same working directory.

Issue: GitDiffTool._execute() raises the error:

fatal: ambiguous argument 'origin/main...HEAD': unknown revision or path not in the working tree.

This is known to occur when running diff-cover in Travis CI

Solution: Fetch the remote main branch before running diff-cover:

git fetch origin master:refs/remotes/origin/main

Issue: diff-quality reports “diff_cover.violations_reporter.QualityReporterError: No config file found, using default configuration”

Solution: Your project needs a pylintrc file. Provide this file (it can be empty) and diff-quality should run without issue.

Issue: diff-quality reports “Quality tool not installed”

Solution: diff-quality assumes you have the tool you wish to run against your diff installed. If you do not have it then install it with your favorite package manager.

Issue: diff-quality reports no quality issues

Solution: You might use a pattern like diff-quality --violations foo *.py. The last argument is not used to specify the files but for the quality tool report. Remove it to resolve the issue

License

The code in this repository is licensed under the Apache 2.0 license. Please see LICENSE.txt for details.

How to Contribute

Contributions are very welcome. The easiest way is to fork this repo, and then make a pull request from your fork.

NOTE: diff-quality supports a plugin model, so new tools can be integrated without requiring changes to this repo. See the section “Adding diff-quality` Support for a New Quality Checker”.

Setting Up For Development

This project is managed with poetry this can be installed with pip poetry manages a python virtual environment and organizes dependencies. It also packages this project.

pip install poetry
poetry install

I would also suggest running this command after. This will make it so git blame ignores the commit that formatted the entire codebase.

git config blame.ignoreRevsFile .git-blame-ignore-revs

Adding diff-quality` Support for a New Quality Checker

Adding support for a new quality checker is simple. diff-quality supports plugins using the popular Python pluggy package.

If the quality checker is already implemented as a Python package, great! If not, create a Python package to host the plugin implementation.

In the Python package’s setup.py file, define an entry point for the plugin, e.g.

setup(
    ...
    entry_points={
        'diff_cover': [
            'sqlfluff = sqlfluff.diff_quality_plugin'
        ],
    },
    ...
)

Notes:

  • The dictionary key for the entry point must be named diff_cover

  • The value must be in the format TOOL_NAME = YOUR_PACKAGE.PLUGIN_MODULE

When your package is installed, diff-quality uses this information to look up the tool package and module based on the tool name provided to the --violations option of the diff-quality command, e.g.:

$ diff-quality --violations sqlfluff

The plugin implementation will look something like the example below. This is a simplified example based on a working plugin implementation.

from diff_cover.hook import hookimpl as diff_cover_hookimpl
from diff_cover.violationsreporters.base import BaseViolationReporter, Violation

class SQLFluffViolationReporter(BaseViolationReporter):
    supported_extensions = ['sql']

    def __init__(self):
        super(SQLFluffViolationReporter, self).__init__('sqlfluff')

    def violations(self, src_path):
        return [
            Violation(violation.line_number, violation.description)
            for violation in get_linter().get_violations(src_path)
        ]

    def measured_lines(self, src_path):
        return None

    @staticmethod
    def installed():
        return True


@diff_cover_hookimpl
def diff_cover_report_quality():
    return SQLFluffViolationReporter()

Important notes:

  • diff-quality is looking for a plugin function:

    • Located in your package’s module that was listed in the setup.py entry point.

    • Marked with the @diff_cover_hookimpl decorator

    • Named diff_cover_report_quality. (This distinguishes it from any other plugin types diff_cover may support.)

  • The function should return an object with the following properties and methods:

    • supported_extensions property with a list of supported file extensions

    • violations() function that returns a list of Violation objects for the specified src_path. For more details on this function and other possible reporting-related methods, see the BaseViolationReporter class here.

Special Thanks

Shout out to the original author of diff-cover Will Daly and the original author of diff-quality Sarina Canelake.

Originally created with the support of edX.

9.7.1 Sep 26, 2025
9.7.0 Sep 24, 2025
9.6.0 Jul 17, 2025
9.5.0 Jul 10, 2025
9.4.1 Jun 23, 2025
9.4.0 Jun 22, 2025
9.3.2 Jun 01, 2025
9.3.1 May 25, 2025
9.3.0 May 24, 2025
9.2.4 Mar 09, 2025
9.2.3 Feb 19, 2025
9.2.2 Jan 30, 2025
9.2.1 Dec 13, 2024
9.2.0 Sep 08, 2024
9.1.1 Jul 18, 2024
9.1.0 Jun 25, 2024
9.0.0 Apr 14, 2024
8.0.3 Jan 20, 2024
8.0.2 Dec 16, 2023
8.0.1 Nov 13, 2023
8.0.0 Oct 14, 2023
7.7.0 Jul 15, 2023
7.6.1 Jul 13, 2023
7.6.0 Jun 11, 2023
7.5.0 Feb 22, 2023
7.4.0 Jan 25, 2023
7.3.2 Jan 19, 2023
7.3.1 Jan 19, 2023
7.3.0 Dec 10, 2022
7.2.0 Dec 01, 2022
7.1.2 Nov 30, 2022
7.1.1 Nov 29, 2022
7.1.0 Nov 26, 2022
7.0.2 Nov 13, 2022
7.0.1 Sep 20, 2022
7.0.0 Sep 19, 2022
6.5.1 Jun 22, 2022
6.5.0 Apr 16, 2022
6.4.5 Mar 24, 2022
6.4.4 Dec 06, 2021
6.4.3 Dec 03, 2021
6.4.2 Oct 06, 2021
6.4.1 Sep 26, 2021
6.4.0 Sep 17, 2021
6.3.5 Aug 30, 2021
6.3.4 Aug 24, 2021
6.3.3 Aug 20, 2021
6.3.2 Aug 19, 2021
6.3.1 Aug 15, 2021
6.3.0 Aug 11, 2021
6.2.2 Aug 08, 2021
6.2.1 Jul 30, 2021
6.2.0 Jul 14, 2021
6.1.1 Jul 09, 2021
6.1.0 Jul 08, 2021
6.0.0 Jul 04, 2021
5.5.0 Jul 03, 2021
5.4.0 Jun 24, 2021
5.3.0 Jun 22, 2021
5.2.0 Jun 18, 2021
5.1.2 May 29, 2021
5.1.1 May 11, 2021
5.1.0 May 10, 2021
5.0.1 Mar 11, 2021
5.0.0 Mar 08, 2021
4.2.3 Mar 03, 2021
4.2.2 Mar 02, 2021
4.2.1 Jan 30, 2021
4.2.0 Jan 20, 2021
4.1.1 Jan 09, 2021
4.1.0 Jan 07, 2021
4.0.1 Sep 22, 2020
4.0.0 Aug 31, 2020
3.0.1 Jun 04, 2020
3.0.0 Jun 03, 2020
2.6.1 Apr 07, 2020
2.6.0 Feb 08, 2020
2.5.2 Jan 11, 2020
2.5.1 Jan 11, 2020
2.5.0 Dec 14, 2019
2.4.1 Nov 21, 2019
2.4.0 Oct 18, 2019
2.3.0 Jun 30, 2019
2.2.0 Jun 14, 2019
2.1.0 Jun 04, 2019
2.0.1 May 10, 2019
2.0.0 Apr 09, 2019
1.0.7 Mar 16, 2019
1.0.6 Dec 18, 2018
1.0.5 Oct 30, 2018
1.0.4 Jul 11, 2018
1.0.3 Jun 25, 2018
1.0.2 Dec 22, 2017
1.0.1 Dec 15, 2017
1.0.0 Nov 15, 2017
0.9.12 Jul 23, 2017
0.9.11 Mar 08, 2017
0.9.10 Feb 25, 2017
0.9.9 Aug 13, 2016
0.9.8 Jul 28, 2016
0.9.7 Mar 30, 2016
0.9.6 Feb 21, 2016
0.9.5 Feb 13, 2016
0.9.4 Feb 11, 2016
0.9.3 Feb 10, 2016
0.9.2 Feb 09, 2016
0.9.1 Feb 08, 2016
0.9.0 Feb 07, 2016
0.8.6 Dec 18, 2015
0.8.5 Dec 01, 2015
0.8.4 Nov 25, 2015
0.8.3 Oct 22, 2015
0.8.2 Sep 17, 2015
0.8.1 Sep 12, 2015
0.8.0 Jun 03, 2015
0.7.6.1 May 08, 2015
0.7.6 May 02, 2015
0.7.5 Mar 07, 2015
0.7.4 Feb 05, 2015
0.7.3 Dec 12, 2014
0.7.2 Nov 07, 2014
0.7.1 Oct 22, 2014
0.6.2 Oct 09, 2014
0.6.1 Oct 01, 2014
0.6.0 Jul 23, 2014
0.5.7 Jul 17, 2014
0.5.6 Jul 13, 2014
0.5.5 Jul 13, 2014
0.5.4 Jul 06, 2014
0.5.2 Jun 28, 2014
0.5.1 Jun 27, 2014
0.5.0 Jun 24, 2014
0.4.3 Jun 13, 2014
0.4.2 Jun 11, 2014
0.4.1 May 22, 2014
0.4.0 Apr 30, 2014
0.3.0 Apr 20, 2014
0.2.9 Dec 24, 2013
0.2.7 Nov 16, 2013
0.2.6 Nov 11, 2013
0.2.4 Sep 23, 2013
0.2.3 Sep 19, 2013
0.2.2 Sep 01, 2013
0.2.1 Aug 09, 2013
0.2.0 Jul 18, 2013
0.1.4 Jun 28, 2013

Wheel compatibility matrix

Platform Python 3
any

Files in release

Extras:
Dependencies:
Jinja2 (>=2.7.1)
Pygments (<3.0.0,>=2.19.1)
chardet (>=3.0.0)
pluggy (<2,>=0.13.1)