From 8def706e6619fe2960af9a899fb38977f744514d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Jun 2026 12:14:36 +0000 Subject: [PATCH 1/3] Wrap visitor recursion errors in PluginExecutionFailed --- bugbear.py | 6 +++++- tests/test_bugbear.py | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/bugbear.py b/bugbear.py index c7d67cc..92cb6de 100644 --- a/bugbear.py +++ b/bugbear.py @@ -26,6 +26,7 @@ import attr # type: ignore import pycodestyle # type: ignore +from flake8.exceptions import PluginExecutionFailed __version__ = "25.11.29" @@ -106,7 +107,10 @@ def run(self) -> Iterable[tuple[int, int, str, type]]: b008_b039_extend_immutable_calls=b008_b039_extend_immutable_calls, b902_classmethod_decorators=b902_classmethod_decorators, ) - visitor.visit(self.tree) + try: + visitor.visit(self.tree) + except RecursionError as e: + raise PluginExecutionFailed(self.filename, self.name, e) from e for e in itertools.chain(visitor.errors, self.gen_line_based_checks()): if self.should_warn(e.message[:4]): yield self.adapt_error(e) diff --git a/tests/test_bugbear.py b/tests/test_bugbear.py index eb8e35a..ca8f666 100644 --- a/tests/test_bugbear.py +++ b/tests/test_bugbear.py @@ -13,6 +13,7 @@ from pathlib import Path import pytest +from flake8.exceptions import PluginExecutionFailed from bugbear import ( BugBearChecker, @@ -235,6 +236,18 @@ def test_b9_flake8_next_default_options(self): errors = list(bbc.run()) self.assertEqual(errors, []) + def test_recursion_error_is_wrapped(self): + from unittest.mock import patch + + bbc = BugBearChecker(filename=str(EVAL_FILES_DIR / "b001.py")) + with patch.object(BugBearVisitor, "visit", side_effect=RecursionError("boom")): + with self.assertRaises(PluginExecutionFailed) as excinfo: + list(bbc.run()) + + self.assertEqual(excinfo.exception.filename, str(EVAL_FILES_DIR / "b001.py")) + self.assertEqual(excinfo.exception.plugin_name, "flake8-bugbear") + self.assertIsInstance(excinfo.exception.original_exception, RecursionError) + def test_selfclean_bugbear(self): filename = Path(__file__).absolute().parent.parent / "bugbear.py" proc = subprocess.run( From 67f76c22af4bd4b3279098b90dc6f1eebcbdc97b Mon Sep 17 00:00:00 2001 From: Maciej Olko Date: Thu, 18 Jun 2026 15:37:14 +0200 Subject: [PATCH 2/3] Change exception handling from RecursionError to RuntimeError Generalise a bit. --- bugbear.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bugbear.py b/bugbear.py index 92cb6de..122297b 100644 --- a/bugbear.py +++ b/bugbear.py @@ -109,7 +109,7 @@ def run(self) -> Iterable[tuple[int, int, str, type]]: ) try: visitor.visit(self.tree) - except RecursionError as e: + except RuntimeError as e: raise PluginExecutionFailed(self.filename, self.name, e) from e for e in itertools.chain(visitor.errors, self.gen_line_based_checks()): if self.should_warn(e.message[:4]): From 22c5e9be476fe98e749be300418cbf479d7542a1 Mon Sep 17 00:00:00 2001 From: Cooper Lees Date: Thu, 18 Jun 2026 09:12:50 -0500 Subject: [PATCH 3/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- bugbear.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bugbear.py b/bugbear.py index 122297b..f85879b 100644 --- a/bugbear.py +++ b/bugbear.py @@ -109,8 +109,8 @@ def run(self) -> Iterable[tuple[int, int, str, type]]: ) try: visitor.visit(self.tree) - except RuntimeError as e: - raise PluginExecutionFailed(self.filename, self.name, e) from e + except RecursionError as exc: + raise PluginExecutionFailed(self.filename, self.name, exc) from exc for e in itertools.chain(visitor.errors, self.gen_line_based_checks()): if self.should_warn(e.message[:4]): yield self.adapt_error(e)