diff --git a/pexpect/pty_spawn.py b/pexpect/pty_spawn.py index e0e2b54f..e84c26d2 100644 --- a/pexpect/pty_spawn.py +++ b/pexpect/pty_spawn.py @@ -430,12 +430,45 @@ def read_nonblocking(self, size=1, timeout=-1): available right away then one character will be returned immediately. It will not wait for 30 seconds for another 99 characters to come in. + On the other hand, if there are bytes available to read immediately, + all those bytes will be read (up to the buffer size). So, if the + buffer size is 1 megabyte and there is 1 megabyte of data available + to read, the buffer will be filled, regardless of timeout. + This is a wrapper around os.read(). It uses select.select() to implement the timeout. ''' if self.closed: raise ValueError('I/O operation on closed file.') + # If there is data available to read right now, read as much as + # we can. We do this to increase performance if there are a lot + # of bytes to be read. This also avoids calling isalive() too + # often. See also: + # * https://github.com/pexpect/pexpect/pull/304 + # * http://trac.sagemath.org/ticket/10295 + incoming = "" + while len(incoming) < size: + if self.use_poll: + r = poll_ignore_interrupts([self.child_fd], 0) + else: + r, w, e = select_ignore_interrupts([self.child_fd], [], [], 0) + if not r: + break + try: + incoming += super(spawn, self).read_nonblocking(size - len(incoming)) + except EOF: + # The process may have died, update the status. + self.isalive() + + # If we read anything, just return that. + if incoming: + return incoming + else: + raise + if incoming: + return incoming + if timeout == -1: timeout = self.timeout @@ -445,14 +478,8 @@ def read_nonblocking(self, size=1, timeout=-1): # For this case, I test isalive() before doing any reading. # If isalive() is false, then I pretend that this is the same as EOF. if not self.isalive(): - # timeout of 0 means "poll" - if self.use_poll: - r = poll_ignore_interrupts([self.child_fd], timeout) - else: - r, w, e = select_ignore_interrupts([self.child_fd], [], [], 0) - if not r: - self.flag_eof = True - raise EOF('End Of File (EOF). Braindead platform.') + self.flag_eof = True + raise EOF('End Of File (EOF). Braindead platform.') elif self.__irix_hack: # Irix takes a long time before it realizes a child was terminated. # FIXME So does this mean Irix systems are forced to always have @@ -464,12 +491,17 @@ def read_nonblocking(self, size=1, timeout=-1): if not r and not self.isalive(): self.flag_eof = True raise EOF('End Of File (EOF). Slow platform.') - if self.use_poll: - r = poll_ignore_interrupts([self.child_fd], timeout) - else: - r, w, e = select_ignore_interrupts( - [self.child_fd], [], [], timeout - ) + + # Wait with timeout until data is available to read. + # Since we already called select() with timeout=0, we don't + # do that again if timeout == 0. + if timeout != 0: + if self.use_poll: + r = poll_ignore_interrupts([self.child_fd], timeout) + else: + r, w, e = select_ignore_interrupts( + [self.child_fd], [], [], timeout + ) if not r: if not self.isalive(): @@ -481,10 +513,7 @@ def read_nonblocking(self, size=1, timeout=-1): else: raise TIMEOUT('Timeout exceeded.') - if self.child_fd in r: - return super(spawn, self).read_nonblocking(size) - - raise ExceptionPexpect('Reached an unexpected state.') # pragma: no cover + return super(spawn, self).read_nonblocking(size) def write(self, s): '''This is similar to send() except that there is no return value.