Skip to content
Draft
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
448dbbb
Adds ruff check
kingbuzzman May 15, 2025
fe444b5
Fixes isort
kingbuzzman May 15, 2025
cedcff1
Adds tests
kingbuzzman May 15, 2025
d0336e3
.
kingbuzzman May 15, 2025
588255b
Adds docs
kingbuzzman May 15, 2025
3b100b0
oops
kingbuzzman May 16, 2025
439a6cf
Adds ruff linting and formatting
kingbuzzman May 16, 2025
d1cbd0b
format
kingbuzzman May 16, 2025
686e18f
.
kingbuzzman May 16, 2025
a633412
Update .git-blame-ignore-revs
kingbuzzman May 16, 2025
6144651
putting it all back
kingbuzzman May 16, 2025
191134e
isort
kingbuzzman May 16, 2025
5abe6a4
Merge branch 'dev/implement-ruff' of github.com:kingbuzzman/diff_cove…
kingbuzzman May 16, 2025
8171a16
.
kingbuzzman May 16, 2025
50f1db7
.
kingbuzzman May 16, 2025
76dd715
.
kingbuzzman May 16, 2025
effe406
Merge branch 'main' into feature/ruff
kingbuzzman May 18, 2025
617225c
Merge remote-tracking branch 'remote/main' into feature/ruff
kingbuzzman May 18, 2025
5451e3e
Merge remote-tracking branch 'origin/feature/ruff' into feature/ruff
kingbuzzman May 18, 2025
ddf7c7b
Merge branch 'feature/ruff' into dev/implement-ruff
kingbuzzman May 18, 2025
d5df82a
Min version should be our least required
kingbuzzman May 18, 2025
78dc75e
Merge remote-tracking branch 'remote/main' into dev/implement-ruff
kingbuzzman May 18, 2025
29abb57
.
kingbuzzman May 18, 2025
eb13b7d
.
kingbuzzman May 18, 2025
047a9a7
Improvements
kingbuzzman May 18, 2025
99f587d
More replacements..
kingbuzzman May 18, 2025
68dc06c
Merge remote-tracking branch 'origin/main' into dev/ruff-implementation
kingbuzzman May 18, 2025
1a3d77e
.
kingbuzzman May 18, 2025
2934d0b
Merge branch 'main' into dev/ruff-implementation
kingbuzzman May 18, 2025
dffcb7b
wip
kingbuzzman May 19, 2025
3b7d5a4
Merge branch 'main' into dev/ruff-implementation
kingbuzzman May 22, 2025
3db2722
Update diff_cover/git_diff.py
kingbuzzman Jun 3, 2025
b41aeb2
Merge branch 'main' into dev/ruff-implementation
kingbuzzman Jun 3, 2025
ba03bd6
Update diff_cover/diff_cover_tool.py
kingbuzzman Jun 3, 2025
bdb3018
.
kingbuzzman Jun 3, 2025
25a1272
.
kingbuzzman Jun 3, 2025
39de607
.
kingbuzzman Jun 3, 2025
ccc357c
Merge branch 'main' into dev/ruff-implementation
kingbuzzman Jun 11, 2025
67b1593
Merge branch 'main' into dev/ruff-implementation
kingbuzzman Jun 12, 2025
e179d5e
Merge branch 'Bachmann1234:main' into dev/ruff-implementation
kingbuzzman Jun 15, 2025
64bdc39
Merge branch 'Bachmann1234:main' into dev/ruff-implementation
kingbuzzman Jun 16, 2025
124a1fb
Update
kingbuzzman Jun 22, 2025
46c46c2
FINALLY fixes isort issue that was driving me up a tree
kingbuzzman Jun 22, 2025
ac6fdc9
.
kingbuzzman Jun 22, 2025
a6f1f82
Fixes tests
kingbuzzman Jun 22, 2025
7261669
.
kingbuzzman Jun 22, 2025
bb53e06
Fixes bug modifying GitPathTool object
kingbuzzman Jun 22, 2025
217f3af
.
kingbuzzman Jun 22, 2025
25af280
.
kingbuzzman Jun 22, 2025
66f22b2
.
kingbuzzman Jun 22, 2025
ed7c7d5
More fixes
kingbuzzman Jun 22, 2025
f5cce2b
Nicer
kingbuzzman Jun 22, 2025
eb257b8
.
kingbuzzman Jun 22, 2025
9886242
Merge branch 'main' into dev/ruff-implementation
kingbuzzman Jun 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions .flake8

This file was deleted.

5 changes: 5 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
# Migrate code style to Black
e1db83a447700237a96be7a9db4413fe5024d328
# Migrate code style to Ruff
# ########################################################################
# TODO: IMPORTANT replace this with the real commit once it's merged
# ########################################################################
d1cbd0bbfd80e19f7ab6231251389fadfd4b9b22
1 change: 1 addition & 0 deletions diff_cover/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from importlib.metadata import version


VERSION = version("diff_cover")
DESCRIPTION = "Automatically find diff lines that need test coverage."
QUALITY_DESCRIPTION = "Automatically find diff lines with quality violations."
2 changes: 2 additions & 0 deletions diff_cover/command_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ def _ensure_unicode(text):
Ensures the text passed in becomes unicode
Args:
text (str|unicode)

Returns:
unicode

"""
if isinstance(text, bytes):
return text.decode(sys.getfilesystemencoding(), "replace")
Expand Down
1 change: 1 addition & 0 deletions diff_cover/config_parser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import abc
import enum


try:
import tomli as toml

Expand Down
8 changes: 5 additions & 3 deletions diff_cover/diff_cover_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
XmlCoverageReporter,
)


HTML_REPORT_HELP = "Diff coverage HTML output"
JSON_REPORT_HELP = "Diff coverage JSON output"
MARKDOWN_REPORT_HELP = "Diff coverage Markdown output"
Expand Down Expand Up @@ -240,9 +241,10 @@ def generate_coverage_report(
for coverage_file in coverage_files
if not coverage_file.endswith(".xml")
]
if len(xml_roots) > 0 and len(lcov_roots) > 0:
raise ValueError(f"Mixing LCov and XML reports is not supported yet")
elif len(xml_roots) > 0:
if xml_roots and lcov_roots:
msg = "Mixing LCov and XML reports is not supported yet"
raise ValueError(msg)
if xml_roots:
coverage = XmlCoverageReporter(xml_roots, src_roots, expand_coverage_report)
else:
coverage = LcovCoverageReporter(lcov_roots, src_roots)
Expand Down
2 changes: 1 addition & 1 deletion diff_cover/diff_quality_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
shellcheck_driver,
)


QUALITY_DRIVERS = {
"cppcheck": CppcheckDriver(),
"pycodestyle": pycodestyle_driver,
Expand Down Expand Up @@ -292,7 +293,6 @@ def main(argv=None, directory=None):
1 is an error
0 is successful run
"""

argv = argv or sys.argv
arg_dict = parse_quality_args(argv[1:])

Expand Down
39 changes: 14 additions & 25 deletions diff_cover/diff_reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ def src_paths_changed(self):
"""
See base class docstring.
"""

# Get the diff dictionary
diff_dict = self._git_diff()
# include untracked files
Expand All @@ -183,7 +182,6 @@ def _get_file_lines(path):
"""
Return the number of lines in a file.
"""

try:
with open(path, encoding="utf-8") as file_handle:
return len(file_handle.readlines())
Expand All @@ -194,7 +192,6 @@ def lines_changed(self, src_path):
"""
See base class docstring.
"""

# Get the diff dictionary (cached)
diff_dict = self._git_diff()

Expand Down Expand Up @@ -227,7 +224,6 @@ def _git_diff(self):

Raises a GitDiffError if `git diff` has an error.
"""

# If we do not have a cached result, execute `git diff`
if self._diff_dict is None:
result_dict = {}
Expand Down Expand Up @@ -268,7 +264,6 @@ def _validate_path_to_diff(self, src_path: str) -> bool:
- If the path is excluded
- If the path has an extension that is not supported
"""

if self._is_path_excluded(src_path):
return False

Expand Down Expand Up @@ -297,7 +292,6 @@ def _parse_diff_str(self, diff_str):

If the output could not be parsed, raises a GitDiffError.
"""

# Create a dict to hold results
diff_dict = {}

Expand All @@ -320,7 +314,6 @@ def _parse_source_sections(self, diff_str):

Raises a `GitDiffError` if `diff_str` is in an invalid format.
"""

# Create a dict to map source files to lines in the diff output
source_dict = {}

Expand Down Expand Up @@ -349,22 +342,20 @@ def _parse_source_sections(self, diff_str):

# Every other line is stored in the dictionary for this source file
# once we find a hunk section
else:
# Only add lines if we're in a hunk section
# (ignore index and files changed lines)
if found_hunk or line.startswith("@@"):
# Remember that we found a hunk
found_hunk = True

if src_path is not None:
source_dict[src_path].append(line)

else:
# We tolerate other information before we have
# a source file defined, unless it's a hunk line
if line.startswith("@@"):
msg = f"Hunk has no source file: '{line}'"
raise GitDiffError(msg)
# Only add lines if we're in a hunk section
# (ignore index and files changed lines)
elif found_hunk or line.startswith("@@"):
# Remember that we found a hunk
found_hunk = True

if src_path is not None:
source_dict[src_path].append(line)

# We tolerate other information before we have
# a source file defined, unless it's a hunk line
elif line.startswith("@@"):
msg = f"Hunk has no source file: '{line}'"
raise GitDiffError(msg)

return source_dict

Expand All @@ -378,7 +369,6 @@ def _parse_lines(self, diff_lines):

Raises a `GitDiffError` if the diff lines are in an invalid format.
"""

added_lines = []
deleted_lines = []

Expand Down Expand Up @@ -502,7 +492,6 @@ def _unique_ordered_lines(line_numbers):
Given a list of line numbers, return a list in which each line
number is included once and the lines are ordered sequentially.
"""

if len(line_numbers) == 0:
return []

Expand Down
15 changes: 3 additions & 12 deletions diff_cover/git_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,7 @@ def diff_committed(self, compare_branch="origin/main"):
Raises a `GitDiffError` if `git diff` outputs anything
to stderr.
"""
diff_range = "{branch}{notation}HEAD".format(
branch=compare_branch, notation=self.range_notation
)
diff_range = f"{compare_branch}{self.range_notation}HEAD"
try:
return execute(
self._default_git_args + self._default_diff_args + [diff_range]
Expand Down Expand Up @@ -112,18 +110,11 @@ def untracked(self):
return self._untracked_cache

output = execute(["git", "ls-files", "--exclude-standard", "--others"])[0]
self._untracked_cache = []
if output:
self._untracked_cache = [
to_unescaped_filename(line) for line in output.splitlines() if line
]
return self._untracked_cache
return [to_unescaped_filename(line) for line in output.splitlines() if line]


class GitDiffFileTool(GitDiffTool):

def __init__(self, diff_file_path):

self.diff_file_path = diff_file_path
super().__init__("...", False)

Expand All @@ -134,7 +125,7 @@ def diff_committed(self, compare_branch="origin/main"):
Raises a `GitDiffError` if the file cannot be read.
"""
try:
with open(self.diff_file_path, "r") as file:
with open(self.diff_file_path) as file:
return file.read()
except OSError as e:
error_message = (
Expand Down
1 change: 1 addition & 0 deletions diff_cover/hook.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pluggy


# Other packages that implement diff_cover plugins use this.
hookimpl = pluggy.HookimplMarker("diff_cover")
1 change: 1 addition & 0 deletions diff_cover/hookspecs.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pluggy


hookspec = pluggy.HookspecMarker("diff_cover")


Expand Down
6 changes: 0 additions & 6 deletions diff_cover/report_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ def violation_lines(self, src_path):
If we have no coverage information for
`src_path`, returns an empty list.
"""

diff_violations = self._diff_violations().get(src_path)

if diff_violations is None:
Expand All @@ -147,7 +146,6 @@ def total_num_lines(self):
Return the total number of lines in the diff for
which we have coverage info.
"""

return sum(
[
len(summary.measured_lines)
Expand All @@ -160,7 +158,6 @@ def total_num_violations(self):
Returns the total number of lines in the diff
that are in violation.
"""

return sum(len(summary.lines) for summary in self._diff_violations().values())

def total_percent_covered(self):
Expand Down Expand Up @@ -233,7 +230,6 @@ def _src_path_stats(self, src_path):
"""
Return a dict of statistics for the source file at `src_path`.
"""

covered_lines = self.covered_lines(src_path)

# Find violation lines
Expand Down Expand Up @@ -296,7 +292,6 @@ def generate_report(self, output_file):
See base class.
output_file must be a file handler that takes in bytes!
"""

if self.template_path is not None:
template = TEMPLATE_ENV.get_template(self.template_path)
report = template.render(self._context())
Expand Down Expand Up @@ -340,7 +335,6 @@ def _context(self):
'total_percent_covered': TOTAL_PERCENT_COVERED
}
"""

# Include snippet style info if we're displaying
# source code snippets
if self.include_snippets:
Expand Down
7 changes: 2 additions & 5 deletions diff_cover/snippets.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ def __init__(
Raises a `ValueError` if `start_line` is less than 1
"""
if start_line < 1:
raise ValueError("Start line must be >= 1")
msg = "Start line must be >= 1"
raise ValueError(msg)

self._src_tokens = src_tokens
self._src_filename = src_filename
Expand Down Expand Up @@ -116,7 +117,6 @@ def markdown(self):
Return a Markdown representation of the snippet using Markdown fenced code blocks.
See https://github.github.com/gfm/#fenced-code-blocks.
"""

line_number_length = len(str(self._last_line))

text = ""
Expand Down Expand Up @@ -188,7 +188,6 @@ def load_formatted_snippets(cls, src_path, violation_lines):

See `load_snippets()` for details.
"""

# load once...
snippet_list = cls.load_snippets(src_path, violation_lines)

Expand Down Expand Up @@ -266,7 +265,6 @@ def _parse_src(cls, src_contents, src_filename):
Uses `src_filename` to guess the type of file
so it can highlight syntax correctly.
"""

# Parse the source into tokens
try:
lexer = guess_lexer_for_filename(src_filename, src_contents)
Expand Down Expand Up @@ -302,7 +300,6 @@ def _group_tokens(cls, token_stream, range_list):
The algorithm is slightly complicated because a single token
can contain multiple line breaks.
"""

# Create a map from ranges (start/end tuples) to tokens
token_map = {rng: [] for rng in range_list}

Expand Down
Loading
Loading