2 Various Windows specific bits and pieces
4 from __future__ import absolute_import
8 if sys.platform != 'win32': # pragma: no cover
9 raise ImportError('win32 only')
21 from . import py33_winapi as _winapi
23 from .py33_exceptions import wrap_error, BlockingIOError, InterruptedError
26 __all__ = ['socketpair', 'pipe', 'Popen', 'PIPE', 'PipeHandle']
33 PIPE = subprocess.PIPE
34 STDOUT = subprocess.STDOUT
35 _mmap_counter = itertools.count()
38 if hasattr(socket, 'socketpair'):
39 # Since Python 3.5, socket.socketpair() is now also available on Windows
40 socketpair = socket.socketpair
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.
46 Origin: https://gist.github.com/4325783, by Geert Jansen.
49 if family == socket.AF_INET:
51 elif family == socket.AF_INET6:
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")
59 raise ValueError("Only protocol zero is supported")
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)
67 # On IPv6, ignore flow_info and scope_id
68 addr, port = lsock.getsockname()[:2]
69 csock = socket.socket(family, type, proto)
71 csock.setblocking(False)
73 wrap_error(csock.connect, (addr, port))
74 except (BlockingIOError, InterruptedError):
76 csock.setblocking(True)
77 ssock, _ = lsock.accept()
86 # Replacement for os.pipe() using handles instead of fds
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)))
95 openmode = _winapi.PIPE_ACCESS_DUPLEX
96 access = _winapi.GENERIC_READ | _winapi.GENERIC_WRITE
97 obsize, ibsize = bufsize, bufsize
99 openmode = _winapi.PIPE_ACCESS_INBOUND
100 access = _winapi.GENERIC_WRITE
101 obsize, ibsize = 0, bufsize
103 openmode |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE
106 openmode |= _winapi.FILE_FLAG_OVERLAPPED
109 flags_and_attribs = _winapi.FILE_FLAG_OVERLAPPED
111 flags_and_attribs = 0
115 h1 = _winapi.CreateNamedPipe(
116 address, openmode, _winapi.PIPE_WAIT,
117 1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL)
119 h2 = _winapi.CreateFile(
120 address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING,
121 flags_and_attribs, _winapi.NULL)
123 ov = _winapi.ConnectNamedPipe(h1, overlapped=True)
124 if hasattr(ov, 'GetOverlappedResult'):
125 # _winapi module of Python 3.3
126 ov.GetOverlappedResult(True)
129 wrap_error(ov.getresult, True)
133 _winapi.CloseHandle(h1)
135 _winapi.CloseHandle(h2)
139 # Wrapper for a pipe handle
142 class PipeHandle(object):
143 """Wrapper for an overlapped pipe handle which is vaguely file-object like.
145 The IOCP event loop can use these instead of socket objects.
147 def __init__(self, handle):
148 self._handle = handle
151 if self._handle is not None:
152 handle = 'handle=%r' % self._handle
155 return '<%s %s>' % (self.__class__.__name__, handle)
162 if self._handle is None:
163 raise ValueError("I/O operatioon on closed pipe")
166 def close(self, CloseHandle=_winapi.CloseHandle):
167 if self._handle is not None:
168 CloseHandle(self._handle)
172 if self._handle is not None:
174 warnings.warn("unclosed %r" % self, ResourceWarning)
180 def __exit__(self, t, v, tb):
184 # Replacement for subprocess.Popen using overlapped pipe handles
187 class Popen(subprocess.Popen):
188 """Replacement for subprocess.Popen using overlapped pipe handles.
190 The stdin, stdout, stderr are None or instances of PipeHandle.
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
198 stdin_rh, stdin_wh = pipe(overlapped=(False, True), duplex=True)
199 stdin_rfd = msvcrt.open_osfhandle(stdin_rh, os.O_RDONLY)
203 stdout_rh, stdout_wh = pipe(overlapped=(True, False))
204 stdout_wfd = msvcrt.open_osfhandle(stdout_wh, 0)
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
215 super(Popen, self).__init__(args,
221 for h in (stdin_wh, stdout_rh, stderr_rh):
223 _winapi.CloseHandle(h)
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)