MCPcopy
hub / github.com/pytest-dev/pytest / _windowsconsoleio_workaround

Function _windowsconsoleio_workaround

src/_pytest/capture.py:100–152  ·  view source on GitHub ↗

Workaround for Windows Unicode console handling. 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 descriptors whe

(stream: TextIO)

Source from the content-addressed store, hash-verified

98
99
100def _windowsconsoleio_workaround(stream: TextIO) -> None:
101 """Workaround for Windows Unicode console handling.
102
103 Python 3.6 implemented Unicode console handling for Windows. This works
104 by reading/writing to the raw console handle using
105 ``{Read,Write}ConsoleW``.
106
107 The problem is that we are going to ``dup2`` over the stdio file
108 descriptors when doing ``FDCapture`` and this will ``CloseHandle`` the
109 handles used by Python to write to the console. Though there is still some
110 weirdness and the console handle seems to only be closed randomly and not
111 on the first call to ``CloseHandle``, or maybe it gets reopened with the
112 same handle value when we suspend capturing.
113
114 The workaround in this case will reopen stdio with a different fd which
115 also means a different handle by replicating the logic in
116 "Py_lifecycle.c:initstdio/create_stdio".
117
118 :param stream:
119 In practice ``sys.stdout`` or ``sys.stderr``, but given
120 here as parameter for unittesting purposes.
121
122 See https://github.com/pytest-dev/py/issues/103.
123 """
124 if not sys.platform.startswith("win32") or hasattr(sys, "pypy_version_info"):
125 return
126
127 # Bail out if ``stream`` doesn't seem like a proper ``io`` stream (#2666).
128 if not hasattr(stream, "buffer"): # type: ignore[unreachable,unused-ignore]
129 return
130
131 raw_stdout = stream.buffer.raw if hasattr(stream.buffer, "raw") else stream.buffer
132
133 if not isinstance(raw_stdout, io._WindowsConsoleIO): # type: ignore[attr-defined,unused-ignore]
134 return
135
136 def _reopen_stdio(f, mode):
137 if not hasattr(stream.buffer, "raw") and mode[0] == "w":
138 buffering = 0
139 else:
140 buffering = -1
141
142 return io.TextIOWrapper(
143 open(os.dup(f.fileno()), mode, buffering),
144 f.encoding,
145 f.errors,
146 f.newlines,
147 f.line_buffering,
148 )
149
150 sys.stdin = _reopen_stdio(sys.stdin, "rb")
151 sys.stdout = _reopen_stdio(sys.stdout, "wb")
152 sys.stderr = _reopen_stdio(sys.stderr, "wb")
153
154
155@hookimpl(wrapper=True)

Calls 1

_reopen_stdioFunction · 0.85