| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  | """Various Windows specific bits and pieces.""" | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if sys.platform != 'win32':  # pragma: no cover | 
					
						
							|  |  |  |     raise ImportError('win32 only') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-15 00:04:21 +01:00
										 |  |  | import _winapi | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | import itertools | 
					
						
							|  |  |  | import msvcrt | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import subprocess | 
					
						
							|  |  |  | import tempfile | 
					
						
							| 
									
										
										
										
											2015-01-29 17:50:58 +01:00
										 |  |  | import warnings | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  | __all__ = 'pipe', 'Popen', 'PIPE', 'PipeHandle' | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 14:20:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | # Constants/globals | 
					
						
							| 
									
										
										
										
											2013-11-01 14:20:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | BUFSIZE = 8192 | 
					
						
							|  |  |  | PIPE = subprocess.PIPE | 
					
						
							| 
									
										
										
										
											2013-10-30 14:52:03 -07:00
										 |  |  | STDOUT = subprocess.STDOUT | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | _mmap_counter = itertools.count() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 14:20:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | # Replacement for os.pipe() using handles instead of fds | 
					
						
							| 
									
										
										
										
											2013-11-01 14:20:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | def pipe(*, duplex=False, overlapped=(True, True), bufsize=BUFSIZE): | 
					
						
							|  |  |  |     """Like os.pipe() but with overlapped support and using handles not fds.""" | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |     address = tempfile.mktemp( | 
					
						
							|  |  |  |         prefix=r'\\.\pipe\python-pipe-{:d}-{:d}-'.format( | 
					
						
							|  |  |  |             os.getpid(), next(_mmap_counter))) | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if duplex: | 
					
						
							|  |  |  |         openmode = _winapi.PIPE_ACCESS_DUPLEX | 
					
						
							|  |  |  |         access = _winapi.GENERIC_READ | _winapi.GENERIC_WRITE | 
					
						
							|  |  |  |         obsize, ibsize = bufsize, bufsize | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         openmode = _winapi.PIPE_ACCESS_INBOUND | 
					
						
							|  |  |  |         access = _winapi.GENERIC_WRITE | 
					
						
							|  |  |  |         obsize, ibsize = 0, bufsize | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     openmode |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if overlapped[0]: | 
					
						
							|  |  |  |         openmode |= _winapi.FILE_FLAG_OVERLAPPED | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if overlapped[1]: | 
					
						
							|  |  |  |         flags_and_attribs = _winapi.FILE_FLAG_OVERLAPPED | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         flags_and_attribs = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     h1 = h2 = None | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         h1 = _winapi.CreateNamedPipe( | 
					
						
							|  |  |  |             address, openmode, _winapi.PIPE_WAIT, | 
					
						
							|  |  |  |             1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         h2 = _winapi.CreateFile( | 
					
						
							|  |  |  |             address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING, | 
					
						
							|  |  |  |             flags_and_attribs, _winapi.NULL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ov = _winapi.ConnectNamedPipe(h1, overlapped=True) | 
					
						
							|  |  |  |         ov.GetOverlappedResult(True) | 
					
						
							|  |  |  |         return h1, h2 | 
					
						
							|  |  |  |     except: | 
					
						
							|  |  |  |         if h1 is not None: | 
					
						
							|  |  |  |             _winapi.CloseHandle(h1) | 
					
						
							|  |  |  |         if h2 is not None: | 
					
						
							|  |  |  |             _winapi.CloseHandle(h2) | 
					
						
							|  |  |  |         raise | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 14:20:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | # Wrapper for a pipe handle | 
					
						
							| 
									
										
										
										
											2013-11-01 14:20:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class PipeHandle: | 
					
						
							|  |  |  |     """Wrapper for an overlapped pipe handle which is vaguely file-object like.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The IOCP event loop can use these instead of socket objects. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self, handle): | 
					
						
							|  |  |  |         self._handle = handle | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-18 23:47:27 +01:00
										 |  |  |     def __repr__(self): | 
					
						
							| 
									
										
										
										
											2015-01-15 00:04:21 +01:00
										 |  |  |         if self._handle is not None: | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |             handle = f'handle={self._handle!r}' | 
					
						
							| 
									
										
										
										
											2014-12-18 23:47:27 +01:00
										 |  |  |         else: | 
					
						
							|  |  |  |             handle = 'closed' | 
					
						
							| 
									
										
										
										
											2017-12-10 18:36:12 -05:00
										 |  |  |         return f'<{self.__class__.__name__} {handle}>' | 
					
						
							| 
									
										
										
										
											2014-12-18 23:47:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  |     @property | 
					
						
							|  |  |  |     def handle(self): | 
					
						
							|  |  |  |         return self._handle | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def fileno(self): | 
					
						
							| 
									
										
										
										
											2015-01-26 15:03:44 +01:00
										 |  |  |         if self._handle is None: | 
					
						
							| 
									
										
										
										
											2017-03-26 23:59:08 +03:00
										 |  |  |             raise ValueError("I/O operation on closed pipe") | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  |         return self._handle | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def close(self, *, CloseHandle=_winapi.CloseHandle): | 
					
						
							| 
									
										
										
										
											2015-01-15 00:04:21 +01:00
										 |  |  |         if self._handle is not None: | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  |             CloseHandle(self._handle) | 
					
						
							| 
									
										
										
										
											2015-01-15 00:04:21 +01:00
										 |  |  |             self._handle = None | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-10 11:24:40 +01:00
										 |  |  |     def __del__(self, _warn=warnings.warn): | 
					
						
							| 
									
										
										
										
											2015-01-29 17:50:58 +01:00
										 |  |  |         if self._handle is not None: | 
					
						
							| 
									
										
										
										
											2019-01-10 11:24:40 +01:00
										 |  |  |             _warn(f"unclosed {self!r}", ResourceWarning, source=self) | 
					
						
							| 
									
										
										
										
											2015-01-29 17:50:58 +01:00
										 |  |  |             self.close() | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __enter__(self): | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __exit__(self, t, v, tb): | 
					
						
							|  |  |  |         self.close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 14:20:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | # Replacement for subprocess.Popen using overlapped pipe handles | 
					
						
							| 
									
										
										
										
											2013-11-01 14:20:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Popen(subprocess.Popen): | 
					
						
							|  |  |  |     """Replacement for subprocess.Popen using overlapped pipe handles.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The stdin, stdout, stderr are None or instances of PipeHandle. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self, args, stdin=None, stdout=None, stderr=None, **kwds): | 
					
						
							| 
									
										
										
										
											2013-10-30 14:52:03 -07:00
										 |  |  |         assert not kwds.get('universal_newlines') | 
					
						
							|  |  |  |         assert kwds.get('bufsize', 0) == 0 | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  |         stdin_rfd = stdout_wfd = stderr_wfd = None | 
					
						
							|  |  |  |         stdin_wh = stdout_rh = stderr_rh = None | 
					
						
							|  |  |  |         if stdin == PIPE: | 
					
						
							| 
									
										
										
										
											2013-10-30 14:52:03 -07:00
										 |  |  |             stdin_rh, stdin_wh = pipe(overlapped=(False, True), duplex=True) | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  |             stdin_rfd = msvcrt.open_osfhandle(stdin_rh, os.O_RDONLY) | 
					
						
							| 
									
										
										
										
											2013-10-30 14:52:03 -07:00
										 |  |  |         else: | 
					
						
							|  |  |  |             stdin_rfd = stdin | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  |         if stdout == PIPE: | 
					
						
							|  |  |  |             stdout_rh, stdout_wh = pipe(overlapped=(True, False)) | 
					
						
							|  |  |  |             stdout_wfd = msvcrt.open_osfhandle(stdout_wh, 0) | 
					
						
							| 
									
										
										
										
											2013-10-30 14:52:03 -07:00
										 |  |  |         else: | 
					
						
							|  |  |  |             stdout_wfd = stdout | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  |         if stderr == PIPE: | 
					
						
							|  |  |  |             stderr_rh, stderr_wh = pipe(overlapped=(True, False)) | 
					
						
							|  |  |  |             stderr_wfd = msvcrt.open_osfhandle(stderr_wh, 0) | 
					
						
							| 
									
										
										
										
											2013-10-30 14:52:03 -07:00
										 |  |  |         elif stderr == STDOUT: | 
					
						
							|  |  |  |             stderr_wfd = stdout_wfd | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             stderr_wfd = stderr | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2013-10-30 14:52:03 -07:00
										 |  |  |             super().__init__(args, stdin=stdin_rfd, stdout=stdout_wfd, | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  |                              stderr=stderr_wfd, **kwds) | 
					
						
							|  |  |  |         except: | 
					
						
							|  |  |  |             for h in (stdin_wh, stdout_rh, stderr_rh): | 
					
						
							| 
									
										
										
										
											2013-10-30 14:52:03 -07:00
										 |  |  |                 if h is not None: | 
					
						
							|  |  |  |                     _winapi.CloseHandle(h) | 
					
						
							| 
									
										
										
										
											2013-10-17 13:40:50 -07:00
										 |  |  |             raise | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             if stdin_wh is not None: | 
					
						
							|  |  |  |                 self.stdin = PipeHandle(stdin_wh) | 
					
						
							|  |  |  |             if stdout_rh is not None: | 
					
						
							|  |  |  |                 self.stdout = PipeHandle(stdout_rh) | 
					
						
							|  |  |  |             if stderr_rh is not None: | 
					
						
							|  |  |  |                 self.stderr = PipeHandle(stderr_rh) | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             if stdin == PIPE: | 
					
						
							|  |  |  |                 os.close(stdin_rfd) | 
					
						
							|  |  |  |             if stdout == PIPE: | 
					
						
							|  |  |  |                 os.close(stdout_wfd) | 
					
						
							|  |  |  |             if stderr == PIPE: | 
					
						
							|  |  |  |                 os.close(stderr_wfd) |