From 0f94bbc5a0cecbba2cf287845925083b9c72cee7 Mon Sep 17 00:00:00 2001 From: Michalis Christodoulou Date: Wed, 1 Apr 2026 11:32:10 +0300 Subject: [PATCH 1/2] Prevent --update-functional-output from deleting or overwriting fallback versioned output files for other Python versions. --- .../functional/lint_module_output_update.py | 2 + pylint/testutils/functional/test_file.py | 16 ++++++- .../test_lint_module_output_update.py | 43 +++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/pylint/testutils/functional/lint_module_output_update.py b/pylint/testutils/functional/lint_module_output_update.py index a9af6bb658..fa8c9235aa 100644 --- a/pylint/testutils/functional/lint_module_output_update.py +++ b/pylint/testutils/functional/lint_module_output_update.py @@ -31,6 +31,8 @@ def _check_output_text( actual_output: list[OutputLine], ) -> None: """Overwrite or remove the expected output file based on actual output.""" + if self._test_file.expected_output_is_fallback: + return # Remove the expected file if no output is actually emitted and a file exists if not actual_output: if os.path.exists(self._test_file.expected_output): diff --git a/pylint/testutils/functional/test_file.py b/pylint/testutils/functional/test_file.py index 342ced44bf..fae018753a 100644 --- a/pylint/testutils/functional/test_file.py +++ b/pylint/testutils/functional/test_file.py @@ -103,6 +103,15 @@ def module(self) -> str: @property def expected_output(self) -> str: + output, _ = self._resolve_expected_output() + return output + + @property + def expected_output_is_fallback(self) -> bool: + _, is_fallback = self._resolve_expected_output() + return is_fallback + + def _resolve_expected_output(self) -> tuple[str, bool]: files = [ p.stem for p in Path(self._directory).glob(f"{split(self.base)[-1]}.[0-9]*.txt") @@ -115,8 +124,11 @@ def expected_output(self) -> str: for opt in sorted(output_options, reverse=True): if _CURRENT_VERSION >= opt: str_opt = "".join([str(s) for s in opt]) - return join(self._directory, f"{self.base}.{str_opt}.txt") - return join(self._directory, self.base + ".txt") + return ( + join(self._directory, f"{self.base}.{str_opt}.txt"), + _CURRENT_VERSION != opt, + ) + return join(self._directory, self.base + ".txt"), False @property def source(self) -> str: diff --git a/tests/testutils/test_lint_module_output_update.py b/tests/testutils/test_lint_module_output_update.py index 60819ac74f..39b7f76c09 100644 --- a/tests/testutils/test_lint_module_output_update.py +++ b/tests/testutils/test_lint_module_output_update.py @@ -9,6 +9,7 @@ import shutil from collections.abc import Callable from pathlib import Path +from unittest.mock import patch import pytest @@ -71,6 +72,48 @@ def test_lint_module_output_update_remove_useless_txt( assert not expected_output_file.exists() +def test_lint_module_output_update_does_not_remove_fallback_versioned_output( + lint_module_fixture: Callable[[str], tuple[Path, Path, LintModuleOutputUpdate]], +) -> None: + """Fallback versioned expected output should not be deleted on update.""" + filename, expected_output_file, lmou = lint_module_fixture("fine_name") + expected_output_file.write_text("", encoding="utf8") + filename.write_text("", encoding="utf8") + fallback_output_file = filename.with_suffix(".313.txt") + fallback_output_file.write_text("old output\n", encoding="utf8") + + with patch( + "pylint.testutils.functional.test_file._CURRENT_VERSION", + new=(3, 14), + ): + assert Path(lmou._test_file.expected_output) == fallback_output_file + lmou.runTest() + assert expected_output_file.exists() + assert fallback_output_file.exists() + + +def test_lint_module_output_update_does_not_overwrite_fallback_versioned_output( + lint_module_fixture: Callable[[str], tuple[Path, Path, LintModuleOutputUpdate]], +) -> None: + """Fallback versioned expected output should not be overwritten on update.""" + filename, expected_output_file, lmou = lint_module_fixture("foo") + expected_output_file.write_text("", encoding="utf8") + filename.write_text("# [disallowed-name]\n", encoding="utf8") + fallback_output_file = filename.with_suffix(".313.txt") + fallback_output_file.write_text("old output\n", encoding="utf8") + + with patch( + "pylint.testutils.functional.test_file._CURRENT_VERSION", + new=(3, 14), + ): + assert Path(lmou._test_file.expected_output) == fallback_output_file + lmou.runTest() + + assert expected_output_file.exists() + assert fallback_output_file.exists() + assert fallback_output_file.read_text(encoding="utf8") == "old output\n" + + @pytest.mark.parametrize( "directory_path", DIRECTORIES, ids=[str(p) for p in DIRECTORIES] ) From 7c861ea0efa00d631781fa414919ef842ac71d22 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 09:02:52 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/testutils/test_lint_module_output_update.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/testutils/test_lint_module_output_update.py b/tests/testutils/test_lint_module_output_update.py index 39b7f76c09..bb4d0173af 100644 --- a/tests/testutils/test_lint_module_output_update.py +++ b/tests/testutils/test_lint_module_output_update.py @@ -73,7 +73,7 @@ def test_lint_module_output_update_remove_useless_txt( def test_lint_module_output_update_does_not_remove_fallback_versioned_output( - lint_module_fixture: Callable[[str], tuple[Path, Path, LintModuleOutputUpdate]], + lint_module_fixture: Callable[[str], tuple[Path, Path, LintModuleOutputUpdate]], ) -> None: """Fallback versioned expected output should not be deleted on update.""" filename, expected_output_file, lmou = lint_module_fixture("fine_name") @@ -83,8 +83,8 @@ def test_lint_module_output_update_does_not_remove_fallback_versioned_output( fallback_output_file.write_text("old output\n", encoding="utf8") with patch( - "pylint.testutils.functional.test_file._CURRENT_VERSION", - new=(3, 14), + "pylint.testutils.functional.test_file._CURRENT_VERSION", + new=(3, 14), ): assert Path(lmou._test_file.expected_output) == fallback_output_file lmou.runTest() @@ -93,7 +93,7 @@ def test_lint_module_output_update_does_not_remove_fallback_versioned_output( def test_lint_module_output_update_does_not_overwrite_fallback_versioned_output( - lint_module_fixture: Callable[[str], tuple[Path, Path, LintModuleOutputUpdate]], + lint_module_fixture: Callable[[str], tuple[Path, Path, LintModuleOutputUpdate]], ) -> None: """Fallback versioned expected output should not be overwritten on update.""" filename, expected_output_file, lmou = lint_module_fixture("foo") @@ -103,8 +103,8 @@ def test_lint_module_output_update_does_not_overwrite_fallback_versioned_output( fallback_output_file.write_text("old output\n", encoding="utf8") with patch( - "pylint.testutils.functional.test_file._CURRENT_VERSION", - new=(3, 14), + "pylint.testutils.functional.test_file._CURRENT_VERSION", + new=(3, 14), ): assert Path(lmou._test_file.expected_output) == fallback_output_file lmou.runTest()