diff --git a/src/debugpy/launcher/output.py b/src/debugpy/launcher/output.py index eda001ee..f0733823 100644 --- a/src/debugpy/launcher/output.py +++ b/src/debugpy/launcher/output.py @@ -29,11 +29,16 @@ class CaptureOutput(object): self.category = category self._whose = whose self._fd = fd - self._stream = stream if sys.version_info < (3,) else stream.buffer self._decoder = codecs.getincrementaldecoder("utf-8")(errors="surrogateescape") - self._encode = codecs.getencoder( - "utf-8" if stream.encoding is None else stream.encoding - ) + + if stream is None: + # Can happen if running under pythonw.exe. + self._stream = None + else: + self._stream = stream if sys.version_info < (3,) else stream.buffer + self._encode = codecs.getencoder( + "utf-8" if stream.encoding is None else stream.encoding + ) self._worker_thread = threading.Thread(target=self._worker, name=category) self._worker_thread.start() @@ -71,6 +76,9 @@ class CaptureOutput(object): except Exception: pass # channel to adapter is already closed + if self._stream is None: + return + s, _ = self._encode(s, "surrogateescape") size = len(s) i = 0 diff --git a/tests/debugpy/test_output.py b/tests/debugpy/test_output.py index 86be8d82..43b1ea9e 100644 --- a/tests/debugpy/test_output.py +++ b/tests/debugpy/test_output.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function, unicode_literals import pytest +import sys from tests import debug from tests.debug import runners @@ -119,3 +120,32 @@ def test_non_ascii_output(pyfile, target, run): b"\xc3\xa9 \xc3\xa0 \xc3\xb6 \xc3\xb9\n", b"\xc3\x83\xc2\xa9 \xc3\x83\xc2\xa0 \xc3\x83\xc2\xb6 \xc3\x83\xc2\xb9\n", ) + + +if sys.platform == "win32": + + @pytest.mark.parametrize("redirect_output", ["", "redirect_output"]) + def test_pythonw_output(pyfile, target, run, redirect_output): + @pyfile + def code_to_debug(): + import debuggee + + debuggee.setup() + print("ok") + () # @wait_for_output + + with debug.Session() as session: + # Don't capture launcher output - we want to see how it handles not + # having sys.stdin and sys.stdout available. + session.captured_output = set() + + session.config["pythonPath"] = sys.executable + "/../pythonw.exe" + session.config["redirectOutput"] = bool(redirect_output) + + with run(session, target(code_to_debug)): + session.set_breakpoints(code_to_debug, all) + + session.wait_for_stop() + session.request_continue() + + assert session.output("stdout") == ("ok\n" if redirect_output else "")