diff options
author | David Cullen <david.cullen@technicolor.com> | 2016-06-28 14:49:43 -0400 |
---|---|---|
committer | David Cullen <david.cullen@technicolor.com> | 2016-06-28 14:49:43 -0400 |
commit | 7c03f4746c06cdfa169b514f38f856dc4caa263f (patch) | |
tree | e524a921ecb320d29c27172f045f944c628cf00e /pexpect | |
parent | 3ed8d66ffb12863bc4a55a4b5dab7fca7ce9a9cc (diff) | |
download | pexpect-git-7c03f4746c06cdfa169b514f38f856dc4caa263f.tar.gz |
Restore POSIX support to fdpexpect.
Diffstat (limited to 'pexpect')
-rw-r--r-- | pexpect/fdpexpect.py | 19 | ||||
-rw-r--r-- | pexpect/pty_spawn.py | 38 | ||||
-rw-r--r-- | pexpect/utils.py | 32 |
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 |