summaryrefslogtreecommitdiff
path: root/pexpect
diff options
context:
space:
mode:
authorDavid Cullen <david.cullen@technicolor.com>2016-06-28 14:49:43 -0400
committerDavid Cullen <david.cullen@technicolor.com>2016-06-28 14:49:43 -0400
commit7c03f4746c06cdfa169b514f38f856dc4caa263f (patch)
treee524a921ecb320d29c27172f045f944c628cf00e /pexpect
parent3ed8d66ffb12863bc4a55a4b5dab7fca7ce9a9cc (diff)
downloadpexpect-git-7c03f4746c06cdfa169b514f38f856dc4caa263f.tar.gz
Restore POSIX support to fdpexpect.
Diffstat (limited to 'pexpect')
-rw-r--r--pexpect/fdpexpect.py19
-rw-r--r--pexpect/pty_spawn.py38
-rw-r--r--pexpect/utils.py32
3 files changed, 55 insertions, 34 deletions
diff --git a/pexpect/fdpexpect.py b/pexpect/fdpexpect.py
index dd1b492..25b5c8d 100644
--- a/pexpect/fdpexpect.py
+++ b/pexpect/fdpexpect.py
@@ -22,7 +22,8 @@ PEXPECT LICENSE
'''
from .spawnbase import SpawnBase
-from .exceptions import ExceptionPexpect
+from .exceptions import ExceptionPexpect, TIMEOUT
+from .utils import select_ignore_interrupts
import os
__all__ = ['fdspawn']
@@ -112,3 +113,19 @@ class fdspawn(SpawnBase):
"Call self.write() for each item in sequence"
for s in sequence:
self.write(s)
+
+ def read_nonblocking(self, size=1, timeout=-1):
+ '''The read_nonblocking method of fdspawn assumes that the file
+ will never block. This is not the case for all file like objects
+ that support fileno (e.g. POSIX sockets and serial ports). So we
+ use select to implement the timeout on POSIX.'''
+ if os.name == 'posix':
+ if timeout == -1:
+ timeout = self.timeout
+ rlist = [self.child_fd]
+ wlist = []
+ xlist = []
+ rlist, wlist, xlist = select_ignore_interrupts(rlist, wlist, xlist, timeout)
+ if self.child_fd not in rlist:
+ raise TIMEOUT('Timeout exceeded.')
+ return super(fdspawn, self).read_nonblocking(size)
diff --git a/pexpect/pty_spawn.py b/pexpect/pty_spawn.py
index 3518cc1..46b03ba 100644
--- a/pexpect/pty_spawn.py
+++ b/pexpect/pty_spawn.py
@@ -1,7 +1,6 @@
import os
import sys
import time
-import select
import pty
import tty
import errno
@@ -13,7 +12,7 @@ from ptyprocess.ptyprocess import use_native_pty_fork
from .exceptions import ExceptionPexpect, EOF, TIMEOUT
from .spawnbase import SpawnBase
-from .utils import which, split_command_line
+from .utils import which, split_command_line, select_ignore_interrupts
@contextmanager
def _wrap_ptyprocess_err():
@@ -440,7 +439,7 @@ class spawn(SpawnBase):
# If isalive() is false, then I pretend that this is the same as EOF.
if not self.isalive():
# timeout of 0 means "poll"
- r, w, e = self.__select([self.child_fd], [], [], 0)
+ 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.')
@@ -448,12 +447,12 @@ class spawn(SpawnBase):
# Irix takes a long time before it realizes a child was terminated.
# FIXME So does this mean Irix systems are forced to always have
# FIXME a 2 second delay when calling read_nonblocking? That sucks.
- r, w, e = self.__select([self.child_fd], [], [], 2)
+ r, w, e = select_ignore_interrupts([self.child_fd], [], [], 2)
if not r and not self.isalive():
self.flag_eof = True
raise EOF('End Of File (EOF). Slow platform.')
- r, w, e = self.__select([self.child_fd], [], [], timeout)
+ r, w, e = select_ignore_interrupts([self.child_fd], [], [], timeout)
if not r:
if not self.isalive():
@@ -771,7 +770,7 @@ class spawn(SpawnBase):
'''
while self.isalive():
- r, w, e = self.__select([self.child_fd, self.STDIN_FILENO], [], [])
+ r, w, e = select_ignore_interrupts([self.child_fd, self.STDIN_FILENO], [], [])
if self.child_fd in r:
try:
data = self.__interact_read(self.child_fd)
@@ -803,33 +802,6 @@ class spawn(SpawnBase):
self._log(data, 'send')
self.__interact_writen(self.child_fd, data)
- def __select(self, iwtd, owtd, ewtd, timeout=None):
-
- '''This is a wrapper around select.select() that ignores signals. If
- select.select raises a select.error exception and errno is an EINTR
- error then it is ignored. Mainly this is used to ignore sigwinch
- (terminal resize). '''
-
- # if select() is interrupted by a signal (errno==EINTR) then
- # we loop back and enter the select() again.
- if timeout is not None:
- end_time = time.time() + timeout
- while True:
- try:
- return select.select(iwtd, owtd, ewtd, timeout)
- except select.error:
- err = sys.exc_info()[1]
- if err.args[0] == errno.EINTR:
- # if we loop back we have to subtract the
- # amount of time we already waited.
- if timeout is not None:
- timeout = end_time - time.time()
- if timeout < 0:
- return([], [], [])
- else:
- # something else caused the select.error, so
- # this actually is an exception.
- raise
def spawnu(*args, **kwargs):
"""Deprecated: pass encoding to spawn() instead."""
diff --git a/pexpect/utils.py b/pexpect/utils.py
index 737f0ed..a6e5aed 100644
--- a/pexpect/utils.py
+++ b/pexpect/utils.py
@@ -1,6 +1,9 @@
import os
import sys
import stat
+import select
+import time
+import errno
def is_executable_file(path):
@@ -110,3 +113,32 @@ def split_command_line(command_line):
if arg != '':
arg_list.append(arg)
return arg_list
+
+
+def select_ignore_interrupts(iwtd, owtd, ewtd, timeout=None):
+
+ '''This is a wrapper around select.select() that ignores signals. If
+ select.select raises a select.error exception and errno is an EINTR
+ error then it is ignored. Mainly this is used to ignore sigwinch
+ (terminal resize). '''
+
+ # if select() is interrupted by a signal (errno==EINTR) then
+ # we loop back and enter the select() again.
+ if timeout is not None:
+ end_time = time.time() + timeout
+ while True:
+ try:
+ return select.select(iwtd, owtd, ewtd, timeout)
+ except select.error:
+ err = sys.exc_info()[1]
+ if err.args[0] == errno.EINTR:
+ # if we loop back we have to subtract the
+ # amount of time we already waited.
+ if timeout is not None:
+ timeout = end_time - time.time()
+ if timeout < 0:
+ return([], [], [])
+ else:
+ # something else caused the select.error, so
+ # this actually is an exception.
+ raise