📄 process.py
字号:
def read(self, nBytes=-1): # nBytes <= 0 means "read everything" # Note that we are changing the "read everything" cue to # include 0, because actually doing # win32file.ReadFile(<handle>, 0) results in every subsequent # read returning 0, i.e. it shuts down the pipe. if self._descriptor is not None: if nBytes <= 0: text, self._lineBuf = self._lineBuf, "" while 1: t = os.read(self._descriptor, 4092) if not t: break else: text += t else: if len(self._lineBuf) >= nBytes: text, self._lineBuf =\ self._lineBuf[:nBytes], self._lineBuf[nBytes:] else: nBytesToGo = nBytes - len(self._lineBuf) text = self._lineBuf + os.read(self._descriptor, nBytesToGo) self._lineBuf = "" return text elif self._handle is not None: if nBytes <= 0: text, self._lineBuf = self._lineBuf, "" while 1: t = self._win32Read(4092) if not t: break else: text += t else: if len(self._lineBuf) >= nBytes: text, self._lineBuf =\ self._lineBuf[:nBytes], self._lineBuf[nBytes:] else: nBytesToGo = nBytes - len(self._lineBuf) text, self._lineBuf =\ self._lineBuf + self._win32Read(nBytesToGo), "" return text elif self._file is not None: return self._file.read(nBytes) else: raise "FileHandle.read: no handle to read with" def readline(self): if self._descriptor is not None or self._handle is not None: while 1: #XXX This is not portable to the Mac. idx = self._lineBuf.find('\n') if idx != -1: line, self._lineBuf =\ self._lineBuf[:idx+1], self._lineBuf[idx+1:] break else: lengthBefore = len(self._lineBuf) t = self.read(4092) if len(t) <= lengthBefore: # no new data was read line, self._lineBuf = self._lineBuf, "" break else: self._lineBuf += t return line elif self._file is not None: return self._file.readline() else: raise "FileHandle.readline: no handle to read with" def readlines(self): if self._descriptor is not None or self._handle is not None: lines = [] while 1: line = self.readline() if line: lines.append(line) else: break return lines elif self._file is not None: return self._file.readlines() else: raise "FileHandle.readline: no handle to read with" def write(self, text): if self._descriptor is not None: os.write(self._descriptor, text) elif self._handle is not None: try: errCode, nBytesWritten = win32file.WriteFile(self._handle, text) except pywintypes.error, ex: # Ingore errors like "The pipe is being closed.", for # now. log.info("[%s] _FileWrapper.write: error writing to pipe, "\ "ignored", id(self)) return assert errCode == 0,\ "Why is 'errCode' from WriteFile non-zero? %r" % errCode if not nBytesWritten: # No bytes written signifies that the pipe has been # closed on the child's end. log.info("[%s] _FileWrapper.write: observed close of pipe", id(self)) return else: log.info("[%s] _FileWrapper.write: wrote %d bytes to pipe: %r", id(self), len(text), text) elif self._file is not None: self._file.write(text) else: raise "FileHandle.write: nothing to write with" def close(self): """Close all associated file objects and handles.""" log.debug("[%s] _FileWrapper.close()", id(self)) if not self._closed: self._closed = 1 if self._file is not None: log.debug("[%s] _FileWrapper.close: close file", id(self)) self._file.close() log.debug("[%s] _FileWrapper.close: done file close", id(self)) if self._descriptor is not None: try: os.close(self._descriptor) except OSError, ex: if ex.errno == 9: # Ignore: OSError: [Errno 9] Bad file descriptor # XXX *Should* we be ignoring this? It appears very # *in*frequently in test_wait.py. log.debug("[%s] _FileWrapper.close: closing "\ "descriptor raised OSError", id(self)) else: raise if self._handle is not None: log.debug("[%s] _FileWrapper.close: close handle", id(self)) try: win32api.CloseHandle(self._handle) except win32api.error: log.debug("[%s] _FileWrapper.close: closing handle raised", id(self)) pass log.debug("[%s] _FileWrapper.close: done closing handle", id(self)) def __repr__(self): return "<_FileWrapper: file:%r fd:%r os_handle:%r>"\ % (self._file, self._descriptor, self._handle)class _CountingCloser: """Call .close() on the given object after own .close() is called the precribed number of times. """ def __init__(self, objectsToClose, count): """ "objectsToClose" is a list of object on which to call .close(). "count" is the number of times this object's .close() method must be called before .close() is called on the given objects. """ self.objectsToClose = objectsToClose self.count = count if self.count <= 0: raise ProcessError("illegal 'count' value: %s" % self.count) def close(self): self.count -= 1 log.debug("[%d] _CountingCloser.close(): count=%d", id(self), self.count) if self.count == 0: for objectToClose in self.objectsToClose: objectToClose.close()#---- public interfaceclass Process: """Create a process. One can optionally specify the starting working directory, the process environment, and std handles to have the child process inherit (all defaults are the parent's current settings). 'wait' and 'kill' method allow for control of the child's termination. """ # TODO: # - Rename this or merge it with ProcessOpen somehow. # if sys.platform.startswith("win"): # .wait() argument constants INFINITE = win32event.INFINITE # .wait() return error codes WAIT_FAILED = win32event.WAIT_FAILED WAIT_TIMEOUT = win32event.WAIT_TIMEOUT # creation "flags" constants # XXX Should drop these and just document usage of # win32process.CREATE_* constants on windows. CREATE_NEW_CONSOLE = win32process.CREATE_NEW_CONSOLE else: # .wait() argument constants INFINITE = 0 # .wait() return error codes WAIT_TIMEOUT = 258 WAIT_FAILED = -1 # creation "flags" constants CREATE_NEW_CONSOLE = 0x10 # same as win32process.CREATE_NEW_CONSOLE def __init__(self, cmd, cwd=None, env=None, flags=0): """Create a child process. "cmd" is a command string or argument vector to spawn. "cwd" is a working directory in which to start the child process. "env" is an environment dictionary for the child. "flags" are system-specific process creation flags. On Windows this can be a bitwise-OR of any of the win32process.CREATE_* constants (Note: win32process.CREATE_NEW_PROCESS_GROUP is always OR'd in). On Unix, this is currently ignored. """ log.info("Process.__init__(cmd=%r, cwd=%r, env=%r, flags=%r)", cmd, cwd, env, flags) self._cmd = cmd if not self._cmd: raise ProcessError("You must specify a command.") self._cwd = cwd self._env = env self._flags = flags if sys.platform.startswith("win"): self._flags |= win32process.CREATE_NEW_PROCESS_GROUP if sys.platform.startswith("win"): self._startOnWindows() else: self.__retvalCache = None self._startOnUnix() def _runChildOnUnix(self): #XXX Errors running the child do *not* get communicated back. #XXX Perhaps we should *always* prefix with '/bin/sh -c'? There is a # disparity btwn how this works on Linux and Windows. if isinstance(self._cmd, types.StringTypes): # This is easier than trying to reproduce shell interpretation to # separate the arguments. cmd = ['/bin/sh', '-c', self._cmd] else: cmd = self._cmd # Close all file descriptors (except std*) inherited from the parent. MAXFD = 256 # Max number of file descriptors (os.getdtablesize()???) for i in range(3, MAXFD): try: os.close(i) except OSError: pass try: if self._env: os.execvpe(cmd[0], cmd, self._env) else: os.execvp(cmd[0], cmd) finally: os._exit(1) # Should never get here. def _forkAndExecChildOnUnix(self): """Fork and start the child process. Sets self._pid as a side effect. """ pid = os.fork() if pid == 0: # child self._runChildOnUnix() # parent self._pid = pid def _startOnUnix(self): if self._cwd: oldDir = os.getcwd() try: os.chdir(self._cwd) except OSError, ex: raise ProcessError(msg=str(ex), errno=ex.errno) self._forkAndExecChildOnUnix() # parent if self._cwd: os.chdir(oldDir) def _startOnWindows(self): if type(self._cmd) in (types.ListType, types.TupleType): # And arg vector was passed in. cmd = _joinArgv(self._cmd) else: cmd = self._cmd si = win32process.STARTUPINFO() si.dwFlags = win32process.STARTF_USESHOWWINDOW si.wShowWindow = SW_SHOWDEFAULT if not (self._flags & self.CREATE_NEW_CONSOLE): #XXX This is hacky. # We cannot then use _fixupCommand because this will cause a # shell to be openned as the command is launched. Therefore need # to ensure be have the full path to the executable to launch. try: cmd = _whichFirstArg(cmd, self._env) except ProcessError: # Could not find the command, perhaps it is an internal # shell command -- fallback to _fixupCommand cmd = _fixupCommand(cmd, self._env) else: cmd = _fixupCommand(cmd, self._env) log.debug("cmd = %r", cmd) # Start the child process.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -