efficient vim config
[dotfiles/.git] / .local / lib / python2.7 / site-packages / trollius / windows_utils.py
1 """
2 Various Windows specific bits and pieces
3 """
4 from __future__ import absolute_import
5
6 import sys
7
8 if sys.platform != 'win32':  # pragma: no cover
9     raise ImportError('win32 only')
10
11 import itertools
12 import msvcrt
13 import os
14 import socket
15 import subprocess
16 import tempfile
17 import warnings
18
19 import six
20
21 from . import py33_winapi as _winapi
22 from . import compat
23 from .py33_exceptions import wrap_error, BlockingIOError, InterruptedError
24
25
26 __all__ = ['socketpair', 'pipe', 'Popen', 'PIPE', 'PipeHandle']
27
28
29 # Constants/globals
30
31
32 BUFSIZE = 8192
33 PIPE = subprocess.PIPE
34 STDOUT = subprocess.STDOUT
35 _mmap_counter = itertools.count()
36
37
38 if hasattr(socket, 'socketpair'):
39     # Since Python 3.5, socket.socketpair() is now also available on Windows
40     socketpair = socket.socketpair
41 else:
42     # Replacement for socket.socketpair()
43     def socketpair(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
44         """A socket pair usable as a self-pipe, for Windows.
45
46         Origin: https://gist.github.com/4325783, by Geert Jansen.
47         Public domain.
48         """
49         if family == socket.AF_INET:
50             host = '127.0.0.1'
51         elif family == socket.AF_INET6:
52             host = '::1'
53         else:
54             raise ValueError("Only AF_INET and AF_INET6 socket address "
55                              "families are supported")
56         if type != socket.SOCK_STREAM:
57             raise ValueError("Only SOCK_STREAM socket type is supported")
58         if proto != 0:
59             raise ValueError("Only protocol zero is supported")
60
61         # We create a connected TCP socket. Note the trick with setblocking(0)
62         # that prevents us from having to create a thread.
63         lsock = socket.socket(family, type, proto)
64         try:
65             lsock.bind((host, 0))
66             lsock.listen(1)
67             # On IPv6, ignore flow_info and scope_id
68             addr, port = lsock.getsockname()[:2]
69             csock = socket.socket(family, type, proto)
70             try:
71                 csock.setblocking(False)
72                 try:
73                     wrap_error(csock.connect, (addr, port))
74                 except (BlockingIOError, InterruptedError):
75                     pass
76                 csock.setblocking(True)
77                 ssock, _ = lsock.accept()
78             except:
79                 csock.close()
80                 raise
81         finally:
82             lsock.close()
83         return (ssock, csock)
84
85
86 # Replacement for os.pipe() using handles instead of fds
87
88
89 def pipe(duplex=False, overlapped=(True, True), bufsize=BUFSIZE):
90     """Like os.pipe() but with overlapped support and using handles not fds."""
91     address = tempfile.mktemp(prefix=r'\\.\pipe\python-pipe-%d-%d-' %
92                               (os.getpid(), next(_mmap_counter)))
93
94     if duplex:
95         openmode = _winapi.PIPE_ACCESS_DUPLEX
96         access = _winapi.GENERIC_READ | _winapi.GENERIC_WRITE
97         obsize, ibsize = bufsize, bufsize
98     else:
99         openmode = _winapi.PIPE_ACCESS_INBOUND
100         access = _winapi.GENERIC_WRITE
101         obsize, ibsize = 0, bufsize
102
103     openmode |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE
104
105     if overlapped[0]:
106         openmode |= _winapi.FILE_FLAG_OVERLAPPED
107
108     if overlapped[1]:
109         flags_and_attribs = _winapi.FILE_FLAG_OVERLAPPED
110     else:
111         flags_and_attribs = 0
112
113     h1 = h2 = None
114     try:
115         h1 = _winapi.CreateNamedPipe(
116             address, openmode, _winapi.PIPE_WAIT,
117             1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL)
118
119         h2 = _winapi.CreateFile(
120             address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING,
121             flags_and_attribs, _winapi.NULL)
122
123         ov = _winapi.ConnectNamedPipe(h1, overlapped=True)
124         if hasattr(ov, 'GetOverlappedResult'):
125             # _winapi module of Python 3.3
126             ov.GetOverlappedResult(True)
127         else:
128             # _overlapped module
129             wrap_error(ov.getresult, True)
130         return h1, h2
131     except:
132         if h1 is not None:
133             _winapi.CloseHandle(h1)
134         if h2 is not None:
135             _winapi.CloseHandle(h2)
136         raise
137
138
139 # Wrapper for a pipe handle
140
141
142 class PipeHandle(object):
143     """Wrapper for an overlapped pipe handle which is vaguely file-object like.
144
145     The IOCP event loop can use these instead of socket objects.
146     """
147     def __init__(self, handle):
148         self._handle = handle
149
150     def __repr__(self):
151         if self._handle is not None:
152             handle = 'handle=%r' % self._handle
153         else:
154             handle = 'closed'
155         return '<%s %s>' % (self.__class__.__name__, handle)
156
157     @property
158     def handle(self):
159         return self._handle
160
161     def fileno(self):
162         if self._handle is None:
163             raise ValueError("I/O operatioon on closed pipe")
164         return self._handle
165
166     def close(self, CloseHandle=_winapi.CloseHandle):
167         if self._handle is not None:
168             CloseHandle(self._handle)
169             self._handle = None
170
171     def __del__(self):
172         if self._handle is not None:
173             if six.PY3:
174                 warnings.warn("unclosed %r" % self, ResourceWarning)
175             self.close()
176
177     def __enter__(self):
178         return self
179
180     def __exit__(self, t, v, tb):
181         self.close()
182
183
184 # Replacement for subprocess.Popen using overlapped pipe handles
185
186
187 class Popen(subprocess.Popen):
188     """Replacement for subprocess.Popen using overlapped pipe handles.
189
190     The stdin, stdout, stderr are None or instances of PipeHandle.
191     """
192     def __init__(self, args, stdin=None, stdout=None, stderr=None, **kwds):
193         assert not kwds.get('universal_newlines')
194         assert kwds.get('bufsize', 0) == 0
195         stdin_rfd = stdout_wfd = stderr_wfd = None
196         stdin_wh = stdout_rh = stderr_rh = None
197         if stdin == PIPE:
198             stdin_rh, stdin_wh = pipe(overlapped=(False, True), duplex=True)
199             stdin_rfd = msvcrt.open_osfhandle(stdin_rh, os.O_RDONLY)
200         else:
201             stdin_rfd = stdin
202         if stdout == PIPE:
203             stdout_rh, stdout_wh = pipe(overlapped=(True, False))
204             stdout_wfd = msvcrt.open_osfhandle(stdout_wh, 0)
205         else:
206             stdout_wfd = stdout
207         if stderr == PIPE:
208             stderr_rh, stderr_wh = pipe(overlapped=(True, False))
209             stderr_wfd = msvcrt.open_osfhandle(stderr_wh, 0)
210         elif stderr == STDOUT:
211             stderr_wfd = stdout_wfd
212         else:
213             stderr_wfd = stderr
214         try:
215             super(Popen, self).__init__(args,
216                                         stdin=stdin_rfd,
217                                         stdout=stdout_wfd,
218                                         stderr=stderr_wfd,
219                                         **kwds)
220         except:
221             for h in (stdin_wh, stdout_rh, stderr_rh):
222                 if h is not None:
223                     _winapi.CloseHandle(h)
224             raise
225         else:
226             if stdin_wh is not None:
227                 self.stdin = PipeHandle(stdin_wh)
228             if stdout_rh is not None:
229                 self.stdout = PipeHandle(stdout_rh)
230             if stderr_rh is not None:
231                 self.stderr = PipeHandle(stderr_rh)
232         finally:
233             if stdin == PIPE:
234                 os.close(stdin_rfd)
235             if stdout == PIPE:
236                 os.close(stdout_wfd)
237             if stderr == PIPE:
238                 os.close(stderr_wfd)