Skip to content

Commit f6e58ae

Browse files
authored
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().
1 parent d36cf5f commit f6e58ae

File tree

6 files changed

+81
-49
lines changed

6 files changed

+81
-49
lines changed

Lib/test/audit-tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,9 @@ def hook(event, args):
350350

351351

352352
if __name__ == "__main__":
353-
from test.libregrtest.setup import suppress_msvcrt_asserts
353+
from test.support import suppress_msvcrt_asserts
354354

355-
suppress_msvcrt_asserts(False)
355+
suppress_msvcrt_asserts()
356356

357357
test = sys.argv[1]
358358
globals()[test]()

Lib/test/libregrtest/setup.py

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def setup_tests(ns):
6969
if ns.threshold is not None:
7070
gc.set_threshold(ns.threshold)
7171

72-
suppress_msvcrt_asserts(ns.verbose and ns.verbose >= 2)
72+
support.suppress_msvcrt_asserts(ns.verbose and ns.verbose >= 2)
7373

7474
support.use_resources = ns.use_resources
7575

@@ -93,31 +93,6 @@ def _test_audit_hook(name, args):
9393
support.LONG_TIMEOUT = min(support.LONG_TIMEOUT, ns.timeout)
9494

9595

96-
def suppress_msvcrt_asserts(verbose):
97-
try:
98-
import msvcrt
99-
except ImportError:
100-
return
101-
102-
msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS|
103-
msvcrt.SEM_NOALIGNMENTFAULTEXCEPT|
104-
msvcrt.SEM_NOGPFAULTERRORBOX|
105-
msvcrt.SEM_NOOPENFILEERRORBOX)
106-
try:
107-
msvcrt.CrtSetReportMode
108-
except AttributeError:
109-
# release build
110-
return
111-
112-
for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
113-
if verbose:
114-
msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE)
115-
msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR)
116-
else:
117-
msvcrt.CrtSetReportMode(m, 0)
118-
119-
120-
12196
def replace_stdout():
12297
"""Set stdout encoder error handler to backslashreplace (as stderr error
12398
handler) to avoid UnicodeEncodeError when printing a traceback"""

Lib/test/support/__init__.py

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,6 +1899,27 @@ def test__all__(self):
18991899
test_case.assertCountEqual(module.__all__, expected)
19001900

19011901

1902+
def suppress_msvcrt_asserts(verbose=False):
1903+
try:
1904+
import msvcrt
1905+
except ImportError:
1906+
return
1907+
1908+
msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS
1909+
| msvcrt.SEM_NOALIGNMENTFAULTEXCEPT
1910+
| msvcrt.SEM_NOGPFAULTERRORBOX
1911+
| msvcrt.SEM_NOOPENFILEERRORBOX)
1912+
1913+
# CrtSetReportMode() is only available in debug build
1914+
if hasattr(msvcrt, 'CrtSetReportMode'):
1915+
for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
1916+
if verbose:
1917+
msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE)
1918+
msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR)
1919+
else:
1920+
msvcrt.CrtSetReportMode(m, 0)
1921+
1922+
19021923
class SuppressCrashReport:
19031924
"""Try to prevent a crash report from popping up.
19041925
@@ -1910,30 +1931,25 @@ class SuppressCrashReport:
19101931

19111932
def __enter__(self):
19121933
"""On Windows, disable Windows Error Reporting dialogs using
1913-
SetErrorMode.
1934+
SetErrorMode() and CrtSetReportMode().
19141935
19151936
On UNIX, try to save the previous core file size limit, then set
19161937
soft limit to 0.
19171938
"""
19181939
if sys.platform.startswith('win'):
19191940
# see http://msdn.microsoft.com/en-us/library/windows/desktop/ms680621.aspx
1920-
# GetErrorMode is not available on Windows XP and Windows Server 2003,
1921-
# but SetErrorMode returns the previous value, so we can use that
1922-
import ctypes
1923-
self._k32 = ctypes.windll.kernel32
1924-
SEM_NOGPFAULTERRORBOX = 0x02
1925-
self.old_value = self._k32.SetErrorMode(SEM_NOGPFAULTERRORBOX)
1926-
self._k32.SetErrorMode(self.old_value | SEM_NOGPFAULTERRORBOX)
1927-
1928-
# Suppress assert dialogs in debug builds
1929-
# (see http://bugs.python.org/issue23314)
19301941
try:
19311942
import msvcrt
1932-
msvcrt.CrtSetReportMode
1933-
except (AttributeError, ImportError):
1934-
# no msvcrt or a release build
1935-
pass
1936-
else:
1943+
except ImportError:
1944+
return
1945+
1946+
self.old_value = msvcrt.GetErrorMode()
1947+
1948+
msvcrt.SetErrorMode(self.old_value | msvcrt.SEM_NOGPFAULTERRORBOX)
1949+
1950+
# bpo-23314: Suppress assert dialogs in debug builds.
1951+
# CrtSetReportMode() is only available in debug build.
1952+
if hasattr(msvcrt, 'CrtSetReportMode'):
19371953
self.old_modes = {}
19381954
for report_type in [msvcrt.CRT_WARN,
19391955
msvcrt.CRT_ERROR,
@@ -1985,10 +2001,10 @@ def __exit__(self, *ignore_exc):
19852001
return
19862002

19872003
if sys.platform.startswith('win'):
1988-
self._k32.SetErrorMode(self.old_value)
2004+
import msvcrt
2005+
msvcrt.SetErrorMode(self.old_value)
19892006

19902007
if self.old_modes:
1991-
import msvcrt
19922008
for report_type, (old_mode, old_file) in self.old_modes.items():
19932009
msvcrt.CrtSetReportMode(report_type, old_mode)
19942010
msvcrt.CrtSetReportFile(report_type, old_file)
@@ -2332,7 +2348,6 @@ def wait_process(pid, *, exitcode, timeout=None):
23322348
if timeout is None:
23332349
timeout = SHORT_TIMEOUT
23342350
t0 = time.monotonic()
2335-
deadline = t0 + timeout
23362351
sleep = 0.001
23372352
max_sleep = 0.1
23382353
while True:

Lib/test/test_repl.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,11 @@ def test_close_stdin(self):
9898
print("before close")
9999
os.close(0)
100100
''')
101-
process = spawn_repl()
101+
prepare_repl = dedent('''
102+
from test.support import suppress_msvcrt_asserts
103+
suppress_msvcrt_asserts()
104+
''')
105+
process = spawn_repl('-c', prepare_repl)
102106
output = process.communicate(user_input)[0]
103107
self.assertEqual(process.returncode, 0)
104108
self.assertIn('before close', output)

PC/clinic/msvcrtmodule.c.h

Lines changed: 19 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PC/msvcrtmodule.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,25 @@ msvcrt_set_error_mode_impl(PyObject *module, int mode)
482482
}
483483
#endif /* _DEBUG */
484484

485+
/*[clinic input]
486+
msvcrt.GetErrorMode
487+
488+
Wrapper around GetErrorMode.
489+
[clinic start generated code]*/
490+
491+
static PyObject *
492+
msvcrt_GetErrorMode_impl(PyObject *module)
493+
/*[clinic end generated code: output=3103fc6145913591 input=5a7fb083b6dd71fd]*/
494+
{
495+
unsigned int res;
496+
497+
_Py_BEGIN_SUPPRESS_IPH
498+
res = GetErrorMode();
499+
_Py_END_SUPPRESS_IPH
500+
501+
return PyLong_FromUnsignedLong(res);
502+
}
503+
485504
/*[clinic input]
486505
msvcrt.SetErrorMode
487506
@@ -520,6 +539,7 @@ static struct PyMethodDef msvcrt_functions[] = {
520539
MSVCRT_GETCHE_METHODDEF
521540
MSVCRT_PUTCH_METHODDEF
522541
MSVCRT_UNGETCH_METHODDEF
542+
MSVCRT_GETERRORMODE_METHODDEF
523543
MSVCRT_SETERRORMODE_METHODDEF
524544
MSVCRT_CRTSETREPORTFILE_METHODDEF
525545
MSVCRT_CRTSETREPORTMODE_METHODDEF

0 commit comments

Comments
 (0)