diff-cover 10.6.0__tar.gz → 11.0.0__tar.gz

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 (162) hide show
  1. {diff_cover-10.6.0 → diff_cover-11.0.0}/PKG-INFO +3 -4
  2. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/config_parser.py +2 -16
  3. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/diff_reporter.py +9 -1
  4. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/git_diff.py +1 -1
  5. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/snippets.py +13 -6
  6. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/violationsreporters/base.py +11 -2
  7. {diff_cover-10.6.0 → diff_cover-11.0.0}/pyproject.toml +7 -6
  8. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_config_parser.py +0 -8
  9. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_diff_reporter.py +26 -0
  10. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_integration.py +4 -4
  11. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_snippets.py +41 -5
  12. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_violations_reporter.py +26 -0
  13. {diff_cover-10.6.0 → diff_cover-11.0.0}/.gitignore +0 -0
  14. {diff_cover-10.6.0 → diff_cover-11.0.0}/LICENSE +0 -0
  15. {diff_cover-10.6.0 → diff_cover-11.0.0}/NOTICE +0 -0
  16. {diff_cover-10.6.0 → diff_cover-11.0.0}/README.rst +0 -0
  17. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/__init__.py +0 -0
  18. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/command_runner.py +0 -0
  19. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/diff_cover_tool.py +0 -0
  20. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/diff_quality_tool.py +0 -0
  21. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/git_path.py +0 -0
  22. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/hook.py +0 -0
  23. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/hookspecs.py +0 -0
  24. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/report_generator.py +0 -0
  25. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/templates/console_coverage_report.txt +0 -0
  26. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/templates/console_quality_report.txt +0 -0
  27. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/templates/external_style.css +0 -0
  28. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/templates/github_coverage_annotations.txt +0 -0
  29. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/templates/html_coverage_report.html +0 -0
  30. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/templates/html_quality_report.html +0 -0
  31. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/templates/markdown_coverage_report.md +0 -0
  32. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/templates/markdown_quality_report.md +0 -0
  33. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/templates/snippet_content.html +0 -0
  34. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/templates/snippet_content.md +0 -0
  35. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/templates/snippet_content.txt +0 -0
  36. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/templates/snippet_style.html +0 -0
  37. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/util.py +0 -0
  38. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/violationsreporters/__init__.py +0 -0
  39. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/violationsreporters/clover.py +0 -0
  40. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/violationsreporters/java_violations_reporter.py +0 -0
  41. {diff_cover-10.6.0 → diff_cover-11.0.0}/diff_cover/violationsreporters/violations_reporter.py +0 -0
  42. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/__init__.py +0 -0
  43. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/conftest.py +0 -0
  44. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/add_console_report.txt +0 -0
  45. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/add_html_report.html +0 -0
  46. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/add_json_report.json +0 -0
  47. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/add_json_report_float.json +0 -0
  48. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/add_markdown_report.md +0 -0
  49. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/changed_console_report.txt +0 -0
  50. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/changed_html_report.html +0 -0
  51. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/coverage.xml +0 -0
  52. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/coverage1.xml +0 -0
  53. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/coverage2.xml +0 -0
  54. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/coverage_missing_lines.xml +0 -0
  55. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/cpp_functions_console_report.txt +0 -0
  56. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/cpp_functions_coverage.lcov +0 -0
  57. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/delete_console_report.txt +0 -0
  58. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/delete_html_report.html +0 -0
  59. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/dotnet_coverage.xml +0 -0
  60. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/empty.txt +0 -0
  61. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/empty_pycodestyle_violations.txt +0 -0
  62. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/expand_console_report.txt +0 -0
  63. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/external_css_html_report.html +0 -0
  64. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/external_style.css +0 -0
  65. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_add.txt +0 -0
  66. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_changed.txt +0 -0
  67. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_code_dupe.txt +0 -0
  68. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_cpp.txt +0 -0
  69. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_cpp_functions.txt +0 -0
  70. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_delete.txt +0 -0
  71. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_dotnet.txt +0 -0
  72. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_external_css.txt +0 -0
  73. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_lua.txt +0 -0
  74. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_moved.txt +0 -0
  75. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_mult.txt +0 -0
  76. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_python.txt +0 -0
  77. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_subdir.txt +0 -0
  78. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_typescript.txt +0 -0
  79. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_typescript_branches.txt +0 -0
  80. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_unicode.txt +0 -0
  81. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_violations.txt +0 -0
  82. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/git_diff_violations_two_files.txt +0 -0
  83. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/hello.py +0 -0
  84. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/hi.py +0 -0
  85. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/html_report.html +0 -0
  86. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/html_report_empty.html +0 -0
  87. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/html_report_one_snippet.html +0 -0
  88. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/html_report_two_snippets.html +0 -0
  89. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/lcov.info +0 -0
  90. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/lua_console_report.txt +0 -0
  91. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/luacoverage.xml +0 -0
  92. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/markdown_report_one_snippet.md +0 -0
  93. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/markdown_report_two_snippets.md +0 -0
  94. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/moved_console_report.txt +0 -0
  95. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/moved_coverage.xml +0 -0
  96. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/moved_html_report.html +0 -0
  97. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/mult_inputs_console_report.txt +0 -0
  98. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/mult_inputs_html_report.html +0 -0
  99. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pycodestyle_report.txt +0 -0
  100. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pycodestyle_violations_report.html +0 -0
  101. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pycodestyle_violations_report.json +0 -0
  102. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pycodestyle_violations_report.md +0 -0
  103. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pycodestyle_violations_report.txt +0 -0
  104. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pycodestyle_violations_report_external_css.html +0 -0
  105. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pycodestyle_violations_report_float.json +0 -0
  106. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pyflakes_two_files.txt +0 -0
  107. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pyflakes_violations_report.html +0 -0
  108. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pyflakes_violations_report.txt +0 -0
  109. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pylint_dupe.txt +0 -0
  110. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pylint_dupe_violations_report.txt +0 -0
  111. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pylint_report.txt +0 -0
  112. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pylint_violations_console_report.txt +0 -0
  113. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pylint_violations_report.html +0 -0
  114. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pylint_violations_report.txt +0 -0
  115. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/pylintrc +0 -0
  116. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/real_cpp_console_report.txt +0 -0
  117. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/real_cpp_coverage.lcov +0 -0
  118. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/real_python_console_report.txt +0 -0
  119. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/real_python_coverage.lcov +0 -0
  120. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/real_typescript_console_report.txt +0 -0
  121. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/real_typescript_coverage.lcov +0 -0
  122. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/show_uncovered_lines_console.txt +0 -0
  123. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet.css +0 -0
  124. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_8859.py +0 -0
  125. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_arabic_output.html +0 -0
  126. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_default.html +0 -0
  127. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_invalid_violations.html +0 -0
  128. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_list.html +0 -0
  129. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_list.md +0 -0
  130. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_list2.md +0 -0
  131. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_list3.md +0 -0
  132. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_no_filename_ext.html +0 -0
  133. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_src.py +0 -0
  134. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_src2.cpp +0 -0
  135. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_src3.cpp +0 -0
  136. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_unicode.html +0 -0
  137. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_unicode.py +0 -0
  138. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/snippet_unicode_html_output.html +0 -0
  139. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/subdir_coverage_console_report.txt +0 -0
  140. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/subdir_coverage_html_report.html +0 -0
  141. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/test_src.txt +0 -0
  142. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/typescript_branches_console_report.txt +0 -0
  143. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/typescript_branches_coverage.lcov +0 -0
  144. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/unicode_console_report.txt +0 -0
  145. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/unicode_coverage.xml +0 -0
  146. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/unicode_html_report.html +0 -0
  147. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/unicode_test_src.txt +0 -0
  148. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/fixtures/violations_test_file.py +0 -0
  149. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/helpers.py +0 -0
  150. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/snippet_list_unicode.html +0 -0
  151. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_clover_violations_reporter/test.xml +0 -0
  152. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_clover_violations_reporter.py +0 -0
  153. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_command_runner_missing_executable.py +0 -0
  154. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_diff_cover_main.py +0 -0
  155. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_diff_cover_tool.py +0 -0
  156. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_diff_quality_main.py +0 -0
  157. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_git_diff.py +0 -0
  158. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_git_diff_file.py +0 -0
  159. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_git_path.py +0 -0
  160. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_java_violations_reporter.py +0 -0
  161. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_report_generator.py +0 -0
  162. {diff_cover-10.6.0 → diff_cover-11.0.0}/tests/test_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: diff_cover
3
- Version: 10.6.0
3
+ Version: 11.0.0
4
4
  Summary: Run coverage and linting reports on diffs
5
5
  Project-URL: Homepage, https://github.com/Bachmann1234/diff-cover
6
6
  Project-URL: Repository, https://github.com/Bachmann1234/diff-cover
@@ -14,21 +14,20 @@ Classifier: Intended Audience :: Developers
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Programming Language :: Python
16
16
  Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.10
18
17
  Classifier: Programming Language :: Python :: 3.11
19
18
  Classifier: Programming Language :: Python :: 3.12
20
19
  Classifier: Programming Language :: Python :: 3.13
21
20
  Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: 3.15
22
22
  Classifier: Programming Language :: Python :: Implementation :: CPython
23
23
  Classifier: Topic :: Software Development :: Quality Assurance
24
24
  Classifier: Topic :: Software Development :: Testing
25
- Requires-Python: >=3.10
25
+ Requires-Python: >=3.11
26
26
  Requires-Dist: chardet>=3.0.0
27
27
  Requires-Dist: jinja2>=2.7.1
28
28
  Requires-Dist: pluggy<2,>=0.13.1
29
29
  Requires-Dist: pygments<3,>=2.19.1
30
30
  Provides-Extra: toml
31
- Requires-Dist: tomli>=1.2.1; extra == 'toml'
32
31
  Description-Content-Type: text/x-rst
33
32
 
34
33
  diff-cover |pypi-version| |conda-version| |build-status|
@@ -1,17 +1,6 @@
1
1
  import abc
2
2
  import enum
3
-
4
- try:
5
- import tomli as toml
6
-
7
- _HAS_TOML = True
8
- except ImportError: # pragma: no cover
9
- try:
10
- import tomllib as toml
11
-
12
- _HAS_TOML = True
13
- except ImportError:
14
- _HAS_TOML = False
3
+ import tomllib
15
4
 
16
5
 
17
6
  class Tool(enum.Enum):
@@ -42,11 +31,8 @@ class TOMLParser(ConfigParser):
42
31
  if not self._file_name.endswith(".toml"):
43
32
  return None
44
33
 
45
- if not _HAS_TOML:
46
- raise ParserError("No Toml lib installed")
47
-
48
34
  with open(self._file_name, "rb") as file_handle:
49
- config = toml.load(file_handle)
35
+ config = tomllib.load(file_handle)
50
36
 
51
37
  config = config.get("tool", {}).get(self._section, {})
52
38
  if not config:
@@ -98,8 +98,16 @@ class BaseDiffReporter(ABC):
98
98
  if self._fnmatch(basename, exclude):
99
99
  return True
100
100
 
101
+ # A pattern that names a directory - "subdir/*", the shape the README
102
+ # uses for include patterns - matches neither the basename nor the
103
+ # absolute path, so it used to exclude nothing at all and said so
104
+ # nowhere. Match the path as the diff reports it, which is relative to
105
+ # the repository root.
106
+ if self._fnmatch(to_unix_path(path), exclude):
107
+ return True
108
+
101
109
  absolute_path = os.path.abspath(path)
102
- return self._fnmatch(absolute_path, exclude)
110
+ return self._fnmatch(to_unix_path(absolute_path), exclude)
103
111
 
104
112
 
105
113
  class GitDiffReporter(BaseDiffReporter):
@@ -129,7 +129,7 @@ class GitDiffFileTool(GitDiffTool):
129
129
  Raises a `GitDiffError` if the file cannot be read.
130
130
  """
131
131
  try:
132
- with open(self.diff_file_path, "r", encoding="utf-8") as file:
132
+ with open(self.diff_file_path, encoding="utf-8") as file:
133
133
  return file.read()
134
134
  except OSError as e:
135
135
  error_message = (
@@ -217,13 +217,20 @@ class Snippet:
217
217
  """
218
218
  Return a Terminal-friendly (with ANSI color sequences) representation of the snippet.
219
219
  """
220
- formatter = TerminalFormatter(
221
- linenos=True,
222
- colorscheme=None,
223
- linenostart=self._start_line,
220
+ # Pygments' TerminalFormatter ignores `linenostart` and always numbers
221
+ # from 1, so the snippet is rendered without line numbers and they are
222
+ # added here, in the same `0001: ` form, starting at the snippet's
223
+ # first line. See #283.
224
+ rendered = pygments.format(
225
+ self.src_tokens(), TerminalFormatter(colorscheme=None)
224
226
  )
225
-
226
- return pygments.format(self.src_tokens(), formatter)
227
+ numbered = [
228
+ f"{line_number:04d}: {line}"
229
+ for line_number, line in enumerate(
230
+ rendered.split("\n"), start=self._start_line
231
+ )
232
+ ]
233
+ return "\n".join(numbered) + "\n"
227
234
 
228
235
  def src_tokens(self):
229
236
  """
@@ -1,6 +1,7 @@
1
1
  import copy
2
2
  import os
3
3
  import re
4
+ import shlex
4
5
  import sys
5
6
  from abc import ABC, abstractmethod
6
7
  from collections import defaultdict, namedtuple
@@ -12,6 +13,15 @@ from diff_cover.util import to_unix_path
12
13
  Violation = namedtuple("Violation", "line, message")
13
14
 
14
15
 
16
+ def split_options(options):
17
+ """Split quoted options without consuming backslashes in paths."""
18
+ lexer = shlex.shlex(options, posix=True)
19
+ lexer.whitespace_split = True
20
+ lexer.escape = ""
21
+ lexer.commenters = ""
22
+ return list(lexer)
23
+
24
+
15
25
  class QualityReporterError(Exception):
16
26
  """
17
27
  A quality reporter command produced an error.
@@ -174,8 +184,7 @@ class QualityReporter(BaseViolationReporter):
174
184
  raise OSError(msg)
175
185
  command = copy.deepcopy(self.driver.command)
176
186
  if self.options:
177
- for arg in self.options.split():
178
- command.append(arg)
187
+ command += split_options(self.options)
179
188
  command.append(relative_src_path.encode(sys.getfilesystemencoding()))
180
189
 
181
190
  stdout, stderr = execute(command, self.driver.exit_codes)
@@ -1,12 +1,12 @@
1
1
  [project]
2
2
  name = "diff_cover"
3
- version = "10.6.0"
3
+ version = "11.0.0"
4
4
  description = "Run coverage and linting reports on diffs"
5
5
  authors = [{ name = "See Contributors" }]
6
6
  license = "Apache-2.0"
7
7
  license-files = ["LICENSE", "NOTICE"]
8
8
  readme = "README.rst"
9
- requires-python = ">=3.10"
9
+ requires-python = ">=3.11"
10
10
  classifiers = [
11
11
  "Development Status :: 5 - Production/Stable",
12
12
  "Environment :: Console",
@@ -14,11 +14,11 @@ classifiers = [
14
14
  "Operating System :: OS Independent",
15
15
  "Programming Language :: Python",
16
16
  "Programming Language :: Python :: 3",
17
- "Programming Language :: Python :: 3.10",
18
17
  "Programming Language :: Python :: 3.11",
19
18
  "Programming Language :: Python :: 3.12",
20
19
  "Programming Language :: Python :: 3.13",
21
20
  "Programming Language :: Python :: 3.14",
21
+ "Programming Language :: Python :: 3.15",
22
22
  "Programming Language :: Python :: Implementation :: CPython",
23
23
  "Topic :: Software Development :: Testing",
24
24
  "Topic :: Software Development :: Quality Assurance",
@@ -31,7 +31,8 @@ dependencies = [
31
31
  ]
32
32
 
33
33
  [project.optional-dependencies]
34
- toml = ["tomli>=1.2.1"]
34
+ # Kept so existing `diff_cover[toml]` installs keep working; tomllib is stdlib on 3.11+
35
+ toml = []
35
36
 
36
37
  [project.urls]
37
38
  Homepage = "https://github.com/Bachmann1234/diff-cover"
@@ -49,7 +50,7 @@ dev = [
49
50
  "pytest-xdist>=3.6.1,<4",
50
51
  "pycodestyle>=2.9.1",
51
52
  "flake8>=7.0.0",
52
- "pyflakes>=3.3.2,<4",
53
+ "pyflakes>=3.3.2,<5",
53
54
  "pylint>=3.3.4,<5.0.0",
54
55
  "pydocstyle>=6.1.1,<7",
55
56
  "doc8==2.0.0",
@@ -68,7 +69,7 @@ include = ["diff_cover", "tests", "README.rst"]
68
69
 
69
70
  [tool.ruff]
70
71
  line-length = 88
71
- target-version = "py310"
72
+ target-version = "py311"
72
73
  exclude = [
73
74
  ".venv",
74
75
  "tests/fixtures",
@@ -1,6 +1,5 @@
1
1
  import pytest
2
2
 
3
- from diff_cover import config_parser
4
3
  from diff_cover.config_parser import ParserError, TOMLParser, Tool, get_config
5
4
 
6
5
  tools = pytest.mark.parametrize("tool", list(Tool))
@@ -12,13 +11,6 @@ class TestTOMLParser:
12
11
  parser = TOMLParser("myfile", tool)
13
12
  assert parser.parse() is None
14
13
 
15
- @tools
16
- def test_parse_but_no_tomli_installed(self, tool, mocker):
17
- mocker.patch.object(config_parser, "_HAS_TOML", False)
18
- parser = TOMLParser("myfile.toml", tool)
19
- with pytest.raises(ParserError):
20
- parser.parse()
21
-
22
14
  @pytest.mark.parametrize(
23
15
  "tool,content",
24
16
  [
@@ -99,6 +99,32 @@ def test_name_include_untracked(git_diff):
99
99
  ["file1.py", "file3.py"],
100
100
  to_unix_paths(["subdir2/file2.py"]),
101
101
  ),
102
+ # exclude by a path pattern rather than a bare filename
103
+ (
104
+ [],
105
+ ["subdir1/*"],
106
+ to_unix_paths(["file3.py", "README.md", "subdir2/file2.py"]),
107
+ ),
108
+ # the same shape the README shows for include patterns
109
+ (
110
+ [],
111
+ ["subdir1/**"],
112
+ to_unix_paths(["file3.py", "README.md", "subdir2/file2.py"]),
113
+ ),
114
+ # a path pattern that matches nothing leaves every path in place
115
+ (
116
+ [],
117
+ ["subdir3/*"],
118
+ to_unix_paths(
119
+ ["file3.py", "README.md", "subdir1/file1.py", "subdir2/file2.py"]
120
+ ),
121
+ ),
122
+ # several path patterns at once
123
+ (
124
+ [],
125
+ ["subdir1/*", "subdir2/*"],
126
+ to_unix_paths(["file3.py", "README.md"]),
127
+ ),
102
128
  ],
103
129
  )
104
130
  def test_git_path_selection(
@@ -216,20 +216,20 @@ class TestDiffCoverIntegration:
216
216
  == 0
217
217
  )
218
218
  output = capsys.readouterr().out
219
- with open("add_console_report.txt", "r", encoding="utf-8") as f:
219
+ with open("add_console_report.txt", encoding="utf-8") as f:
220
220
  actual = f.read()
221
221
  assert actual in output
222
- with open("add_html_report.html", "r", encoding="utf-8") as f:
222
+ with open("add_html_report.html", encoding="utf-8") as f:
223
223
  actual = clean_html(f.read(), clear_inline_css=True)
224
224
  # can't compare the output inside <head> since it changes
225
225
  # a lot so we just compare the body
226
226
  actual = actual[actual.find("</head>") :]
227
227
  assert len(actual) > 20
228
228
  assert actual in output
229
- with open("add_json_report.json", "r", encoding="utf-8") as f:
229
+ with open("add_json_report.json", encoding="utf-8") as f:
230
230
  actual = json.dumps(json.loads(f.read()))
231
231
  assert actual in output
232
- with open("add_markdown_report.md", "r", encoding="utf-8") as f:
232
+ with open("add_markdown_report.md", encoding="utf-8") as f:
233
233
  actual = f.read()
234
234
  assert actual in output
235
235
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  """Test for diff_cover.snippets"""
4
4
 
5
- import os
5
+ import contextlib
6
6
 
7
7
  import pytest
8
8
  from pygments.token import Token
@@ -135,12 +135,11 @@ def patch_path_tool(mocker):
135
135
 
136
136
 
137
137
  @pytest.fixture
138
- def switch_to_fixture_dir(request):
138
+ def switch_to_fixture_dir():
139
139
  # Need to be in the fixture directory
140
140
  # so the source path is displayed correctly
141
- os.chdir(fixture_path(""))
142
- yield
143
- os.chdir(request.config.invocation_dir)
141
+ with contextlib.chdir(fixture_path("")):
142
+ yield
144
143
 
145
144
 
146
145
  def test_style_defs():
@@ -364,6 +363,43 @@ def test_html_marks_covered_lines_with_nonzero_start_line():
364
363
  assert "hll" in rendered
365
364
 
366
365
 
366
+ def test_terminal_numbers_lines_from_start_line():
367
+ """
368
+ The terminal snippet must be numbered from the snippet's first line,
369
+ as the HTML and Markdown ones are, not from 1. See #283.
370
+ """
371
+ src_tokens = [
372
+ (Token.Text, "Line 217\n"),
373
+ (Token.Text, "Line 218\n"),
374
+ (Token.Text, "Line 219\n"),
375
+ ]
376
+ snippet = Snippet(
377
+ src_tokens,
378
+ "test.txt",
379
+ start_line=217,
380
+ last_line=219,
381
+ violation_lines=[218],
382
+ lexer_name=None,
383
+ )
384
+
385
+ lines = snippet.terminal().splitlines()
386
+
387
+ assert lines[:3] == ["0217: Line 217", "0218: Line 218", "0219: Line 219"]
388
+
389
+
390
+ def test_terminal_numbers_lines_from_one_for_a_snippet_at_the_top():
391
+ snippet = Snippet(
392
+ [(Token.Text, "first\n"), (Token.Text, "second\n")],
393
+ "test.txt",
394
+ start_line=1,
395
+ last_line=2,
396
+ violation_lines=[1],
397
+ lexer_name=None,
398
+ )
399
+
400
+ assert snippet.terminal().splitlines()[:2] == ["0001: first", "0002: second"]
401
+
402
+
367
403
  def test_end_range_on_violation(tmpfile):
368
404
  src_path = tmpfile(40)
369
405
 
@@ -1278,6 +1278,32 @@ class TestLcovCoverageReporterTest:
1278
1278
 
1279
1279
 
1280
1280
  class TestPycodestyleQualityReporterTest:
1281
+ @pytest.mark.parametrize(
1282
+ "options, config",
1283
+ [
1284
+ ("--config='lint config.ini' --ignore='E501'", "lint config.ini"),
1285
+ (
1286
+ r"--config=C:\lint\config.ini --ignore='E501'",
1287
+ r"C:\lint\config.ini",
1288
+ ),
1289
+ ],
1290
+ )
1291
+ def test_quality_quoted_options(self, mocker, options, config):
1292
+ execute = mocker.patch.object(base, "execute", return_value=("", ""))
1293
+ quality = QualityReporter(pycodestyle_driver, options=options)
1294
+ quality.driver_tool_installed = True
1295
+
1296
+ assert quality.violations("file1.py") == []
1297
+ execute.assert_called_once_with(
1298
+ [
1299
+ "pycodestyle",
1300
+ f"--config={config}",
1301
+ "--ignore=E501",
1302
+ b"file1.py",
1303
+ ],
1304
+ [0, 1],
1305
+ )
1306
+
1281
1307
  def test_quality(self, mocker, process_patcher):
1282
1308
  # Patch the output of `pycodestyle`
1283
1309
  mocker.patch.object(Popen, "communicate")
File without changes
File without changes
File without changes
File without changes