https://github.com/python/cpython/commit/0055140b2cf3e3a86ef9ab7a39e2083212b27c58
commit: 0055140b2cf3e3a86ef9ab7a39e2083212b27c58
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-03-25T14:34:50+01:00
summary:

gh-146358: Fix warnings.catch_warnings on Free Threading (#146374)

catch_warnings now also overrides warnings.showwarning() on Free
Threading to support custom warnings.showwarning().

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 d5a9cec86f3674..81a386c4487d95 100644
--- a/Lib/_py_warnings.py
+++ b/Lib/_py_warnings.py
@@ -703,8 +703,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:
@@ -712,9 +712,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:
@@ -729,8 +729,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 a6af5057cc8968..d86844c1a29a9a 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
@@ -509,6 +510,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