*** subprocessold.py Sat Apr 2 17:25:00 2005 --- subprocess.py Sun Apr 3 16:37:36 2005 *************** *** 95,101 **** will occur; the child's file handles will be inherited from the parent. Additionally, stderr can be STDOUT, which indicates that the stderr data from the applications should be captured into the same ! file handle as for stdout. If preexec_fn is set to a callable object, this object will be called in the child process just before the child is executed. --- 95,103 ---- will occur; the child's file handles will be inherited from the parent. Additionally, stderr can be STDOUT, which indicates that the stderr data from the applications should be captured into the same ! file handle as for stdout. The stdout and stderr arguments support ! file-like objects, but when these don't provide a fileno function, ! they will be only updated when calling poll or wait. If preexec_fn is set to a callable object, this object will be called in the child process just before the child is executed. *************** *** 396,408 **** from win32api import GetCurrentProcess, DuplicateHandle, \ GetModuleFileName, GetVersion from win32con import DUPLICATE_SAME_ACCESS, SW_HIDE ! from win32pipe import CreatePipe from win32process import CreateProcess, STARTUPINFO, \ GetExitCodeProcess, STARTF_USESTDHANDLES, \ STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE ! from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0 else: from _subprocess import * class STARTUPINFO: dwFlags = 0 hStdInput = None --- 398,414 ---- from win32api import GetCurrentProcess, DuplicateHandle, \ GetModuleFileName, GetVersion from win32con import DUPLICATE_SAME_ACCESS, SW_HIDE ! from win32pipe import CreatePipe, PeekNamedPipe from win32process import CreateProcess, STARTUPINFO, \ GetExitCodeProcess, STARTF_USESTDHANDLES, \ STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE ! from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0, \ ! WaitForMultipleObjects else: from _subprocess import * + from win32event import WaitForMultipleObjects + from win32pipe import PeekNamedPipe + from win32file import ReadFile class STARTUPINFO: dwFlags = 0 hStdInput = None *************** *** 573,578 **** --- 579,592 ---- self.returncode = None self.universal_newlines = universal_newlines + # File-like objects without fileno + self._stdoutfileobj = None + self._stderrfileobj = None + + # Read side of pipes used to support file-like objects without fileno + self._stdoutread = None + self._stderrread = None + # Input and output objects. The general principle is like # this: # *************** *** 686,694 **** c2pread = msvcrt.open_osfhandle(c2pread, 0) elif isinstance(stdout, int): c2pwrite = msvcrt.get_osfhandle(stdout) ! else: # Assuming file-like object c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) c2pwrite = self._make_inheritable(c2pwrite) if stderr is None: --- 700,715 ---- c2pread = msvcrt.open_osfhandle(c2pread, 0) elif isinstance(stdout, int): c2pwrite = msvcrt.get_osfhandle(stdout) ! elif hasattr(stdout, 'fileno'): # Assuming file-like object c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) + else: + # Assuming file-like object without fileno + self._stdoutfileobj = stdout + self._stdoutread, stdoutwrite = CreatePipe(None, 0) + stdoutwrite = stdoutwrite.Detach() + c2pwrite = msvcrt.open_osfhandle(stdoutwrite, 0) + c2pwrite = msvcrt.get_osfhandle(c2pwrite) c2pwrite = self._make_inheritable(c2pwrite) if stderr is None: *************** *** 702,710 **** errwrite = c2pwrite elif isinstance(stderr, int): errwrite = msvcrt.get_osfhandle(stderr) ! else: # Assuming file-like object errwrite = msvcrt.get_osfhandle(stderr.fileno()) errwrite = self._make_inheritable(errwrite) return (p2cread, p2cwrite, --- 723,738 ---- errwrite = c2pwrite elif isinstance(stderr, int): errwrite = msvcrt.get_osfhandle(stderr) ! elif hasattr(stdout, 'fileno'): # Assuming file-like object errwrite = msvcrt.get_osfhandle(stderr.fileno()) + else: + # Assuming file-like object without fileno + self._stderrfileobj = stdout + self._stderrread, stderrwrite = CreatePipe(None, 0) + stderrwrite = stderrwrite.Detach() + errwrite = msvcrt.open_osfhandle(stderrwrite, 0) + errwrite = msvcrt.get_osfhandle(errwrite) errwrite = self._make_inheritable(errwrite) return (p2cread, p2cwrite, *************** *** 814,819 **** --- 842,864 ---- if errwrite is not None: errwrite.Close() + def _update_file_objects(self): + """Update file-like objects without fileno for stdout and + stderr.""" + if self._stdoutfileobj is not None: + buffer, nbBytes, bytesAvail = PeekNamedPipe( + self._stdoutread, 0) + if nbBytes: + bytesRead, data = ReadFile( + self._stdoutread, nbBytes) + self._stdoutfileobj.write(data) + if self._stderrfileobj is not None: + buffer, nbBytes, bytesAvail = PeekNamedPipe( + self._stderrread, 0) + if nbBytes: + bytesRead, data = ReadFile( + self._stderrread, nbBytes) + self._stderrfileobj.write(data) def poll(self): """Check if child process has terminated. Returns returncode *************** *** 822,837 **** if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0: self.returncode = GetExitCodeProcess(self._handle) _active.remove(self) return self.returncode - def wait(self): """Wait for child process to terminate. Returns returncode attribute.""" if self.returncode is None: ! obj = WaitForSingleObject(self._handle, INFINITE) ! self.returncode = GetExitCodeProcess(self._handle) ! _active.remove(self) return self.returncode --- 867,898 ---- if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0: self.returncode = GetExitCodeProcess(self._handle) _active.remove(self) + self._update_file_objects() return self.returncode def wait(self): """Wait for child process to terminate. Returns returncode attribute.""" if self.returncode is None: ! if self._stdoutfileobj or self._stderrfileobj: ! obj = None ! handles = [self._handle] ! if self._stdoutfileobj: ! handles.append(self._stdoutread) ! if self._stderrfileobj: ! handles.append(self._stderrread) ! while obj != WAIT_OBJECT_0: ! obj = WaitForMultipleObjects(handles, False, INFINITE) ! if obj == WAIT_OBJECT_0: ! self.returncode = GetExitCodeProcess(self._handle) ! _active.remove(self) ! else: ! self._update_file_objects() ! else: ! obj = WaitForSingleObject(self._handle, INFINITE) ! self.returncode = GetExitCodeProcess(self._handle) ! _active.remove(self) ! self._update_file_objects() return self.returncode