https://github.com/python/cpython/commit/e34945a94c8ed084d6742da0393880c975ebbc51
commit: e34945a94c8ed084d6742da0393880c975ebbc51
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: vstinner <[email protected]>
date: 2026-03-25T16:23:21Z
summary:

[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 <[email protected]>

files:
M Lib/_py_warnings.py
M Lib/test/test_warnings/__init__.py

diff --git a/Lib/_py_warnings.py b/Lib/_py_warnings.py
index 55f8c06959180b..36513ba2e05ef4 100644
--- a/Lib/_py_warnings.py
+++ b/Lib/_py_warnings.py
@@ -647,8 +647,8 @@ def __enter__(self):
                 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 @@ def __enter__(self):
                 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 @@ def __exit__(self, *exc_info):
                 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 4c3c715a8fbf0a..799ea4939ddab5 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 @@ def test_catchwarnings_with_simplefilter_error(self):
                     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
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to