diff --git a/diff_cover/git_diff.py b/diff_cover/git_diff.py index 8bc6c1fa..cd46bbc7 100644 --- a/diff_cover/git_diff.py +++ b/diff_cover/git_diff.py @@ -72,14 +72,10 @@ def diff_committed(self, compare_branch="origin/main"): )[0] except CommandError as e: if "unknown revision" in str(e): - raise ValueError( - dedent( - f""" + raise ValueError(dedent(f""" Could not find the branch to compare to. Does '{compare_branch}' exist? the `--compare-branch` argument allows you to set a different branch. - """ - ) - ) from e + """)) from e raise def diff_unstaged(self): diff --git a/diff_cover/violationsreporters/violations_reporter.py b/diff_cover/violationsreporters/violations_reporter.py index bfe61ca1..585cdc6e 100644 --- a/diff_cover/violationsreporters/violations_reporter.py +++ b/diff_cover/violationsreporters/violations_reporter.py @@ -831,7 +831,7 @@ def parse_reports(self, reports): # Ignore any line that isn't matched # (for example, snippets from the source code) if match is not None: - (cppcheck_src_path, line_number, message) = match.groups() + cppcheck_src_path, line_number, message = match.groups() violation = Violation(int(line_number), message) violations_dict[util.to_unix_path(cppcheck_src_path)].append( diff --git a/poetry.lock b/poetry.lock index 0696c20e..b6739a9e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "astroid" @@ -17,46 +17,46 @@ typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} [[package]] name = "black" -version = "25.12.0" +version = "26.1.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "black-25.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f85ba1ad15d446756b4ab5f3044731bf68b777f8f9ac9cdabd2425b97cd9c4e8"}, - {file = "black-25.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:546eecfe9a3a6b46f9d69d8a642585a6eaf348bcbbc4d87a19635570e02d9f4a"}, - {file = "black-25.12.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17dcc893da8d73d8f74a596f64b7c98ef5239c2cd2b053c0f25912c4494bf9ea"}, - {file = "black-25.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:09524b0e6af8ba7a3ffabdfc7a9922fb9adef60fed008c7cd2fc01f3048e6e6f"}, - {file = "black-25.12.0-cp310-cp310-win_arm64.whl", hash = "sha256:b162653ed89eb942758efeb29d5e333ca5bb90e5130216f8369857db5955a7da"}, - {file = "black-25.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0cfa263e85caea2cff57d8f917f9f51adae8e20b610e2b23de35b5b11ce691a"}, - {file = "black-25.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a2f578ae20c19c50a382286ba78bfbeafdf788579b053d8e4980afb079ab9be"}, - {file = "black-25.12.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e1b65634b0e471d07ff86ec338819e2ef860689859ef4501ab7ac290431f9b"}, - {file = "black-25.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a3fa71e3b8dd9f7c6ac4d818345237dfb4175ed3bf37cd5a581dbc4c034f1ec5"}, - {file = "black-25.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:51e267458f7e650afed8445dc7edb3187143003d52a1b710c7321aef22aa9655"}, - {file = "black-25.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:31f96b7c98c1ddaeb07dc0f56c652e25bdedaac76d5b68a059d998b57c55594a"}, - {file = "black-25.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05dd459a19e218078a1f98178c13f861fe6a9a5f88fc969ca4d9b49eb1809783"}, - {file = "black-25.12.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1f68c5eff61f226934be6b5b80296cf6939e5d2f0c2f7d543ea08b204bfaf59"}, - {file = "black-25.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:274f940c147ddab4442d316b27f9e332ca586d39c85ecf59ebdea82cc9ee8892"}, - {file = "black-25.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:169506ba91ef21e2e0591563deda7f00030cb466e747c4b09cb0a9dae5db2f43"}, - {file = "black-25.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a05ddeb656534c3e27a05a29196c962877c83fa5503db89e68857d1161ad08a5"}, - {file = "black-25.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9ec77439ef3e34896995503865a85732c94396edcc739f302c5673a2315e1e7f"}, - {file = "black-25.12.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e509c858adf63aa61d908061b52e580c40eae0dfa72415fa47ac01b12e29baf"}, - {file = "black-25.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:252678f07f5bac4ff0d0e9b261fbb029fa530cfa206d0a636a34ab445ef8ca9d"}, - {file = "black-25.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bc5b1c09fe3c931ddd20ee548511c64ebf964ada7e6f0763d443947fd1c603ce"}, - {file = "black-25.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:0a0953b134f9335c2434864a643c842c44fba562155c738a2a37a4d61f00cad5"}, - {file = "black-25.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2355bbb6c3b76062870942d8cc450d4f8ac71f9c93c40122762c8784df49543f"}, - {file = "black-25.12.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9678bd991cc793e81d19aeeae57966ee02909877cb65838ccffef24c3ebac08f"}, - {file = "black-25.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:97596189949a8aad13ad12fcbb4ae89330039b96ad6742e6f6b45e75ad5cfd83"}, - {file = "black-25.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:778285d9ea197f34704e3791ea9404cd6d07595745907dd2ce3da7a13627b29b"}, - {file = "black-25.12.0-py3-none-any.whl", hash = "sha256:48ceb36c16dbc84062740049eef990bb2ce07598272e673c17d1a7720c71c828"}, - {file = "black-25.12.0.tar.gz", hash = "sha256:8d3dd9cea14bff7ddc0eb243c811cdb1a011ebb4800a5f0335a01a68654796a7"}, + {file = "black-26.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ca699710dece84e3ebf6e92ee15f5b8f72870ef984bf944a57a777a48357c168"}, + {file = "black-26.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5e8e75dabb6eb83d064b0db46392b25cabb6e784ea624219736e8985a6b3675d"}, + {file = "black-26.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eb07665d9a907a1a645ee41a0df8a25ffac8ad9c26cdb557b7b88eeeeec934e0"}, + {file = "black-26.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:7ed300200918147c963c87700ccf9966dceaefbbb7277450a8d646fc5646bf24"}, + {file = "black-26.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:c5b7713daea9bf943f79f8c3b46f361cc5229e0e604dcef6a8bb6d1c37d9df89"}, + {file = "black-26.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3cee1487a9e4c640dc7467aaa543d6c0097c391dc8ac74eb313f2fbf9d7a7cb5"}, + {file = "black-26.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d62d14ca31c92adf561ebb2e5f2741bf8dea28aef6deb400d49cca011d186c68"}, + {file = "black-26.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb1dafbbaa3b1ee8b4550a84425aac8874e5f390200f5502cf3aee4a2acb2f14"}, + {file = "black-26.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:101540cb2a77c680f4f80e628ae98bd2bd8812fb9d72ade4f8995c5ff019e82c"}, + {file = "black-26.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:6f3977a16e347f1b115662be07daa93137259c711e526402aa444d7a88fdc9d4"}, + {file = "black-26.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6eeca41e70b5f5c84f2f913af857cf2ce17410847e1d54642e658e078da6544f"}, + {file = "black-26.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dd39eef053e58e60204f2cdf059e2442e2eb08f15989eefe259870f89614c8b6"}, + {file = "black-26.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9459ad0d6cd483eacad4c6566b0f8e42af5e8b583cee917d90ffaa3778420a0a"}, + {file = "black-26.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a19915ec61f3a8746e8b10adbac4a577c6ba9851fa4a9e9fbfbcf319887a5791"}, + {file = "black-26.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:643d27fb5facc167c0b1b59d0315f2674a6e950341aed0fc05cf307d22bf4954"}, + {file = "black-26.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ba1d768fbfb6930fc93b0ecc32a43d8861ded16f47a40f14afa9bb04ab93d304"}, + {file = "black-26.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2b807c240b64609cb0e80d2200a35b23c7df82259f80bef1b2c96eb422b4aac9"}, + {file = "black-26.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1de0f7d01cc894066a1153b738145b194414cc6eeaad8ef4397ac9abacf40f6b"}, + {file = "black-26.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:91a68ae46bf07868963671e4d05611b179c2313301bd756a89ad4e3b3db2325b"}, + {file = "black-26.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:be5e2fe860b9bd9edbf676d5b60a9282994c03fbbd40fe8f5e75d194f96064ca"}, + {file = "black-26.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9dc8c71656a79ca49b8d3e2ce8103210c9481c57798b48deeb3a8bb02db5f115"}, + {file = "black-26.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b22b3810451abe359a964cc88121d57f7bce482b53a066de0f1584988ca36e79"}, + {file = "black-26.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:53c62883b3f999f14e5d30b5a79bd437236658ad45b2f853906c7cbe79de00af"}, + {file = "black-26.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:f016baaadc423dc960cdddf9acae679e71ee02c4c341f78f3179d7e4819c095f"}, + {file = "black-26.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:66912475200b67ef5a0ab665011964bf924745103f51977a78b4fb92a9fc1bf0"}, + {file = "black-26.1.0-py3-none-any.whl", hash = "sha256:1054e8e47ebd686e078c0bb0eaf31e6ce69c966058d122f2c0c950311f9f3ede"}, + {file = "black-26.1.0.tar.gz", hash = "sha256:d294ac3340eef9c9eb5d29288e96dc719ff269a88e27b396340459dd85da4c58"}, ] [package.dependencies] click = ">=8.0.0" mypy-extensions = ">=0.4.3" packaging = ">=22.0" -pathspec = ">=0.9.0" +pathspec = ">=1.0.0" platformdirs = ">=2" pytokens = ">=0.3.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} @@ -102,7 +102,7 @@ description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["dev"] -markers = "platform_system == \"Windows\" or sys_platform == \"win32\"" +markers = "sys_platform == \"win32\" or platform_system == \"Windows\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -270,7 +270,7 @@ description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["dev"] -markers = "python_version == \"3.10\"" +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, @@ -487,16 +487,22 @@ files = [ [[package]] name = "pathspec" -version = "0.12.1" +version = "1.0.4" description = "Utility library for gitignore style pattern matching of file paths." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, + {file = "pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723"}, + {file = "pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645"}, ] +[package.extras] +hyperscan = ["hyperscan (>=0.7)"] +optional = ["typing-extensions (>=4)"] +re2 = ["google-re2 (>=1.1)"] +tests = ["pytest (>=9)", "typing-extensions (>=4.15)"] + [[package]] name = "pbr" version = "6.1.1" @@ -911,7 +917,7 @@ files = [ {file = "tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a"}, {file = "tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c"}, ] -markers = {main = "extra == \"toml\"", dev = "python_version == \"3.10\""} +markers = {main = "extra == \"toml\"", dev = "python_version < \"3.11\""} [[package]] name = "tomlkit" @@ -932,7 +938,7 @@ description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" groups = ["dev"] -markers = "python_version == \"3.10\"" +markers = "python_version < \"3.11\"" files = [ {file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"}, {file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"}, @@ -944,4 +950,4 @@ toml = ["tomli"] [metadata] lock-version = "2.1" python-versions = ">=3.10" -content-hash = "b663351213d46fa0eeedf0dca90ae71c81d0cf896f5a850624c25e152e3b195c" +content-hash = "4db2a878260bf9f7d53c6f038153b6a223bf21319a6e1bfb9001c55be069d27d" diff --git a/pyproject.toml b/pyproject.toml index a86a99ea..9c6c33b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,7 +58,7 @@ pyflakes = "^3.3.2" pylint = ">=3.3.4,<5.0.0" pylint-pytest = "^1.1.8" pydocstyle = "^6.1.1" -black = "^25.1.0" +black = "^26.1.0" isort = ">=6.0.1,<8.0.0" doc8 = "2.0.0" ruff = ">=0.11.10,<0.15.0" diff --git a/tests/test_diff_reporter.py b/tests/test_diff_reporter.py index 5e50e810..fa523cd2 100644 --- a/tests/test_diff_reporter.py +++ b/tests/test_diff_reporter.py @@ -246,8 +246,7 @@ def test_ignore_lines_outside_src(diff, git_diff): def test_one_line_file(diff, git_diff): # Files with only one line have a special format # in which the "length" part of the hunk is not specified - diff_str = dedent( - """ + diff_str = dedent(""" diff --git a/diff_cover/one_line.txt b/diff_cover/one_line.txt index 0867e73..9daeafb 100644 --- a/diff_cover/one_line.txt @@ -256,8 +255,7 @@ def test_one_line_file(diff, git_diff): test -test -test - """ - ).strip() + """).strip() # Configure the git diff output _set_git_diff_output(diff, git_diff, diff_str, "", "") @@ -291,8 +289,7 @@ def test_git_deleted_lines(diff, git_diff): def test_git_unicode_filename(diff, git_diff): # Filenames with unicode characters have double quotes surrounding them # in the git diff output. - diff_str = dedent( - """ + diff_str = dedent(""" diff --git "a/unic\303\270\342\210\202e\314\201.txt" "b/unic\303\270\342\210\202e\314\201.txt" new file mode 100644 index 0000000..248ebea @@ -302,8 +299,7 @@ def test_git_unicode_filename(diff, git_diff): +μῆνιν ἄειδε θεὰ Πηληϊάδεω Ἀχιλῆος +οὐλομένην, ἣ μυρί᾽ Ἀχαιοῖς ἄλγε᾽ ἔθηκε, +πολλὰς δ᾽ ἰφθίμους ψυχὰς Ἄϊδι προΐαψεν - """ - ).strip() + """).strip() _set_git_diff_output(diff, git_diff, diff_str, "", "") # Get the lines changed in the diff @@ -429,28 +425,22 @@ def test_git_diff_error( diff, git_diff, ): - invalid_hunk_str = dedent( - """ + invalid_hunk_str = dedent(""" diff --git a/subdir/file1.py b/subdir/file1.py @@ invalid @@ Text - """ - ).strip() + """).strip() no_src_line_str = "@@ -33,10 +34,13 @@ Text" - non_numeric_lines = dedent( - """ + non_numeric_lines = dedent(""" diff --git a/subdir/file1.py b/subdir/file1.py @@ -1,2 +a,b @@ - """ - ).strip() + """).strip() - missing_line_num = dedent( - """ + missing_line_num = dedent(""" diff --git a/subdir/file1.py b/subdir/file1.py @@ -1,2 + @@ - """ - ).strip() + """).strip() missing_src_str = "diff --git " @@ -478,16 +468,14 @@ def test_git_diff_error( def test_plus_sign_in_hunk_bug(diff, git_diff): # This was a bug that caused a parse error - diff_str = dedent( - """ + diff_str = dedent(""" diff --git a/file.py b/file.py @@ -16,16 +16,7 @@ 1 + 2 + test + test + test + test - """ - ) + """) _set_git_diff_output(diff, git_diff, diff_str, "", "") @@ -498,16 +486,14 @@ def test_plus_sign_in_hunk_bug(diff, git_diff): def test_terminating_chars_in_hunk(diff, git_diff): # Check what happens when there's an @@ symbol after the # first terminating @@ symbol - diff_str = dedent( - """ + diff_str = dedent(""" diff --git a/file.py b/file.py @@ -16,16 +16,7 @@ and another +23,2 @@ symbol + test + test + test + test - """ - ) + """) _set_git_diff_output(diff, git_diff, diff_str, "", "") @@ -518,8 +504,7 @@ def test_terminating_chars_in_hunk(diff, git_diff): def test_merge_conflict_diff(diff, git_diff): # Handle different git diff format when in the middle # of a merge conflict - diff_str = dedent( - """ + diff_str = dedent(""" diff --cc subdir/src.py index d2034c0,e594d54..0000000 diff --cc subdir/src.py @@ -531,8 +516,7 @@ def test_merge_conflict_diff(diff, git_diff): ++<<<<<< HEAD + test ++======= - """ - ) + """) _set_git_diff_output(diff, git_diff, diff_str, "", "") diff --git a/tests/test_integration.py b/tests/test_integration.py index 07b50d6d..4f21816b 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -2,6 +2,7 @@ # pylint: disable=use-implicit-booleaness-not-comparison """High-level integration tests of diff-cover tool.""" + import json import os import os.path @@ -383,8 +384,7 @@ def test_dot_net_diff(self, mocker, runbin, patch_git_command, capsys): mocker.patch.object(GitPathTool, "_git_root", return_value="/code/samplediff/") patch_git_command.set_stdout("git_diff_dotnet.txt") assert runbin(["dotnet_coverage.xml"]) == 0 - expected = textwrap.dedent( - f"""\ + expected = textwrap.dedent(f"""\ ------------- Diff Coverage Diff: origin/main...HEAD, staged and unstaged changes @@ -395,8 +395,7 @@ def test_dot_net_diff(self, mocker, runbin, patch_git_command, capsys): Missing: 3 lines Coverage: 0% ------------- - """ - ) + """) assert capsys.readouterr().out.strip() == expected.strip() def test_unicode_html(self, runbin, patch_git_command): @@ -469,22 +468,19 @@ def test_github_silent(self, runbin, patch_git_command, capsys): assert ( runbin(["coverage.xml", "--format", "github-annotations:notice", "-q"]) == 0 ) - expected = textwrap.dedent( - """\ + expected = textwrap.dedent("""\ ::notice file=test_src.txt,line=2,title=Missing Coverage::Line 2 missing coverage ::notice file=test_src.txt,line=4,title=Missing Coverage::Line 4 missing coverage ::notice file=test_src.txt,line=6,title=Missing Coverage::Line 6 missing coverage ::notice file=test_src.txt,line=8,title=Missing Coverage::Line 8 missing coverage ::notice file=test_src.txt,line=10,title=Missing Coverage::Line 10 missing coverage - """ - ) + """) assert capsys.readouterr().out == expected @pytest.mark.usefixtures("patch_git_command") def test_github_fully_covered(self, runbin, capsys): assert runbin(["coverage2.xml", "--format", "github-annotations:notice"]) == 0 - expected = textwrap.dedent( - """\ + expected = textwrap.dedent("""\ ------------- Diff Coverage Diff: origin/main...HEAD, staged and unstaged changes @@ -492,15 +488,13 @@ def test_github_fully_covered(self, runbin, capsys): No lines with coverage information in this diff. ------------- - """ - ) + """) assert capsys.readouterr().out == expected def test_github_empty_diff(self, runbin, patch_git_command, capsys): patch_git_command.set_stdout("") assert runbin(["coverage.xml", "--format", "github-annotations:notice"]) == 0 - expected = textwrap.dedent( - """\ + expected = textwrap.dedent("""\ ------------- Diff Coverage Diff: origin/main...HEAD, staged and unstaged changes @@ -508,8 +502,7 @@ def test_github_empty_diff(self, runbin, patch_git_command, capsys): No lines with coverage information in this diff. ------------- - """ - ) + """) assert capsys.readouterr().out == expected def test_real_world_cpp_lcov_coverage(self, runbin, patch_git_command, capsys): diff --git a/tests/test_java_violations_reporter.py b/tests/test_java_violations_reporter.py index fd1f18fc..443f89c4 100644 --- a/tests/test_java_violations_reporter.py +++ b/tests/test_java_violations_reporter.py @@ -62,14 +62,10 @@ def test_quality(self, process_patcher): # Patch the output of `checkstyle` process_patcher( ( - dedent( - """ + dedent(""" [WARN] ../new_file.java:1:1: Line contains a tab character. [WARN] ../new_file.java:13: 'if' construct must use '{}'s. - """ - ) - .strip() - .encode("ascii"), + """).strip().encode("ascii"), "", ) ) @@ -127,8 +123,7 @@ def test_quality(self, process_patcher): # Patch the output of `checkstyle` process_patcher( ( - dedent( - """ + dedent(""" @@ -144,10 +139,7 @@ def test_quality(self, process_patcher): - """ - ) - .strip() - .encode("ascii"), + """).strip().encode("ascii"), "", ) ) @@ -187,16 +179,14 @@ def test_quality_error(self, mocker, process_patcher): # Patch the output stderr/stdout and returncode of `checkstyle` process_patcher( ( - dedent( - """ + dedent(""" - """ - ), + """), b"oops", ), status_code=1, @@ -216,9 +206,7 @@ def test_quality_pregenerated_report(self): # When the user provides us with a pre-generated checkstyle report # then use that instead of calling checkstyle directly. checkstyle_reports = [ - BytesIO( - dedent( - """ + BytesIO(dedent(""" @@ -231,14 +219,8 @@ def test_quality_pregenerated_report(self): - """ - ) - .strip() - .encode("utf-8") - ), - BytesIO( - dedent( - """ + """).strip().encode("utf-8")), + BytesIO(dedent(""" @@ -248,11 +230,7 @@ def test_quality_pregenerated_report(self): - """ - ) - .strip() - .encode("utf-8") - ), + """).strip().encode("utf-8")), ] # Generate the violation report @@ -307,9 +285,7 @@ def test_quality_pregenerated_report(self): # When the user provides us with a pre-generated findbugs report # then use that instead of calling findbugs directly. findbugs_reports = [ - BytesIO( - dedent( - """ + BytesIO(dedent(""" @@ -333,14 +309,8 @@ def test_quality_pregenerated_report(self): - """ - ) - .strip() - .encode("utf-8") - ), - BytesIO( - dedent( - """ + """).strip().encode("utf-8")), + BytesIO(dedent(""" @@ -364,15 +334,9 @@ def test_quality_pregenerated_report(self): - """ - ) - .strip() - .encode("utf-8") - ), + """).strip().encode("utf-8")), # this is a violation which is not bounded to a specific line. We'll skip those - BytesIO( - dedent( - """ + BytesIO(dedent(""" @@ -383,11 +347,7 @@ def test_quality_pregenerated_report(self): - """ - ) - .strip() - .encode("utf-8") - ), + """).strip().encode("utf-8")), ] # Generate the violation report @@ -441,10 +401,7 @@ def test_no_java_file(self): def test_quality_pregenerated_report(self): # When the user provides us with a pre-generated findbugs report # then use that instead of calling findbugs directly. - pmd_reports = [ - BytesIO( - dedent( - """ + pmd_reports = [BytesIO(dedent(""" @@ -458,12 +415,7 @@ def test_quality_pregenerated_report(self): - """ - ) - .strip() - .encode("utf-8") - ) - ] + """).strip().encode("utf-8"))] pmd_xml_driver = PmdXmlDriver() # Generate the violation report diff --git a/tests/test_report_generator.py b/tests/test_report_generator.py index a1e7792a..2136ce99 100644 --- a/tests/test_report_generator.py +++ b/tests/test_report_generator.py @@ -368,8 +368,7 @@ def report(self, coverage, diff): @pytest.mark.usefixtures("use_default_values") def test_generate_report(self): # Verify that we got the expected string - expected = dedent( - """ + expected = dedent(""" ------------- Diff Coverage Diff: main @@ -381,8 +380,7 @@ def test_generate_report(self): Missing: 4 lines Coverage: 66% ------------- - """ - ).strip() + """).strip() self.assert_report(expected) @@ -395,8 +393,7 @@ def test_hundred_percent( coverage_violations.update({"file.py": []}) coverage_measured_lines.update({"file.py": [2]}) - expected = dedent( - """ + expected = dedent(""" ------------- Diff Coverage Diff: main @@ -407,8 +404,7 @@ def test_hundred_percent( Missing: 0 lines Coverage: 100% ------------- - """ - ).strip() + """).strip() self.assert_report(expected) @@ -416,16 +412,14 @@ def test_empty_report(self): # Have the dependencies return an empty report # (this is the default) - expected = dedent( - """ + expected = dedent(""" ------------- Diff Coverage Diff: main ------------- No lines with coverage information in this diff. ------------- - """ - ).strip() + """).strip() self.assert_report(expected) @@ -448,12 +442,10 @@ def report(self, coverage, diff): @pytest.mark.usefixtures("use_default_values") def test_generate_report(self): # Verify that we got the expected string - expected = dedent( - """ + expected = dedent(""" ::warning file=file1.py,line=10,endLine=11,title=Missing Coverage::Line 10-11 missing coverage ::warning file=subdir/file2.py,line=10,endLine=11,title=Missing Coverage::Line 10-11 missing coverage - """ - ).strip() + """).strip() self.assert_report(expected) @@ -466,11 +458,9 @@ def test_single_line( coverage_measured_lines.update({"file.py": [2]}) # Verify that we got the expected string - expected = dedent( - """ + expected = dedent(""" ::warning file=file.py,line=10,title=Missing Coverage::Line 10 missing coverage - """ - ).strip() + """).strip() self.assert_report(expected) @@ -549,8 +539,7 @@ def test_generate_report(self): # Generate a default report # Verify that we got the expected string - expected = dedent( - """ + expected = dedent(""" # Diff Coverage ## Diff: main @@ -562,8 +551,7 @@ def test_generate_report(self): - **Total**: 12 lines - **Missing**: 4 lines - **Coverage**: 66% - """ - ).strip() + """).strip() self.assert_report(expected) @@ -576,8 +564,7 @@ def test_hundred_percent( coverage_violations.update({"file.py": []}) coverage_measured_lines.update({"file.py": [2]}) - expected = dedent( - """ + expected = dedent(""" # Diff Coverage ## Diff: main @@ -588,8 +575,7 @@ def test_hundred_percent( - **Total**: 1 line - **Missing**: 0 lines - **Coverage**: 100% - """ - ).strip() + """).strip() self.assert_report(expected) @@ -597,14 +583,12 @@ def test_empty_report(self): # Have the dependencies return an empty report # (this is the default) - expected = dedent( - """ + expected = dedent(""" # Diff Coverage ## Diff: main No lines with coverage information in this diff. - """ - ).strip() + """).strip() self.assert_report(expected) diff --git a/tests/test_violations_reporter.py b/tests/test_violations_reporter.py index 6be46d42..4b6ccba9 100644 --- a/tests/test_violations_reporter.py +++ b/tests/test_violations_reporter.py @@ -151,15 +151,13 @@ def test_non_python_violations_empty_path(self): In the wild empty sources can happen. See https://github.com/Bachmann1234/diff-cover/issues/88 Best I can tell its mostly irrelevant but I mostly don't want it crashing """ - xml = etree.fromstring( - """ + xml = etree.fromstring(""" - """ - ) + """) coverage = XmlCoverageReporter([xml]) @@ -1099,17 +1097,11 @@ class TestPycodestyleQualityReporterTest: def test_quality(self, mocker, process_patcher): # Patch the output of `pycodestyle` mocker.patch.object(Popen, "communicate") - return_string = ( - "\n" - + dedent( - """ + return_string = "\n" + dedent(""" ../new_file.py:1:17: E231 whitespace ../new_file.py:3:13: E225 whitespace ../new_file.py:7:1: E302 blank lines - """ - ).strip() - + "\n" - ) + """).strip() + "\n" process_patcher((return_string.encode("utf-8"), b"")) # Parse the report @@ -1179,31 +1171,15 @@ def test_quality_pregenerated_report(self): # When the user provides us with a pre-generated pycodestyle report # then use that instead of calling pycodestyle directly. pycodestyle_reports = [ - BytesIO( - ( - "\n" - + dedent( - """ + BytesIO(("\n" + dedent(""" path/to/file.py:1:17: E231 whitespace path/to/file.py:3:13: E225 whitespace another/file.py:7:1: E302 blank lines - """ - ).strip() - + "\n" - ).encode("utf-8") - ), - BytesIO( - ( - "\n" - + dedent( - """ + """).strip() + "\n").encode("utf-8")), + BytesIO(("\n" + dedent(""" path/to/file.py:24:2: W123 \u9134\u1912 another/file.py:50:1: E302 blank lines - """ - ).strip() - + "\n" - ).encode("utf-8") - ), + """).strip() + "\n").encode("utf-8")), ] # Parse the report @@ -1236,16 +1212,10 @@ class TestPyflakesQualityReporterTest: def test_quality(self, process_patcher): # Patch the output of `pyflakes` - return_string = ( - "\n" - + dedent( - """ + return_string = "\n" + dedent(""" ../new_file.py:328: undefined name '_thing' ../new_file.py:418: 'random' imported but unused - """ - ).strip() - + "\n" - ) + """).strip() + "\n" process_patcher((return_string.encode("utf-8"), b"")) # Parse the report @@ -1312,31 +1282,15 @@ def test_quality_pregenerated_report(self): # When the user provides us with a pre-generated pyflakes report # then use that instead of calling pyflakes directly. pyflakes_reports = [ - BytesIO( - ( - "\n" - + dedent( - """ + BytesIO(("\n" + dedent(""" path/to/file.py:1: undefined name 'this' path/to/file.py:3: 'random' imported but unused another/file.py:7: 'os' imported but unused - """ - ).strip() - + "\n" - ).encode("utf-8") - ), - BytesIO( - ( - "\n" - + dedent( - """ + """).strip() + "\n").encode("utf-8")), + BytesIO(("\n" + dedent(""" path/to/file.py:24: undefined name 'that' another/file.py:50: undefined name 'another' - """ - ).strip() - + "\n" - ).encode("utf-8") - ), + """).strip() + "\n").encode("utf-8")), ] # Parse the report @@ -1365,10 +1319,7 @@ def test_quality_pregenerated_report(self): class TestFlake8QualityReporterTest: def test_quality(self, process_patcher): # Patch the output of `flake8` - return_string = ( - "\n" - + dedent( - """ + return_string = "\n" + dedent(""" ../new_file.py:1:17: E231 whitespace ../new_file.py:3:13: E225 whitespace ../new_file.py:7:1: E302 blank lines @@ -1383,10 +1334,7 @@ def test_quality(self, process_patcher): ../new_file.py:100:0: S100 Snippet found ../new_file.py:110:0: Q000 Remove Single quotes ../new_file.py:120:0: ABCXYZ000 Dummy - """ - ).strip() - + "\n" - ) + """).strip() + "\n" process_patcher((return_string.encode("utf-8"), b"")) # Parse the report @@ -1475,31 +1423,15 @@ def test_quality_pregenerated_report(self): # When the user provides us with a pre-generated flake8 report # then use that instead of calling flake8 directly. flake8_reports = [ - BytesIO( - ( - "\n" - + dedent( - """ + BytesIO(("\n" + dedent(""" path/to/file.py:1:17: E231 whitespace path/to/file.py:3:13: E225 whitespace another/file.py:7:1: E302 blank lines - """ - ).strip() - + "\n" - ).encode("utf-8") - ), - BytesIO( - ( - "\n" - + dedent( - """ + """).strip() + "\n").encode("utf-8")), + BytesIO(("\n" + dedent(""" path/to/file.py:24:2: W123 \u9134\u1912 another/file.py:50:1: E302 blank lines - """ - ).strip() - + "\n" - ).encode("utf-8") - ), + """).strip() + "\n").encode("utf-8")), ] # Parse the report @@ -1548,16 +1480,12 @@ def test_quality(self, process_patcher): # Patch the output of `pydocstye` process_patcher( ( - dedent( - """ + dedent(""" ../new_file.py:1 at module level: D100: Missing docstring in public module ../new_file.py:13 in public function `gather`: D103: Missing docstring in public function - """ - ) - .strip() - .encode("ascii"), + """).strip().encode("ascii"), "", ) ) @@ -1609,8 +1537,7 @@ def test_quality(self, process_patcher): # Patch the output of `pylint` process_patcher( ( - dedent( - """ + dedent(""" file1.py:1: [C0111] Missing docstring file1.py:1: [C0111, func_1] Missing docstring file1.py:2: [W0612, cls_name.func] Unused variable 'd' @@ -1632,10 +1559,7 @@ def test_quality(self, process_patcher): import foo import bar path/to/file2.py:100: [W0212, openid_login_complete] Access to a protected member - """ - ) - .strip() - .encode("ascii"), + """).strip().encode("ascii"), "", ) ) @@ -1677,12 +1601,10 @@ def test_quality(self, process_patcher): def test_unicode(self, process_patcher): process_patcher( ( - dedent( - """ + dedent(""" file_\u6729.py:616: [W1401] Anomalous backslash in string: '\u5922'. String constant might be missing an r prefix. file.py:2: [W0612, cls_name.func_\u9492] Unused variable '\u2920' - """ - ).encode("utf-8"), + """).encode("utf-8"), "", ), 0, @@ -1713,12 +1635,10 @@ def test_unicode_continuation_char(self, process_patcher): def test_non_integer_line_num(self, process_patcher): process_patcher( ( - dedent( - """ + dedent(""" file.py:not_a_number: C0111: Missing docstring file.py:\u8911: C0111: Missing docstring - """ - ).encode("utf-8"), + """).encode("utf-8"), "", ), 0, @@ -1782,9 +1702,7 @@ def test_quality_pregenerated_report(self): # When the user provides us with a pre-generated pylint report # then use that instead of calling pylint directly. pylint_reports = [ - BytesIO( - dedent( - """ + BytesIO(dedent(""" path/to/file.py:1: [C0111] Missing docstring path/to/file.py:57: [W0511] TODO the name of this method is a little bit confusing another/file.py:41: [W1201, assign_default_role] Specify string format arguments as logging function parameters @@ -1793,21 +1711,11 @@ def test_quality_pregenerated_report(self): ^ Unicode: \u9404 \u1239 another/file.py:259: [C0103, bar] Invalid name "\u4920" for type variable (should match [a-z_][a-z0-9_]{2,30}$) - """ - ) - .strip() - .encode("utf-8") - ), - BytesIO( - dedent( - """ + """).strip().encode("utf-8")), + BytesIO(dedent(""" path/to/file.py:183: [C0103, Foo.bar.gettag] Invalid name "\u3240" for type argument (should match [a-z_][a-z0-9_]{2,30}$) another/file.py:183: [C0111, Foo.bar.gettag] Missing docstring - """ - ) - .strip() - .encode("utf-8") - ), + """).strip().encode("utf-8")), ] # Generate the violation report @@ -1884,16 +1792,10 @@ def test_quality(self): Test basic scenarios, including special characters that would appear in JavaScript and mixed quotation marks """ # Patch the output of the linter cmd - return_string = ( - "\n" - + dedent( - """ + return_string = "\n" + dedent(""" ../test_file.js: line 3, col 9, Missing "use strict" statement. ../test_file.js: line 10, col 17, '$hi' is defined but never used. - """ - ).strip() - + "\n" - ) + """).strip() + "\n" self.subproc_mock.communicate.return_value = ( return_string.encode("utf-8"), b"", @@ -1967,31 +1869,15 @@ def test_quality_pregenerated_report(self): # When the user provides us with a pre-generated linter report # then use that instead of calling linter directly. reports = [ - BytesIO( - ( - "\n" - + dedent( - """ + BytesIO(("\n" + dedent(""" path/to/file.js: line 3, col 9, Missing "use strict" statement. path/to/file.js: line 10, col 130, Line is too long. another/file.js: line 1, col 1, 'require' is not defined. - """ - ).strip() - + "\n" - ).encode("utf-8") - ), - BytesIO( - ( - "\n" - + dedent( - """ + """).strip() + "\n").encode("utf-8")), + BytesIO(("\n" + dedent(""" path/to/file.js: line 12, col 14, \u9134\u1912 path/to/file.js: line 10, col 17, '$hi' is defined but never used. - """ - ).strip() - + "\n" - ).encode("utf-8") - ), + """).strip() + "\n").encode("utf-8")), ] # Parse the report @@ -2089,14 +1975,10 @@ def test_quality(self, process_patcher): """Integration test.""" process_patcher( ( - dedent( - """ + dedent(""" foo/bar/path/to/file.sh:2:18: note: Double quote to prevent globbing and word splitting. [SC2086] foo/bar/path/to/file.sh:53:10: warning: Use 'cd ... || exit' or 'cd ... || return' in case cd fails. [SC2164] - """ - ) - .strip() - .encode("ascii"), + """).strip().encode("ascii"), "", ) ) @@ -2248,8 +2130,7 @@ def test_quality(self, process_patcher): """Integration test.""" process_patcher( ( - dedent( - """ + dedent(""" foo/bar/path/to/file.py:244:26: F541 [*] f-string without any placeholders | 242 | ] @@ -2271,10 +2152,7 @@ def test_quality(self, process_patcher): 134 | dedent( | = help: Remove assignment to unused variable `e` - """ - ) - .strip() - .encode("ascii"), + """).strip().encode("ascii"), "", ) )