From eb38e69e860d2e08c954a0759cf11d72d4266410 Mon Sep 17 00:00:00 2001 From: Kaylin Yeoh Date: Sat, 2 Dec 2023 17:49:20 -0500 Subject: [PATCH 01/10] created test file to test issue --- pyproject.toml | 2 +- testing/examples/test_issue10863.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 testing/examples/test_issue10863.py diff --git a/pyproject.toml b/pyproject.toml index cdbdd3880..f72f393c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ build-backend = "setuptools.build_meta" write_to = "src/_pytest/_version.py" [tool.pytest.ini_options] -minversion = "2.0" +minversion = "0.0" addopts = "-rfEX -p pytester --strict-markers" python_files = ["test_*.py", "*_test.py", "testing/python/*.py"] python_classes = ["Test", "Acceptance"] diff --git a/testing/examples/test_issue10863.py b/testing/examples/test_issue10863.py new file mode 100644 index 000000000..337e8fa9c --- /dev/null +++ b/testing/examples/test_issue10863.py @@ -0,0 +1,6 @@ +def test_(): + m = [ + "This is some dummy test which shows the strange way in which Pycharm" + " displays the full diff." + ] + assert m == [] \ No newline at end of file From b8483dcb41eb498564b71f346677de83a8a9f011 Mon Sep 17 00:00:00 2001 From: Kaylin Yeoh Date: Mon, 4 Dec 2023 18:51:12 -0500 Subject: [PATCH 02/10] removed test file, no longer needed --- testing/examples/test_issue10863.py | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 testing/examples/test_issue10863.py diff --git a/testing/examples/test_issue10863.py b/testing/examples/test_issue10863.py deleted file mode 100644 index 337e8fa9c..000000000 --- a/testing/examples/test_issue10863.py +++ /dev/null @@ -1,6 +0,0 @@ -def test_(): - m = [ - "This is some dummy test which shows the strange way in which Pycharm" - " displays the full diff." - ] - assert m == [] \ No newline at end of file From d8c80eb35bfc59e2cf916b51a046e6f536bf93e1 Mon Sep 17 00:00:00 2001 From: Kaylin Yeoh Date: Thu, 7 Dec 2023 18:22:06 -0500 Subject: [PATCH 03/10] corrected minversion --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f72f393c0..cdbdd3880 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ build-backend = "setuptools.build_meta" write_to = "src/_pytest/_version.py" [tool.pytest.ini_options] -minversion = "0.0" +minversion = "2.0" addopts = "-rfEX -p pytester --strict-markers" python_files = ["test_*.py", "*_test.py", "testing/python/*.py"] python_classes = ["Test", "Acceptance"] From 3a513ac6bd5957c973ba838a8680d3c6cb688fa8 Mon Sep 17 00:00:00 2001 From: JamieC2002 Date: Thu, 7 Dec 2023 18:53:10 -0500 Subject: [PATCH 04/10] Added conditional to check if left or right is an empty list. Added modifications to the formatting to fix strings that were created with implicit string concatenation. --- src/_pytest/assertion/util.py | 35 +++++++++++++++++++++++++++-- testing/examples/test_issue10863.py | 6 ----- 2 files changed, 33 insertions(+), 8 deletions(-) delete mode 100644 testing/examples/test_issue10863.py diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 4d9fd114b..4669278e6 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -12,6 +12,7 @@ from typing import Mapping from typing import Optional from typing import Protocol from typing import Sequence +from typing import Tuple from unicodedata import normalize import _pytest._code @@ -341,12 +342,16 @@ def _compare_eq_iterable( # dynamic import to speedup pytest import difflib - left_formatting = pprint.pformat(left).splitlines() - right_formatting = pprint.pformat(right).splitlines() + if _is_empty_vs_non_empty(left, right): + left_formatting, right_formatting = _format_for_empty_and_non_empty(left, right) + else: + left_formatting = pprint.pformat(left).splitlines() + right_formatting = pprint.pformat(right).splitlines() # Re-format for different output lengths. lines_left = len(left_formatting) lines_right = len(right_formatting) + if lines_left != lines_right: printer = PrettyPrinter() left_formatting = printer.pformat(left).splitlines() @@ -371,6 +376,32 @@ def _compare_eq_iterable( return explanation +def _is_empty_vs_non_empty(left: Iterable[Any], right: Iterable[Any]) -> bool: + is_left_empty = not any(left) if isinstance(left, Iterable) else not left + is_right_empty = not any(right) if isinstance(right, Iterable) else not right + return (is_left_empty and not is_right_empty) or ( + not is_left_empty and is_right_empty + ) + + +def _format_for_empty_and_non_empty( + left: Iterable[Any], right: Iterable[Any] +) -> Tuple[List[str], List[str]]: + if isinstance(left, (list, tuple)) and isinstance(right, (list, tuple)): + if not left: + right_width = len(right[0]) + 4 if right else 80 + right_formatting = pprint.pformat(right, width=right_width).splitlines() + left_formatting = pprint.pformat(left).splitlines() + else: + left_width = len(left[0]) + 4 if left else 80 + left_formatting = pprint.pformat(left, width=left_width).splitlines() + right_formatting = pprint.pformat(right).splitlines() + return left_formatting, right_formatting + else: + # Fall back to default formatting + return pprint.pformat(left).splitlines(), pprint.pformat(right).splitlines() + + def _compare_eq_sequence( left: Sequence[Any], right: Sequence[Any], verbose: int = 0 ) -> List[str]: diff --git a/testing/examples/test_issue10863.py b/testing/examples/test_issue10863.py deleted file mode 100644 index 337e8fa9c..000000000 --- a/testing/examples/test_issue10863.py +++ /dev/null @@ -1,6 +0,0 @@ -def test_(): - m = [ - "This is some dummy test which shows the strange way in which Pycharm" - " displays the full diff." - ] - assert m == [] \ No newline at end of file From 7c6915da640e6d8c59e1c627644447978b0e3d3e Mon Sep 17 00:00:00 2001 From: Kaylin Yeoh Date: Thu, 7 Dec 2023 18:56:03 -0500 Subject: [PATCH 05/10] added test cases for multiline string diffs --- testing/test_assertion.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/testing/test_assertion.py b/testing/test_assertion.py index 7c8c01556..9ae04a9bf 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -395,6 +395,27 @@ class TestAssert_reprcompare: "- eggs", "+ spam", ] + + def test_multiline_diff(self) -> None: + m = [ + "This is some dummy test which shows the strange way in which Pycharm" + " displays the full diff." + ] + assert callequal(m, []) == [ + "['This is som...e full diff.'] == []", + "Left contains one more item: 'This is some dummy test which shows the " + "strange way in which Pycharm displays the full diff.'", + 'Use -v to get more diff', + ] + assert callequal(m, [], verbose=True) == [ + "['This is som...e full diff.'] == []", + "Left contains one more item: 'This is some dummy test which shows the " + "strange way in which Pycharm displays the full diff.'", + "Full diff:", + "- []", + "+ ['This is some dummy test which shows the strange way in which Pycharm " + "displays the full diff.']", + ] def test_text_skipping(self) -> None: lines = callequal("a" * 50 + "spam", "a" * 50 + "eggs") From 7cab05fddadecf4608fd8478e52d4b30ec2e63e5 Mon Sep 17 00:00:00 2001 From: Kaylin Yeoh Date: Thu, 7 Dec 2023 19:03:42 -0500 Subject: [PATCH 06/10] added documentation --- AUTHORS | 2 ++ changelog/10863.bugfix.rst | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 changelog/10863.bugfix.rst diff --git a/AUTHORS b/AUTHORS index e30131d1a..731f3c92c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -180,6 +180,7 @@ Jake VanderPlas Jakob van Santen Jakub Mitoraj James Bourbeau +Jamie Chen Jan Balster Janne Vanhala Jason R. Coombs @@ -205,6 +206,7 @@ Justice Ndou Justyna Janczyszyn Kale Kundert Kamran Ahmad +Kaylin Yeoh Kenny Y Karl O. Pinc Karthikeyan Singaravelan diff --git a/changelog/10863.bugfix.rst b/changelog/10863.bugfix.rst new file mode 100644 index 000000000..60ac21559 --- /dev/null +++ b/changelog/10863.bugfix.rst @@ -0,0 +1,4 @@ +Found source causes multiline string diff error +Added private functions to check specific cases +Fixed output issue with implicit concatonated strings +Added tests in test assertion file in function test_multiline_diff From 1ef76f3a0a36291e1455541ba0df578118496dd6 Mon Sep 17 00:00:00 2001 From: JamieC2002 Date: Thu, 7 Dec 2023 19:45:39 -0500 Subject: [PATCH 07/10] Revised formatting to work with multiple implicitly concatenated strings --- src/_pytest/assertion/util.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 4669278e6..684e7cce5 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -344,18 +344,19 @@ def _compare_eq_iterable( if _is_empty_vs_non_empty(left, right): left_formatting, right_formatting = _format_for_empty_and_non_empty(left, right) + lines_left = len(left_formatting) + lines_right = len(right_formatting) else: left_formatting = pprint.pformat(left).splitlines() right_formatting = pprint.pformat(right).splitlines() - # Re-format for different output lengths. - lines_left = len(left_formatting) - lines_right = len(right_formatting) + lines_left = len(left_formatting) + lines_right = len(right_formatting) - if lines_left != lines_right: - printer = PrettyPrinter() - left_formatting = printer.pformat(left).splitlines() - right_formatting = printer.pformat(right).splitlines() + if lines_left != lines_right: + printer = PrettyPrinter() + left_formatting = printer.pformat(left).splitlines() + right_formatting = printer.pformat(right).splitlines() if lines_left > 1 or lines_right > 1: _surrounding_parens_on_own_lines(left_formatting) @@ -389,16 +390,15 @@ def _format_for_empty_and_non_empty( ) -> Tuple[List[str], List[str]]: if isinstance(left, (list, tuple)) and isinstance(right, (list, tuple)): if not left: - right_width = len(right[0]) + 4 if right else 80 + right_width = max(len(s) + 4 for s in right) right_formatting = pprint.pformat(right, width=right_width).splitlines() left_formatting = pprint.pformat(left).splitlines() else: - left_width = len(left[0]) + 4 if left else 80 + left_width = max(len(s) + 4 for s in left) left_formatting = pprint.pformat(left, width=left_width).splitlines() right_formatting = pprint.pformat(right).splitlines() return left_formatting, right_formatting else: - # Fall back to default formatting return pprint.pformat(left).splitlines(), pprint.pformat(right).splitlines() From 21c08dae13ffcdcbb16d9d4e371183efd70f8815 Mon Sep 17 00:00:00 2001 From: Kaylin Yeoh Date: Thu, 7 Dec 2023 19:57:53 -0500 Subject: [PATCH 08/10] added more tests to check for longer multiline string output and multiple multiline strings --- testing/test_assertion.py | 59 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/testing/test_assertion.py b/testing/test_assertion.py index 9ae04a9bf..b7f52026e 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -397,17 +397,29 @@ class TestAssert_reprcompare: ] def test_multiline_diff(self) -> None: - m = [ + m1 = [ "This is some dummy test which shows the strange way in which Pycharm" " displays the full diff." ] - assert callequal(m, []) == [ + m2 = [ + "This is some dummy test which shows the strange way in which Pycharm" + " displays the full diff.This is some dummy test which shows the strange way in which Pycharm" + " displays the full diff." + ] + m3 = [ + "This is some dummy test which shows the strange way in which Pycharm" + " displays the full diff.", + "This is some dummy test which shows the strange way in which Pycharm" + " displays the full diff." + ] + + assert callequal(m1, []) == [ "['This is som...e full diff.'] == []", "Left contains one more item: 'This is some dummy test which shows the " "strange way in which Pycharm displays the full diff.'", 'Use -v to get more diff', ] - assert callequal(m, [], verbose=True) == [ + assert callequal(m1, [], verbose=True) == [ "['This is som...e full diff.'] == []", "Left contains one more item: 'This is some dummy test which shows the " "strange way in which Pycharm displays the full diff.'", @@ -416,6 +428,47 @@ class TestAssert_reprcompare: "+ ['This is some dummy test which shows the strange way in which Pycharm " "displays the full diff.']", ] + + assert callequal(m2, []) == [ + "['This is som...e full diff.'] == []", + "Left contains one more item: 'This is some dummy test which shows the " + "strange way in which Pycharm displays the full diff.This is some dummy test " + "which shows the strange way in which Pycharm displays the full diff.'", + 'Use -v to get more diff', + ] + + assert callequal(m2, [], verbose=True) == [ + "['This is som...e full diff.'] == []", + "Left contains one more item: 'This is some dummy test which shows the " + "strange way in which Pycharm displays the full diff.This is some dummy test " + "which shows the strange way in which Pycharm displays the full diff.'", + "Full diff:", + "- []", + "+ ['This is some dummy test which shows the strange way in which Pycharm " + "displays the full diff.This is some dummy test which shows the strange " + "way in which Pycharm displays the full diff.']", + ] + + assert callequal(m3, []) == [ + "['This is som...e full diff.'] == []", + "Left contains 2 more items, first extra item: 'This is some dummy test which shows the strange way in " + "which Pycharm displays the full diff.'", + 'Use -v to get more diff', + ] + + assert callequal(m3, [], verbose=True) == [ + "['This is som...e full diff.'] == []", + "Left contains 2 more items, first extra item: 'This is some dummy test which shows the strange way in " + "which Pycharm displays the full diff.'", + "Full diff:", + " [", + "- ,", + "+ 'This is some dummy test which shows the strange way in which Pycharm " + "displays the full diff.',", + "+ 'This is some dummy test which shows the strange way in which Pycharm " + "displays the full diff.',", + " ]", + ] def test_text_skipping(self) -> None: lines = callequal("a" * 50 + "spam", "a" * 50 + "eggs") From 1741952b4945776980cef5b6197715cca8862429 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 8 Dec 2023 01:02:07 +0000 Subject: [PATCH 09/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytest/assertion/util.py | 2 +- testing/test_assertion.py | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 22bedf0b6..7a6613bfd 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -336,7 +336,7 @@ def _compare_eq_iterable( left_formatting, right_formatting = _format_for_empty_and_non_empty(left, right) lines_left = len(left_formatting) lines_right = len(right_formatting) - + if lines_left > 1 or lines_right > 1: _surrounding_parens_on_own_lines(left_formatting) _surrounding_parens_on_own_lines(right_formatting) diff --git a/testing/test_assertion.py b/testing/test_assertion.py index a6bccf3c8..f3e8ae249 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -396,7 +396,7 @@ class TestAssert_reprcompare: "- eggs", "+ spam", ] - + def test_multiline_diff(self) -> None: m1 = [ "This is some dummy test which shows the strange way in which Pycharm" @@ -411,14 +411,14 @@ class TestAssert_reprcompare: "This is some dummy test which shows the strange way in which Pycharm" " displays the full diff.", "This is some dummy test which shows the strange way in which Pycharm" - " displays the full diff." + " displays the full diff.", ] assert callequal(m1, []) == [ "['This is som...e full diff.'] == []", "Left contains one more item: 'This is some dummy test which shows the " "strange way in which Pycharm displays the full diff.'", - 'Use -v to get more diff', + "Use -v to get more diff", ] assert callequal(m1, [], verbose=True) == [ "['This is som...e full diff.'] == []", @@ -429,15 +429,15 @@ class TestAssert_reprcompare: "+ ['This is some dummy test which shows the strange way in which Pycharm " "displays the full diff.']", ] - + assert callequal(m2, []) == [ "['This is som...e full diff.'] == []", "Left contains one more item: 'This is some dummy test which shows the " "strange way in which Pycharm displays the full diff.This is some dummy test " "which shows the strange way in which Pycharm displays the full diff.'", - 'Use -v to get more diff', + "Use -v to get more diff", ] - + assert callequal(m2, [], verbose=True) == [ "['This is som...e full diff.'] == []", "Left contains one more item: 'This is some dummy test which shows the " @@ -449,14 +449,14 @@ class TestAssert_reprcompare: "displays the full diff.This is some dummy test which shows the strange " "way in which Pycharm displays the full diff.']", ] - + assert callequal(m3, []) == [ "['This is som...e full diff.'] == []", "Left contains 2 more items, first extra item: 'This is some dummy test which shows the strange way in " "which Pycharm displays the full diff.'", - 'Use -v to get more diff', + "Use -v to get more diff", ] - + assert callequal(m3, [], verbose=True) == [ "['This is som...e full diff.'] == []", "Left contains 2 more items, first extra item: 'This is some dummy test which shows the strange way in " From 745953512772f468492858640a1140cfab5dba05 Mon Sep 17 00:00:00 2001 From: JamieC2002 Date: Thu, 7 Dec 2023 20:21:04 -0500 Subject: [PATCH 10/10] Re-added _surrounding_parens_on_own_lines(), and fixed test cases related to issue #10863 to account for new changes from main --- src/_pytest/assertion/util.py | 16 ++++++++++++++-- testing/test_assertion.py | 11 ++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 7a6613bfd..cc8967ed3 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -338,8 +338,8 @@ def _compare_eq_iterable( lines_right = len(right_formatting) if lines_left > 1 or lines_right > 1: - _surrounding_parens_on_own_lines(left_formatting) - _surrounding_parens_on_own_lines(right_formatting) + _surrounding_parens_on_own_lines(left_formatting) + _surrounding_parens_on_own_lines(right_formatting) else: left_formatting = PrettyPrinter().pformat(left).splitlines() right_formatting = PrettyPrinter().pformat(right).splitlines() @@ -359,6 +359,18 @@ def _compare_eq_iterable( return explanation +def _surrounding_parens_on_own_lines(lines: List[str]) -> None: + """Move opening/closing parenthesis/bracket to own lines.""" + opening = lines[0][:1] + if opening in ["(", "[", "{"]: + lines[0] = " " + lines[0][1:] + lines[:] = [opening] + lines + closing = lines[-1][-1:] + if closing in [")", "]", "}"]: + lines[-1] = lines[-1][:-1] + "," + lines[:] = lines + [closing] + + def _is_empty_vs_non_empty(left: Iterable[Any], right: Iterable[Any]) -> bool: is_left_empty = not any(left) if isinstance(left, Iterable) else not left is_right_empty = not any(right) if isinstance(right, Iterable) else not right diff --git a/testing/test_assertion.py b/testing/test_assertion.py index f3e8ae249..d7fd51a1e 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -416,14 +416,17 @@ class TestAssert_reprcompare: assert callequal(m1, []) == [ "['This is som...e full diff.'] == []", + "", "Left contains one more item: 'This is some dummy test which shows the " "strange way in which Pycharm displays the full diff.'", "Use -v to get more diff", ] assert callequal(m1, [], verbose=True) == [ "['This is som...e full diff.'] == []", + "", "Left contains one more item: 'This is some dummy test which shows the " "strange way in which Pycharm displays the full diff.'", + "", "Full diff:", "- []", "+ ['This is some dummy test which shows the strange way in which Pycharm " @@ -432,6 +435,7 @@ class TestAssert_reprcompare: assert callequal(m2, []) == [ "['This is som...e full diff.'] == []", + "", "Left contains one more item: 'This is some dummy test which shows the " "strange way in which Pycharm displays the full diff.This is some dummy test " "which shows the strange way in which Pycharm displays the full diff.'", @@ -440,9 +444,11 @@ class TestAssert_reprcompare: assert callequal(m2, [], verbose=True) == [ "['This is som...e full diff.'] == []", + "", "Left contains one more item: 'This is some dummy test which shows the " "strange way in which Pycharm displays the full diff.This is some dummy test " "which shows the strange way in which Pycharm displays the full diff.'", + "" "", "Full diff:", "- []", "+ ['This is some dummy test which shows the strange way in which Pycharm " @@ -452,15 +458,18 @@ class TestAssert_reprcompare: assert callequal(m3, []) == [ "['This is som...e full diff.'] == []", + "", "Left contains 2 more items, first extra item: 'This is some dummy test which shows the strange way in " "which Pycharm displays the full diff.'", - "Use -v to get more diff", + "" "Use -v to get more diff", ] assert callequal(m3, [], verbose=True) == [ "['This is som...e full diff.'] == []", + "", "Left contains 2 more items, first extra item: 'This is some dummy test which shows the strange way in " "which Pycharm displays the full diff.'", + "", "Full diff:", " [", "- ,",