forked from DonJayamanne/pythonVSCode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdaemon_output.py
More file actions
131 lines (104 loc) · 3.96 KB
/
Copy pathdaemon_output.py
File metadata and controls
131 lines (104 loc) · 3.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
# Code borrowed from `pydevd` (https://github.com/microsoft/ptvsd/blob/608803cb99b450aedecc45167a7339b9b7b93b75/src/ptvsd/_vendored/pydevd/pydevd.py)
import os
import sys
import logging
from threading import Lock
log = logging.getLogger(__name__)
class IORedirector:
"""
This class works to wrap a stream (stdout/stderr) with an additional redirect.
"""
def __init__(self, name, original, new_redirect, wrap_buffer=False):
"""
:param stream original:
The stream to be wrapped (usually stdout/stderr, but could be None).
:param stream new_redirect:
:param bool wrap_buffer:
Whether to create a buffer attribute (needed to mimick python 3 s
tdout/stderr which has a buffer to write binary data).
"""
self._name = name
self._lock = Lock()
self._writing = False
self._redirect_to = (new_redirect,)
if wrap_buffer and hasattr(original, "buffer"):
self.buffer = IORedirector(
name, original.buffer, new_redirect.buffer, False
)
def write(self, s):
# Note that writing to the original stream may fail for some reasons
# (such as trying to write something that's not a string or having it closed).
with self._lock:
if self._writing:
return
self._writing = True
try:
for r in self._redirect_to:
if hasattr(r, "write"):
r.write(s)
finally:
self._writing = False
def isatty(self):
for r in self._redirect_to:
if hasattr(r, "isatty"):
return r.isatty()
return False
def flush(self):
for r in self._redirect_to:
if hasattr(r, "flush"):
r.flush()
def __getattr__(self, name):
log.info("getting attr for %s: %s", self._name, name)
for r in self._redirect_to:
if hasattr(r, name):
return getattr(r, name)
raise AttributeError(name)
class CustomWriter(object):
def __init__(self, name, wrap_stream, wrap_buffer, on_write=None):
"""
:param wrap_stream:
Either sys.stdout or sys.stderr.
:param bool wrap_buffer:
If True the buffer attribute (which wraps writing bytes) should be
wrapped.
:param callable(str) on_write:
Call back with the string that has been written.
"""
self._name = name
encoding = getattr(wrap_stream, "encoding", None)
if not encoding:
encoding = os.environ.get("PYTHONIOENCODING", "utf-8")
self.encoding = encoding
if wrap_buffer:
self.buffer = CustomWriter(
name, wrap_stream, wrap_buffer=False, on_write=on_write
)
self._on_write = on_write
def flush(self):
pass # no-op here
def write(self, s):
if s:
# Need s in str
if isinstance(s, bytes):
s = s.decode(self.encoding, errors="replace")
log.info("write to %s: %s", self._name, s)
if self._on_write is not None:
self._on_write(s)
_stdin = sys.stdin.buffer
_stdout = sys.stdout.buffer
def get_io_buffers():
return _stdin, _stdout
def redirect_output(stdout_handler, stderr_handler):
log.info("Redirect stdout/stderr")
sys._vsc_out_buffer_ = CustomWriter("stdout", sys.stdout, True, stdout_handler)
sys.stdout_original = sys.stdout
_stdout_redirector = sys.stdout = IORedirector(
"stdout", sys.stdout, sys._vsc_out_buffer_, True
)
sys._vsc_err_buffer_ = CustomWriter("stderr", sys.stderr, True, stderr_handler)
sys.stderr_original = sys.stderr
_stderr_redirector = sys.stderr = IORedirector(
"stderr", sys.stderr, sys._vsc_err_buffer_, True
)