Skip to content

Commit

Permalink
Merge 7e3c5ec into c694853
Browse files Browse the repository at this point in the history
  • Loading branch information
jdemeyer committed Jun 29, 2018
2 parents c694853 + 7e3c5ec commit 7926c89
Showing 1 changed file with 47 additions and 18 deletions.
65 changes: 47 additions & 18 deletions pexpect/pty_spawn.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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():
Expand All @@ -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.
Expand Down

0 comments on commit 7926c89

Please sign in to comment.