From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Wed, 25 Mar 2026 16:23:21 +0000 (+0100) Subject: [3.14] gh-146358: Fix warnings.catch_warnings on Free Threading (GH-146374) (#146418) X-Git-Tag: v3.14.4~70 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e34945a94c8ed084d6742da0393880c975ebbc51;p=thirdparty%2FPython%2Fcpython.git [3.14] gh-146358: Fix warnings.catch_warnings on Free Threading (GH-146374) (#146418) gh-146358: Fix warnings.catch_warnings on Free Threading (GH-146374) catch_warnings now also overrides warnings.showwarning() on Free Threading to support custom warnings.showwarning(). (cherry picked from commit 0055140b2cf3e3a86ef9ab7a39e2083212b27c58) Co-authored-by: Victor Stinner --- diff --git a/Lib/_py_warnings.py b/Lib/_py_warnings.py index 55f8c0695918..36513ba2e05e 100644 --- a/Lib/_py_warnings.py +++ b/Lib/_py_warnings.py @@ -647,8 +647,8 @@ class catch_warnings(object): context = None self._filters = self._module.filters self._module.filters = self._filters[:] - self._showwarning = self._module.showwarning self._showwarnmsg_impl = self._module._showwarnmsg_impl + self._showwarning = self._module.showwarning self._module._filters_mutated_lock_held() if self._record: if _use_context: @@ -656,9 +656,9 @@ class catch_warnings(object): else: log = [] self._module._showwarnmsg_impl = log.append - # Reset showwarning() to the default implementation to make sure - # that _showwarnmsg() calls _showwarnmsg_impl() - self._module.showwarning = self._module._showwarning_orig + # Reset showwarning() to the default implementation to make sure + # that _showwarnmsg() calls _showwarnmsg_impl() + self._module.showwarning = self._module._showwarning_orig else: log = None if self._filter is not None: @@ -673,8 +673,8 @@ class catch_warnings(object): self._module._warnings_context.set(self._saved_context) else: self._module.filters = self._filters - self._module.showwarning = self._showwarning self._module._showwarnmsg_impl = self._showwarnmsg_impl + self._module.showwarning = self._showwarning self._module._filters_mutated_lock_held() diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 4c3c715a8fbf..799ea4939dda 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -1,5 +1,6 @@ from contextlib import contextmanager import linecache +import logging import os import importlib import inspect @@ -498,6 +499,47 @@ class FilterTests(BaseTest): stderr = stderr.getvalue() self.assertIn(error_msg, stderr) + def test_catchwarnings_with_showwarning(self): + # gh-146358: catch_warnings must override warnings.showwarning() + # if it's not the default implementation. + + warns = [] + def custom_showwarning(message, category, filename, lineno, + file=None, line=None): + warns.append(message) + + with self.module.catch_warnings(): + self.module.resetwarnings() + + with support.swap_attr(self.module, 'showwarning', + custom_showwarning): + with self.module.catch_warnings(record=True) as recorded: + self.module.warn("recorded") + self.assertEqual(len(recorded), 1) + self.assertEqual(str(recorded[0].message), 'recorded') + self.assertIs(self.module.showwarning, custom_showwarning) + + self.module.warn("custom") + + self.assertEqual(len(warns), 1) + self.assertEqual(str(warns[0]), "custom") + + def test_catchwarnings_logging(self): + # gh-146358: catch_warnings(record=True) must replace the + # showwarning() function set by logging.captureWarnings(True). + + with self.module.catch_warnings(): + self.module.resetwarnings() + logging.captureWarnings(True) + + with self.module.catch_warnings(record=True) as recorded: + self.module.warn("recorded") + self.assertEqual(len(recorded), 1) + self.assertEqual(str(recorded[0].message), 'recorded') + + logging.captureWarnings(False) + + class CFilterTests(FilterTests, unittest.TestCase): module = c_warnings