[Python-checkins] bpo-45410: regrtest replaces print_warning.orig_stderr (GH-28926)

vstinner webhook-mailer at python.org
Wed Oct 13 11:35:29 EDT 2021


https://github.com/python/cpython/commit/676201a59f90caace606d11d4172aa74c1cd4992
commit: 676201a59f90caace606d11d4172aa74c1cd4992
branch: main
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2021-10-13T17:35:21+02:00
summary:

bpo-45410: regrtest replaces print_warning.orig_stderr (GH-28926)

When running Python tests with -W, runtest() now replaces
support.print_warning.orig_stderr to preserve the messages order.

Add an unit test.

files:
M Lib/test/libregrtest/runtest.py
M Lib/test/libregrtest/save_env.py
M Lib/test/test_regrtest.py

diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py
index 6fb996a5f947b..23970410a28fb 100644
--- a/Lib/test/libregrtest/runtest.py
+++ b/Lib/test/libregrtest/runtest.py
@@ -196,10 +196,18 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult:
             stream = io.StringIO()
             orig_stdout = sys.stdout
             orig_stderr = sys.stderr
+            print_warning = support.print_warning
+            orig_print_warnings_stderr = print_warning.orig_stderr
+
             output = None
             try:
                 sys.stdout = stream
                 sys.stderr = stream
+                # print_warning() writes into the temporary stream to preserve
+                # messages order. If support.environment_altered becomes true,
+                # warnings will be written to sys.stderr below.
+                print_warning.orig_stderr = stream
+
                 result = _runtest_inner(ns, test_name,
                                         display_failure=False)
                 if not isinstance(result, Passed):
@@ -207,6 +215,7 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult:
             finally:
                 sys.stdout = orig_stdout
                 sys.stderr = orig_stderr
+                print_warning.orig_stderr = orig_print_warnings_stderr
 
             if output is not None:
                 sys.stderr.write(output)
diff --git a/Lib/test/libregrtest/save_env.py b/Lib/test/libregrtest/save_env.py
index f0bfcf389992d..60c9be24617a6 100644
--- a/Lib/test/libregrtest/save_env.py
+++ b/Lib/test/libregrtest/save_env.py
@@ -320,7 +320,8 @@ def __exit__(self, exc_type, exc_val, exc_tb):
                 support.environment_altered = True
                 restore(original)
                 if not self.quiet and not self.pgo:
-                    print_warning(f"{name} was modified by {self.testname}")
-                    print(f"  Before: {original}\n  After:  {current} ",
-                          file=sys.stderr, flush=True)
+                    print_warning(
+                        f"{name} was modified by {self.testname}\n"
+                        f"  Before: {original}\n"
+                        f"  After:  {current} ")
         return False
diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py
index 3780feeda30e1..dcc795de1a4b6 100644
--- a/Lib/test/test_regrtest.py
+++ b/Lib/test/test_regrtest.py
@@ -1300,6 +1300,46 @@ def test_threading_excepthook(self):
         self.assertIn("Warning -- Uncaught thread exception", output)
         self.assertIn("Exception: bug in thread", output)
 
+    def test_print_warning(self):
+        # bpo-45410: The order of messages must be preserved when -W and
+        # support.print_warning() are used.
+        code = textwrap.dedent(r"""
+            import sys
+            import unittest
+            from test import support
+
+            class MyObject:
+                pass
+
+            def func_bug():
+                raise Exception("bug in thread")
+
+            class Tests(unittest.TestCase):
+                def test_print_warning(self):
+                    print("msg1: stdout")
+                    support.print_warning("msg2: print_warning")
+                    # Fail with ENV CHANGED to see print_warning() log
+                    support.environment_altered = True
+        """)
+        testname = self.create_test(code=code)
+
+        # Expect an output like:
+        #
+        #   test_threading_excepthook (test.test_x.Tests) ... msg1: stdout
+        #   Warning -- msg2: print_warning
+        #   ok
+        regex = (r"test_print_warning.*msg1: stdout\n"
+                 r"Warning -- msg2: print_warning\n"
+                 r"ok\n")
+        for option in ("-v", "-W"):
+            with self.subTest(option=option):
+                cmd = ["--fail-env-changed", option, testname]
+                output = self.run_tests(*cmd, exitcode=3)
+                self.check_executed_tests(output, [testname],
+                                          env_changed=[testname],
+                                          fail_env_changed=True)
+                self.assertRegex(output, regex)
+
     def test_unicode_guard_env(self):
         guard = os.environ.get(setup.UNICODE_GUARD_ENV)
         self.assertIsNotNone(guard, f"{setup.UNICODE_GUARD_ENV} not set")



More information about the Python-checkins mailing list