From 4461c86c841e298d5c644e2a6ad5468cb7fffce3 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Mon, 25 May 2026 18:09:49 +0200 Subject: [PATCH 1/2] [match case] Use match case in ``assertrepr_compare`` Replace the if/elif dispatch on ``op`` with a ``match``/``case`` on ``(left, op, right)``. The ``str()`` and ``AbstractSet()`` class patterns subsume the ``istext`` / ``isset`` guards that the if/elif form needed alongside the operator check. --- src/_pytest/assertion/util.py | 38 +++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index a6f124bb502..441ff0993cf 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -6,6 +6,7 @@ from collections.abc import Callable from collections.abc import Iterator from collections.abc import Sequence +from collections.abc import Set as AbstractSet from unicodedata import normalize from _pytest import outcomes @@ -14,8 +15,6 @@ from _pytest._io.saferepr import saferepr_unlimited from _pytest.assertion._compare_any import _compare_eq_any from _pytest.assertion._compare_set import SET_COMPARISON_FUNCTIONS -from _pytest.assertion._guards import isset -from _pytest.assertion._guards import istext from _pytest.assertion._typing import _AssertionTextDiffStyle from _pytest.assertion._typing import _HighlightFunc from _pytest.assertion._typing import NO_TRUNCATION_BUDGET @@ -151,21 +150,26 @@ def assertrepr_compare( summary = f"{left_repr} {op} {right_repr}" try: - if op == "==": - source = _compare_eq_any( - left, - right, - highlighter, - verbose, - assertion_text_diff_style, - truncation_budget, - ) - elif op == "not in" and istext(left) and istext(right): - source = _notin_text(left, right, verbose, truncation_budget) - elif op in {"!=", ">=", "<=", ">", "<"} and isset(left) and isset(right): - source = SET_COMPARISON_FUNCTIONS[op](left, right, highlighter, verbose) - else: - source = iter(()) + match (left, op, right): + case (_, "==", _): + source = _compare_eq_any( + left, + right, + highlighter, + verbose, + assertion_text_diff_style, + truncation_budget, + ) + case (str(), "not in", str()): + source = _notin_text(left, right, verbose, truncation_budget) + case ( + AbstractSet(), + "!=" | ">=" | "<=" | ">" | "<", + AbstractSet(), + ): + source = SET_COMPARISON_FUNCTIONS[op](left, right, highlighter, verbose) + case _: + source = iter(()) # Only yield the summary if there is a detailed explanation. # Make sure there's a separating empty line after the summary. From a1d1ce4a30b755294f861616c0244ff39285c2ff Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Mon, 3 Aug 2026 20:03:15 +0200 Subject: [PATCH 2/2] [match case] Fit the set case pattern on a single line The magic trailing comma, not the line width, was forcing the ``AbstractSet()`` case to span five lines: without it the pattern is 80 characters and ruff keeps it on one, matching the two cases around it. Co-Authored-By: Claude Opus 5 (1M context) --- src/_pytest/assertion/util.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 441ff0993cf..dd993d7bcae 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -162,11 +162,7 @@ def assertrepr_compare( ) case (str(), "not in", str()): source = _notin_text(left, right, verbose, truncation_budget) - case ( - AbstractSet(), - "!=" | ">=" | "<=" | ">" | "<", - AbstractSet(), - ): + case (AbstractSet(), "!=" | ">=" | "<=" | ">" | "<", AbstractSet()): source = SET_COMPARISON_FUNCTIONS[op](left, right, highlighter, verbose) case _: source = iter(())