From 1396ca6b0ea6e32e8c9933f1a9c7cd7ba4154c71 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Tue, 30 Sep 2025 10:04:24 +0300 Subject: [PATCH 1/4] compat: state in the module docstring that it also contains utilities Maybe it's not ideal but that's the current reality, and I wouldn't like to break tradition by renaming the file. --- src/_pytest/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index bef8c317bb9..b8f5ebe04e7 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -1,5 +1,5 @@ # mypy: allow-untyped-defs -"""Python version compatibility code.""" +"""Python version compatibility code and random general utilities.""" from __future__ import annotations From d70cf2c34375da548d99498abb3d32c2e1203020 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Tue, 30 Sep 2025 10:06:24 +0300 Subject: [PATCH 2/4] cacheprovider: drop +x mode bit from file The file is definitely not executable. --- src/_pytest/cacheprovider.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/_pytest/cacheprovider.py diff --git a/src/_pytest/cacheprovider.py b/src/_pytest/cacheprovider.py old mode 100755 new mode 100644 From 57e38ccddfe8eecdb64241cce0f29db667e2e513 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Tue, 30 Sep 2025 10:08:19 +0300 Subject: [PATCH 3/4] compat: assert_never is now in the stdlib Use the upstream implementation, so we can easily drop our own impl when we drop Python 3.10. --- src/_pytest/compat.py | 39 ++++++--------------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index b8f5ebe04e7..43ec0ebcd26 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -278,39 +278,12 @@ def get_user_id() -> int | None: return uid if uid != ERROR else None -# Perform exhaustiveness checking. -# -# Consider this example: -# -# MyUnion = Union[int, str] -# -# def handle(x: MyUnion) -> int { -# if isinstance(x, int): -# return 1 -# elif isinstance(x, str): -# return 2 -# else: -# raise Exception('unreachable') -# -# Now suppose we add a new variant: -# -# MyUnion = Union[int, str, bytes] -# -# After doing this, we must remember ourselves to go and update the handle -# function to handle the new variant. -# -# With `assert_never` we can do better: -# -# // raise Exception('unreachable') -# return assert_never(x) -# -# Now, if we forget to handle the new variant, the type-checker will emit a -# compile-time error, instead of the runtime error we would have gotten -# previously. -# -# This also work for Enums (if you use `is` to compare) and Literals. -def assert_never(value: NoReturn) -> NoReturn: - assert False, f"Unhandled value: {value} ({type(value).__name__})" +if sys.version_info >= (3, 11): + from typing import assert_never +else: + + def assert_never(value: NoReturn) -> NoReturn: + assert False, f"Unhandled value: {value} ({type(value).__name__})" class CallableBool: From 082a27e30153a840c467f9ade194602e6882d157 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Tue, 30 Sep 2025 10:12:06 +0300 Subject: [PATCH 4/4] compat: move `running_on_ci()` to compat Currently defined in `_pytest.assertion.util`, but then imported from `_pytest.terminal`, so makes sense to move it to the general utils place. --- src/_pytest/assertion/truncate.py | 4 ++-- src/_pytest/assertion/util.py | 8 +------- src/_pytest/compat.py | 6 ++++++ src/_pytest/terminal.py | 2 +- testing/test_collection.py | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/_pytest/assertion/truncate.py b/src/_pytest/assertion/truncate.py index 4854a62ba6b..5820e6e8a80 100644 --- a/src/_pytest/assertion/truncate.py +++ b/src/_pytest/assertion/truncate.py @@ -6,7 +6,7 @@ from __future__ import annotations -from _pytest.assertion import util +from _pytest.compat import running_on_ci from _pytest.config import Config from _pytest.nodes import Item @@ -43,7 +43,7 @@ def _get_truncation_parameters(item: Item) -> tuple[bool, int, int]: verbose = item.config.get_verbosity(Config.VERBOSITY_ASSERTIONS) - should_truncate = verbose < 2 and not util.running_on_ci() + should_truncate = verbose < 2 and not running_on_ci() should_truncate = should_truncate and (max_lines > 0 or max_chars > 0) return should_truncate, max_lines, max_chars diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index cc499f7186f..f35d83a6fe4 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -9,7 +9,6 @@ from collections.abc import Mapping from collections.abc import Sequence from collections.abc import Set as AbstractSet -import os import pprint from typing import Any from typing import Literal @@ -21,6 +20,7 @@ from _pytest._io.pprint import PrettyPrinter from _pytest._io.saferepr import saferepr from _pytest._io.saferepr import saferepr_unlimited +from _pytest.compat import running_on_ci from _pytest.config import Config @@ -613,9 +613,3 @@ def _notin_text(term: str, text: str, verbose: int = 0) -> list[str]: else: newdiff.append(line) return newdiff - - -def running_on_ci() -> bool: - """Check if we're currently running on a CI system.""" - env_vars = ["CI", "BUILD_NUMBER"] - return any(var in os.environ for var in env_vars) diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index 43ec0ebcd26..c00000c794d 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -304,3 +304,9 @@ def __bool__(self) -> bool: def __call__(self) -> bool: return self._value + + +def running_on_ci() -> bool: + """Check if we're currently running on a CI system.""" + env_vars = ["CI", "BUILD_NUMBER"] + return any(var in os.environ for var in env_vars) diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index a95f79ba6b6..857c83bc457 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -39,7 +39,7 @@ from _pytest._io import TerminalWriter from _pytest._io.wcwidth import wcswidth import _pytest._version -from _pytest.assertion.util import running_on_ci +from _pytest.compat import running_on_ci from _pytest.config import _PluggyPlugin from _pytest.config import Config from _pytest.config import ExitCode diff --git a/testing/test_collection.py b/testing/test_collection.py index bb2fd82c898..0dcf2990ed3 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -10,7 +10,7 @@ import tempfile import textwrap -from _pytest.assertion.util import running_on_ci +from _pytest.compat import running_on_ci from _pytest.config import ExitCode from _pytest.fixtures import FixtureRequest from _pytest.main import _in_venv