[Python-checkins] bpo-40826: Fix test_repl.test_close_stdin() on Windows (GH-20779)

Victor Stinner webhook-mailer at python.org
Wed Jun 10 12:49:30 EDT 2020


https://github.com/python/cpython/commit/f6e58aefde2e57e4cb11ea7743955da53a3f1e80
commit: f6e58aefde2e57e4cb11ea7743955da53a3f1e80
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-06-10T18:49:23+02:00
summary:

bpo-40826: Fix test_repl.test_close_stdin() on Windows (GH-20779)

test_repl.test_close_stdin() now calls
support.suppress_msvcrt_asserts() to fix the test on Windows.

* Move suppress_msvcrt_asserts() from test.libregrtest.setup to
  test.support. Make its verbose parameter optional: verbose=False by
  default.
* Add msvcrt.GetErrorMode().
* SuppressCrashReport now uses GetErrorMode() and SetErrorMode() of
  the msvcrt module, rather than using ctypes.
* Remove also an unused variable (deadline) in wait_process().

files:
M Lib/test/audit-tests.py
M Lib/test/libregrtest/setup.py
M Lib/test/support/__init__.py
M Lib/test/test_repl.py
M PC/clinic/msvcrtmodule.c.h
M PC/msvcrtmodule.c

diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py
index b90c4b8f75794..a58395b068b39 100644
--- a/Lib/test/audit-tests.py
+++ b/Lib/test/audit-tests.py
@@ -350,9 +350,9 @@ def hook(event, args):
 
 
 if __name__ == "__main__":
-    from test.libregrtest.setup import suppress_msvcrt_asserts
+    from test.support import suppress_msvcrt_asserts
 
-    suppress_msvcrt_asserts(False)
+    suppress_msvcrt_asserts()
 
     test = sys.argv[1]
     globals()[test]()
diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py
index ce8149677e0b9..1f264c1be49fe 100644
--- a/Lib/test/libregrtest/setup.py
+++ b/Lib/test/libregrtest/setup.py
@@ -69,7 +69,7 @@ def setup_tests(ns):
     if ns.threshold is not None:
         gc.set_threshold(ns.threshold)
 
-    suppress_msvcrt_asserts(ns.verbose and ns.verbose >= 2)
+    support.suppress_msvcrt_asserts(ns.verbose and ns.verbose >= 2)
 
     support.use_resources = ns.use_resources
 
@@ -93,31 +93,6 @@ def _test_audit_hook(name, args):
         support.LONG_TIMEOUT = min(support.LONG_TIMEOUT, ns.timeout)
 
 
-def suppress_msvcrt_asserts(verbose):
-    try:
-        import msvcrt
-    except ImportError:
-        return
-
-    msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS|
-                        msvcrt.SEM_NOALIGNMENTFAULTEXCEPT|
-                        msvcrt.SEM_NOGPFAULTERRORBOX|
-                        msvcrt.SEM_NOOPENFILEERRORBOX)
-    try:
-        msvcrt.CrtSetReportMode
-    except AttributeError:
-        # release build
-        return
-
-    for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
-        if verbose:
-            msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE)
-            msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR)
-        else:
-            msvcrt.CrtSetReportMode(m, 0)
-
-
-
 def replace_stdout():
     """Set stdout encoder error handler to backslashreplace (as stderr error
     handler) to avoid UnicodeEncodeError when printing a traceback"""
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 3a5f7b556d767..83b21733de0f1 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -1899,6 +1899,27 @@ def test__all__(self):
     test_case.assertCountEqual(module.__all__, expected)
 
 
+def suppress_msvcrt_asserts(verbose=False):
+    try:
+        import msvcrt
+    except ImportError:
+        return
+
+    msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS
+                        | msvcrt.SEM_NOALIGNMENTFAULTEXCEPT
+                        | msvcrt.SEM_NOGPFAULTERRORBOX
+                        | msvcrt.SEM_NOOPENFILEERRORBOX)
+
+    # CrtSetReportMode() is only available in debug build
+    if hasattr(msvcrt, 'CrtSetReportMode'):
+        for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
+            if verbose:
+                msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE)
+                msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR)
+            else:
+                msvcrt.CrtSetReportMode(m, 0)
+
+
 class SuppressCrashReport:
     """Try to prevent a crash report from popping up.
 
@@ -1910,30 +1931,25 @@ class SuppressCrashReport:
 
     def __enter__(self):
         """On Windows, disable Windows Error Reporting dialogs using
-        SetErrorMode.
+        SetErrorMode() and CrtSetReportMode().
 
         On UNIX, try to save the previous core file size limit, then set
         soft limit to 0.
         """
         if sys.platform.startswith('win'):
             # see http://msdn.microsoft.com/en-us/library/windows/desktop/ms680621.aspx
-            # GetErrorMode is not available on Windows XP and Windows Server 2003,
-            # but SetErrorMode returns the previous value, so we can use that
-            import ctypes
-            self._k32 = ctypes.windll.kernel32
-            SEM_NOGPFAULTERRORBOX = 0x02
-            self.old_value = self._k32.SetErrorMode(SEM_NOGPFAULTERRORBOX)
-            self._k32.SetErrorMode(self.old_value | SEM_NOGPFAULTERRORBOX)
-
-            # Suppress assert dialogs in debug builds
-            # (see http://bugs.python.org/issue23314)
             try:
                 import msvcrt
-                msvcrt.CrtSetReportMode
-            except (AttributeError, ImportError):
-                # no msvcrt or a release build
-                pass
-            else:
+            except ImportError:
+                return
+
+            self.old_value = msvcrt.GetErrorMode()
+
+            msvcrt.SetErrorMode(self.old_value | msvcrt.SEM_NOGPFAULTERRORBOX)
+
+            # bpo-23314: Suppress assert dialogs in debug builds.
+            # CrtSetReportMode() is only available in debug build.
+            if hasattr(msvcrt, 'CrtSetReportMode'):
                 self.old_modes = {}
                 for report_type in [msvcrt.CRT_WARN,
                                     msvcrt.CRT_ERROR,
@@ -1985,10 +2001,10 @@ def __exit__(self, *ignore_exc):
             return
 
         if sys.platform.startswith('win'):
-            self._k32.SetErrorMode(self.old_value)
+            import msvcrt
+            msvcrt.SetErrorMode(self.old_value)
 
             if self.old_modes:
-                import msvcrt
                 for report_type, (old_mode, old_file) in self.old_modes.items():
                     msvcrt.CrtSetReportMode(report_type, old_mode)
                     msvcrt.CrtSetReportFile(report_type, old_file)
@@ -2332,7 +2348,6 @@ def wait_process(pid, *, exitcode, timeout=None):
         if timeout is None:
             timeout = SHORT_TIMEOUT
         t0 = time.monotonic()
-        deadline = t0 + timeout
         sleep = 0.001
         max_sleep = 0.1
         while True:
diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py
index 563f188706b93..03bf8d8b5483f 100644
--- a/Lib/test/test_repl.py
+++ b/Lib/test/test_repl.py
@@ -98,7 +98,11 @@ def test_close_stdin(self):
             print("before close")
             os.close(0)
         ''')
-        process = spawn_repl()
+        prepare_repl = dedent('''
+            from test.support import suppress_msvcrt_asserts
+            suppress_msvcrt_asserts()
+        ''')
+        process = spawn_repl('-c', prepare_repl)
         output = process.communicate(user_input)[0]
         self.assertEqual(process.returncode, 0)
         self.assertIn('before close', output)
diff --git a/PC/clinic/msvcrtmodule.c.h b/PC/clinic/msvcrtmodule.c.h
index 9701e8a63be8c..1ac82cb965b64 100644
--- a/PC/clinic/msvcrtmodule.c.h
+++ b/PC/clinic/msvcrtmodule.c.h
@@ -590,6 +590,24 @@ msvcrt_set_error_mode(PyObject *module, PyObject *arg)
 
 #endif /* defined(_DEBUG) */
 
+PyDoc_STRVAR(msvcrt_GetErrorMode__doc__,
+"GetErrorMode($module, /)\n"
+"--\n"
+"\n"
+"Wrapper around GetErrorMode.");
+
+#define MSVCRT_GETERRORMODE_METHODDEF    \
+    {"GetErrorMode", (PyCFunction)msvcrt_GetErrorMode, METH_NOARGS, msvcrt_GetErrorMode__doc__},
+
+static PyObject *
+msvcrt_GetErrorMode_impl(PyObject *module);
+
+static PyObject *
+msvcrt_GetErrorMode(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return msvcrt_GetErrorMode_impl(module);
+}
+
 PyDoc_STRVAR(msvcrt_SetErrorMode__doc__,
 "SetErrorMode($module, mode, /)\n"
 "--\n"
@@ -629,4 +647,4 @@ msvcrt_SetErrorMode(PyObject *module, PyObject *arg)
 #ifndef MSVCRT_SET_ERROR_MODE_METHODDEF
     #define MSVCRT_SET_ERROR_MODE_METHODDEF
 #endif /* !defined(MSVCRT_SET_ERROR_MODE_METHODDEF) */
-/*[clinic end generated code: output=ab3b5ce5c1447f0e input=a9049054013a1b77]*/
+/*[clinic end generated code: output=20dfbc768edce7c0 input=a9049054013a1b77]*/
diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c
index faceb03fba39d..b7ff20ab0fb1c 100644
--- a/PC/msvcrtmodule.c
+++ b/PC/msvcrtmodule.c
@@ -482,6 +482,25 @@ msvcrt_set_error_mode_impl(PyObject *module, int mode)
 }
 #endif /* _DEBUG */
 
+/*[clinic input]
+msvcrt.GetErrorMode
+
+Wrapper around GetErrorMode.
+[clinic start generated code]*/
+
+static PyObject *
+msvcrt_GetErrorMode_impl(PyObject *module)
+/*[clinic end generated code: output=3103fc6145913591 input=5a7fb083b6dd71fd]*/
+{
+    unsigned int res;
+
+    _Py_BEGIN_SUPPRESS_IPH
+    res = GetErrorMode();
+    _Py_END_SUPPRESS_IPH
+
+    return PyLong_FromUnsignedLong(res);
+}
+
 /*[clinic input]
 msvcrt.SetErrorMode
 
@@ -520,6 +539,7 @@ static struct PyMethodDef msvcrt_functions[] = {
     MSVCRT_GETCHE_METHODDEF
     MSVCRT_PUTCH_METHODDEF
     MSVCRT_UNGETCH_METHODDEF
+    MSVCRT_GETERRORMODE_METHODDEF
     MSVCRT_SETERRORMODE_METHODDEF
     MSVCRT_CRTSETREPORTFILE_METHODDEF
     MSVCRT_CRTSETREPORTMODE_METHODDEF



More information about the Python-checkins mailing list