read stdout/stderr without blocking

Adriaan Renting renting at astron.nl
Mon Sep 12 07:57:39 EDT 2005


I was not aware you were using Windows, you might need to find something similar to select and pty that works in Windows or maybe go though Cygwin, I don't know. I'm on Linux, the only help I can offer is showing you my working code, that's a mix of Pexpect, subProcess and Parseltongue.
I'm not sure if this is 100% correct, it just happens to work and might help you in solving a similar problem:

---- in spawn()
        (self._errorpipe_end, self._errorpipe_front) = os.pipe() ## need to handle stderr separate from stdout
        try:
            (self._pid, self._child_fd) = pty.fork()
        except OSError, e:
            raise Exception ('fork failed')
        if self._pid == 0: ## the new client
            try:
                os.dup2(self._errorpipe_front, 2) ## we hardcoded assume stderr of the pty has fd 2
                os.close(self._errorpipe_end)
                os.close(self._errorpipe_front) ## close what we don't need
                os.execvp(self.task, self.inputs)
            except:
                sys.stderr.write('Process could not be started: ' + self.task)
                os._exit(1)
        else: ## the parent
            os.close(self._errorpipe_front) ## close what we don't need
            fcntl.fcntl(self._child_fd, fcntl.F_SETFL, os.O_NONBLOCK)

---- in handle_messages()
        tocheck=[]
        if not self._fd_eof:
            tocheck.append(self._child_fd)
        if not self._pipe_eof:
            tocheck.append(self._errorpipe_end)
        ready = select.select(tocheck, [], [], 0.25) ##continues after 0.25s
        for file in ready[0]:
            try:
                text = os.read(file, 1024)
            except: ## probalby Input/Output error because the child died
                text = ''
            if text:
                for x in self._expect:
                    if x[0] in text: ## we need to do something if we see this text
                        returntext = x[1](text)
                        if returntext:
                            os.write(file, returntext)
                self.handle_text(text)
            else:
                if file == self._child_fd:
                    self._fd_eof   = 1
                elif file == self._errorpipe_end:
                    self._pipe_eof = 1
            return 1
        if self._fd_eof or self._pipe_eof: # should be an and not an or, but python 2.3.5 doesn't like it
            return 0
        if len(ready[0]) == 0: ## no data in 0.25 second timeout
            return 1
        return 0
 
---- in finish()
        (pid, status) = os.waitpid(self._pid, os.WNOHANG) ## clean up the zombie
        assert(pid == self._pid)
        if os.WIFEXITED(status) or os.WIFSIGNALED(status):
            self._pid       = 0
            self.exitstatus = status
        assert(self.finished())
        del self._pid
        os.close(self._child_fd)
        os.close(self._errorpipe_end)


|>>>Jacek Pop*awski <jpopl at interia.pl> 09/12/05 1:14 pm >>> 
|Adriaan Renting wrote: 
|>Check out the select module, for an example on how to use it: 
|>pexpect.sourceforge.net 
| 
|Two problems: 
|- it won't work on Windows (Cygwin) 
|- how much data should I read after select? 1 character? Can it block if 
|I read 2 characters? 
|-- 
|http://mail.python.org/mailman/listinfo/python-list 




More information about the Python-list mailing list