Document and detect EOF condition in interact()
authorjquast <contact@jeffquast.com>
Sun, 8 Jun 2014 04:35:16 +0000 (21:35 -0700)
committerThomas Kluyver <takowl@gmail.com>
Mon, 16 Jun 2014 01:01:18 +0000 (18:01 -0700)
doc/history.rst
pexpect/__init__.py

index 245b24cc88a40c3795c3c88e18c0c7b236309328..2b924a9290e62be48518a8092ce494db645edb78 100644 (file)
@@ -16,6 +16,9 @@ Version 3.3
   provides a more flexible alternative.
 * Fixed ``TypeError: got <type 'str'> ('\r\n') as pattern`` in ``readline()``
   method of ``spawnu`` (:ghissue:`67`).
+* Fixed issue where EOF was not correctly detected in ``interact()``, causing
+  a repeating loop of output on Linux, and blocking before EOF on BSD and
+  Solaris (:ghissue:`49`).
 
 Version 3.2
 ```````````
index 5a2cacc4b4fd7e26530e55c99e924d9a2ee76a64..a6323abf0ebc2f7acfc3937d74a9635e3123c53c 100644 (file)
@@ -914,12 +914,14 @@ class spawn(object):
         if self.child_fd in r:
             try:
                 s = os.read(self.child_fd, size)
-            except OSError:
-                # Linux does this
-                self.flag_eof = True
-                raise EOF('End Of File (EOF). Exception style platform.')
+            except OSError, err:
+                if err.args[0] == errno.EIO:
+                    # Linux-style EOF
+                    self.flag_eof = True
+                    raise EOF('End Of File (EOF). Exception style platform.')
+                raise
             if s == b'':
-                # BSD style
+                # BSD-style EOF
                 self.flag_eof = True
                 raise EOF('End Of File (EOF). Empty string style platform.')
 
@@ -1075,23 +1077,6 @@ class spawn(object):
         called at the beginning of a line. This method does not send a newline.
         It is the responsibility of the caller to ensure the eof is sent at the
         beginning of a line. '''
-
-        ### Hmmm... how do I send an EOF?
-        ###C  if ((m = write(pty, *buf, p - *buf)) < 0)
-        ###C      return (errno == EWOULDBLOCK) ? n : -1;
-        #fd = sys.stdin.fileno()
-        #old = termios.tcgetattr(fd) # remember current state
-        #attr = termios.tcgetattr(fd)
-        #attr[3] = attr[3] | termios.ICANON # ICANON must be set to see EOF
-        #try: # use try/finally to ensure state gets restored
-        #    termios.tcsetattr(fd, termios.TCSADRAIN, attr)
-        #    if hasattr(termios, 'CEOF'):
-        #        os.write(self.child_fd, '%c' % termios.CEOF)
-        #    else:
-        #        # Silly platform does not define CEOF so assume CTRL-D
-        #        os.write(self.child_fd, '%c' % 4)
-        #finally: # restore state
-        #    termios.tcsetattr(fd, termios.TCSADRAIN, old)
         if hasattr(termios, 'VEOF'):
             char = ord(termios.tcgetattr(self.child_fd)[6][termios.VEOF])
         else:
@@ -1644,10 +1629,14 @@ class spawn(object):
             if self.child_fd in r:
                 try:
                     data = self.__interact_read(self.child_fd)
-                except OSError as e:
-                    # The subprocess may have closed before we get to reading it
-                    if e.errno != errno.EIO:
-                        raise
+                except OSError, err:
+                    if err.args[0] == errno.EIO:
+                        # Linux-style EOF
+                        break
+                    raise
+                if data == b'':
+                    # BSD-style EOF
+                    break
                 if output_filter:
                     data = output_filter(data)
                 if self.logfile is not None: