MCPcopy Create free account
hub / github.com/pytest-dev/pytest / _py36_windowsconsoleio_workaround

Function _py36_windowsconsoleio_workaround

src/_pytest/capture.py:71–124  ·  view source on GitHub ↗

Workaround for Windows Unicode console handling on Python>=3.6. Python 3.6 implemented Unicode console handling for Windows. This works by reading/writing to the raw console handle using ``{Read,Write}ConsoleW``. The problem is that we are going to ``dup2`` over the stdio file

(stream: TextIO)

Source from the content-addressed store, hash-verified

69
70
71def _py36_windowsconsoleio_workaround(stream: TextIO) -> None:
72 """Workaround for Windows Unicode console handling on Python>=3.6.
73
74 Python 3.6 implemented Unicode console handling for Windows. This works
75 by reading/writing to the raw console handle using
76 ``{Read,Write}ConsoleW``.
77
78 The problem is that we are going to ``dup2`` over the stdio file
79 descriptors when doing ``FDCapture`` and this will ``CloseHandle`` the
80 handles used by Python to write to the console. Though there is still some
81 weirdness and the console handle seems to only be closed randomly and not
82 on the first call to ``CloseHandle``, or maybe it gets reopened with the
83 same handle value when we suspend capturing.
84
85 The workaround in this case will reopen stdio with a different fd which
86 also means a different handle by replicating the logic in
87 "Py_lifecycle.c:initstdio/create_stdio".
88
89 :param stream:
90 In practice ``sys.stdout`` or ``sys.stderr``, but given
91 here as parameter for unittesting purposes.
92
93 See https://github.com/pytest-dev/py/issues/103.
94 """
95 if not sys.platform.startswith("win32") or hasattr(sys, "pypy_version_info"):
96 return
97
98 # Bail out if ``stream`` doesn't seem like a proper ``io`` stream (#2666).
99 if not hasattr(stream, "buffer"): # type: ignore[unreachable]
100 return
101
102 buffered = hasattr(stream.buffer, "raw")
103 raw_stdout = stream.buffer.raw if buffered else stream.buffer # type: ignore[attr-defined]
104
105 if not isinstance(raw_stdout, io._WindowsConsoleIO): # type: ignore[attr-defined]
106 return
107
108 def _reopen_stdio(f, mode):
109 if not buffered and mode[0] == "w":
110 buffering = 0
111 else:
112 buffering = -1
113
114 return io.TextIOWrapper(
115 open(os.dup(f.fileno()), mode, buffering), # type: ignore[arg-type]
116 f.encoding,
117 f.errors,
118 f.newlines,
119 f.line_buffering,
120 )
121
122 sys.stdin = _reopen_stdio(sys.stdin, "rb")
123 sys.stdout = _reopen_stdio(sys.stdout, "wb")
124 sys.stderr = _reopen_stdio(sys.stderr, "wb")
125
126
127@hookimpl(hookwrapper=True)

Calls 1

_reopen_stdioFunction · 0.85