def maybeCallProcessEnded(self): if self.closedNotifies == 3 and self.lostProcess: win32file.CloseHandle(self.hProcess) win32file.CloseHandle(self.hThread) self.hProcess = None self.hThread = None BaseProcess.maybeCallProcessEnded(self)
def test_callProcessExitedMissing(self): """ L{BaseProcess._callProcessExited} emits a L{DeprecationWarning} if the object referred to by its C{proto} attribute has no C{processExited} method. """ class FakeProto: pass reason = object() process = BaseProcess(FakeProto()) self.addCleanup(setWarningMethod, getWarningMethod()) warnings = [] def collect(message, category, stacklevel): warnings.append((message, category, stacklevel)) setWarningMethod(collect) process._callProcessExited(reason) [(message, category, stacklevel)] = warnings self.assertEqual( message, "Since Twisted 8.2, IProcessProtocol.processExited is required. " "%s.%s must implement it." % ( FakeProto.__module__, FakeProto.__name__)) self.assertIdentical(category, DeprecationWarning) # The stacklevel doesn't really make sense for this kind of # deprecation. Requiring it to be 0 will at least avoid pointing to # any part of Twisted or a random part of the application's code, which # I think would be more misleading than having it point inside the # warning system itself. -exarkun self.assertEqual(stacklevel, 0)
def test_callProcessExitedMissing(self): """ L{BaseProcess._callProcessExited} emits a L{DeprecationWarning} if the object referred to by its C{proto} attribute has no C{processExited} method. """ class FakeProto: pass reason = object() process = BaseProcess(FakeProto()) self.addCleanup(setWarningMethod, getWarningMethod()) warnings = [] def collect(message, category, stacklevel): warnings.append((message, category, stacklevel)) setWarningMethod(collect) process._callProcessExited(reason) [(message, category, stacklevel)] = warnings self.assertEqual( message, "Since Twisted 8.2, IProcessProtocol.processExited is required. " "%s.%s must implement it." % (FakeProto.__module__, FakeProto.__name__)) self.assertIdentical(category, DeprecationWarning) # The stacklevel doesn't really make sense for this kind of # deprecation. Requiring it to be 0 will at least avoid pointing to # any part of Twisted or a random part of the application's code, which # I think would be more misleading than having it point inside the # warning system itself. -exarkun self.assertEqual(stacklevel, 0)
def test_callProcessExited(self): """ L{BaseProcess._callProcessExited} calls the C{processExited} method of its C{proto} attribute and passes it a L{Failure} wrapping the given exception. """ class FakeProto: reason = None def processExited(self, reason): self.reason = reason reason = RuntimeError("fake reason") process = BaseProcess(FakeProto()) process._callProcessExited(reason) process.proto.reason.trap(RuntimeError) self.assertIdentical(reason, process.proto.reason.value)
def __init__(self, reactor, protocol, command, args, environment, path): _pollingfile._PollingTimer.__init__(self, reactor) BaseProcess.__init__(self, protocol) # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create the pipes which will connect to the secondary process self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0) self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0) hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0) win32pipe.SetNamedPipeHandleState(self.hStdinW, win32pipe.PIPE_NOWAIT, None, None) # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = hStdoutW StartupInfo.hStdError = hStderrW StartupInfo.hStdInput = hStdinR StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Create new handles whose inheritance property is false currentPid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(currentPid, self.hStdoutR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdoutR) self.hStdoutR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStderrR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStderrR) self.hStderrR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStdinW, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdinW) self.hStdinW = tmp # Add the specified environment to the current environment - this is # necessary because certain operations are only supported on Windows # if certain environment variables are present. env = os.environ.copy() env.update(environment or {}) cmdline = quoteArguments(args) # TODO: error detection here. def doCreate(): self.hProcess, self.hThread, self.pid, dwTid = win32process.CreateProcess( command, cmdline, None, None, 1, 0, env, path, StartupInfo) try: doCreate() except pywintypes.error, pwte: if not _invalidWin32App(pwte): # This behavior isn't _really_ documented, but let's make it # consistent with the behavior that is documented. raise OSError(pwte) else: # look for a shebang line. Insert the original 'command' # (actually a script) into the new arguments list. sheb = _findShebang(command) if sheb is None: raise OSError( "%r is neither a Windows executable, " "nor a script with a shebang line" % command) else: args = list(args) args.insert(0, command) cmdline = quoteArguments(args) origcmd = command command = sheb try: # Let's try again. doCreate() except pywintypes.error, pwte2: # d'oh, failed again! if _invalidWin32App(pwte2): raise OSError( "%r has an invalid shebang line: " "%r is not a valid executable" % ( origcmd, sheb)) raise OSError(pwte2)
def __init__(self, reactor, protocol, command, args, environment, path): _pollingfile._PollingTimer.__init__(self, reactor) BaseProcess.__init__(self, protocol) # security attributes for pipes sAttrs = win32security.SECURITY_ATTRIBUTES() sAttrs.bInheritHandle = 1 # create the pipes which will connect to the secondary process self.hStdoutR, hStdoutW = win32pipe.CreatePipe(sAttrs, 0) self.hStderrR, hStderrW = win32pipe.CreatePipe(sAttrs, 0) hStdinR, self.hStdinW = win32pipe.CreatePipe(sAttrs, 0) win32pipe.SetNamedPipeHandleState(self.hStdinW, win32pipe.PIPE_NOWAIT, None, None) # set the info structure for the new process. StartupInfo = win32process.STARTUPINFO() StartupInfo.hStdOutput = hStdoutW StartupInfo.hStdError = hStderrW StartupInfo.hStdInput = hStdinR StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES # Create new handles whose inheritance property is false currentPid = win32api.GetCurrentProcess() tmp = win32api.DuplicateHandle(currentPid, self.hStdoutR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdoutR) self.hStdoutR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStderrR, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStderrR) self.hStderrR = tmp tmp = win32api.DuplicateHandle(currentPid, self.hStdinW, currentPid, 0, 0, win32con.DUPLICATE_SAME_ACCESS) win32file.CloseHandle(self.hStdinW) self.hStdinW = tmp # Add the specified environment to the current environment - this is # necessary because certain operations are only supported on Windows # if certain environment variables are present. env = os.environ.copy() env.update(environment or {}) cmdline = quoteArguments(args) # TODO: error detection here. def doCreate(): self.hProcess, self.hThread, self.pid, dwTid = win32process.CreateProcess( command, cmdline, None, None, 1, 0, env, path, StartupInfo ) try: doCreate() except pywintypes.error, pwte: if not _invalidWin32App(pwte): # This behavior isn't _really_ documented, but let's make it # consistent with the behavior that is documented. raise OSError(pwte) else: # look for a shebang line. Insert the original 'command' # (actually a script) into the new arguments list. sheb = _findShebang(command) if sheb is None: raise OSError("%r is neither a Windows executable, " "nor a script with a shebang line" % command) else: args = list(args) args.insert(0, command) cmdline = quoteArguments(args) origcmd = command command = sheb try: # Let's try again. doCreate() except pywintypes.error, pwte2: # d'oh, failed again! if _invalidWin32App(pwte2): raise OSError( "%r has an invalid shebang line: " "%r is not a valid executable" % (origcmd, sheb) ) raise OSError(pwte2)