[Python-modules-commits] [python-spur] 05/13: Handle reading using pty in Python >= 3.4

Ruben Undheim rubund-guest at moszumanska.debian.org
Sun Jan 3 10:38:51 UTC 2016


This is an automated email from the git hooks/post-receive script.

rubund-guest pushed a commit to branch master
in repository python-spur.

commit 090a23aaef653539d9ec10794996f8664779bff4
Author: Michael Williamson <mike at zwobble.org>
Date:   Sun Dec 27 23:04:41 2015 +0000

    Handle reading using pty in Python >= 3.4
---
 spur/io.py    | 51 ++++++++++++++++++++++++++++-----------------------
 spur/local.py | 18 ++++++++----------
 spur/ssh.py   |  6 +++---
 3 files changed, 39 insertions(+), 36 deletions(-)

diff --git a/spur/io.py b/spur/io.py
index 04190f8..11f4e93 100644
--- a/spur/io.py
+++ b/spur/io.py
@@ -1,23 +1,27 @@
 import threading
+import os
 
 
 class IoHandler(object):
-    def __init__(self, in_out_pairs):
-        self._handlers = [
-            _output_handler(file_in, file_out)
-            for file_in, file_out
-            in in_out_pairs
-        ]
+    def __init__(self, channels):
+        self._handlers = list(map(_output_handler, channels))
         
     def wait(self):
         return [handler.wait() for handler in self._handlers]
 
 
-def _output_handler(file_in, file_out):
-    if file_out is None:
-        return _ReadOutputAtEnd(file_in)
+class Channel(object):
+    def __init__(self, file_in, file_out, is_pty=False):
+        self.file_in = file_in
+        self.file_out = file_out
+        self.is_pty = is_pty
+
+
+def _output_handler(channel):
+    if channel.file_out is None and not channel.is_pty:
+        return _ReadOutputAtEnd(channel.file_in)
     else:
-        return _ContinuousReader(file_in, file_out)
+        return _ContinuousReader(channel)
 
 
 class _ReadOutputAtEnd(object):
@@ -25,20 +29,14 @@ class _ReadOutputAtEnd(object):
         self._file_in = file_in
     
     def wait(self):
-        try:
-            return self._file_in.read()
-        except IOError:
-            # TODO: is there a more elegant fix?
-            # Attempting to read from a pty master that has received nothing
-            # seems to raise an IOError when reading
-            # See: http://bugs.python.org/issue5380
-            return b""
+        return self._file_in.read()
     
 
 class _ContinuousReader(object):
-    def __init__(self, file_in, file_out):
-        self._file_in = file_in
-        self._file_out = file_out
+    def __init__(self, channel):
+        self._file_in = channel.file_in
+        self._file_out = channel.file_out
+        self._is_pty = channel.is_pty
         self._output = b""
         
         self._thread = threading.Thread(target=self._capture_output)
@@ -52,9 +50,16 @@ class _ContinuousReader(object):
     def _capture_output(self):
         output_buffer = []
         while True:
-            output = self._file_in.read(1)
+            try:
+                output = self._file_in.read(1)
+            except IOError:
+                if self._is_pty:
+                    output = b""
+                else:
+                    raise
             if output:
-                self._file_out.write(output)
+                if self._file_out is not None:
+                    self._file_out.write(output)
                 output_buffer.append(output)
             else:
                 self._output = b"".join(output_buffer)
diff --git a/spur/local.py b/spur/local.py
index a4045e1..77e840b 100644
--- a/spur/local.py
+++ b/spur/local.py
@@ -14,7 +14,7 @@ except ImportError:
 from spur.tempdir import create_temporary_dir
 from spur.files import FileOperations
 import spur.results
-from .io import IoHandler
+from .io import IoHandler, Channel
 from .errors import NoSuchCommandError
 
 
@@ -79,6 +79,7 @@ class LocalShell(object):
             
             def close_slave_on_exit():
                 process.wait()
+                # TODO: ensure the IO handler has finished before closing
                 os.close(slave)
             
             thread = threading.Thread(target=close_slave_on_exit)
@@ -94,10 +95,10 @@ class LocalShell(object):
             process,
             allow_error=allow_error,
             process_stdin=process_stdin,
-            process_stdout=process_stdout,
-            process_stderr=process_stderr,
-            stdout=stdout,
-            stderr=stderr
+            channels=[
+                Channel(process_stdout, stdout, is_pty=use_pty),
+                Channel(process_stderr, stderr, is_pty=use_pty),
+            ]
         )
         if store_pid:
             spur_process.pid = process.pid
@@ -140,16 +141,13 @@ class LocalShell(object):
             
 
 class LocalProcess(object):
-    def __init__(self, subprocess, allow_error, process_stdin, process_stdout, process_stderr, stdout, stderr):
+    def __init__(self, subprocess, allow_error, process_stdin, channels):
         self._subprocess = subprocess
         self._allow_error = allow_error
         self._process_stdin = process_stdin
         self._result = None
             
-        self._io = IoHandler([
-            (process_stdout, stdout),
-            (process_stderr, stderr),
-        ])
+        self._io = IoHandler(channels)
         
     def is_running(self):
         return self._subprocess.poll() is None
diff --git a/spur/ssh.py b/spur/ssh.py
index 49f3efe..5fb20f3 100644
--- a/spur/ssh.py
+++ b/spur/ssh.py
@@ -17,7 +17,7 @@ import paramiko
 from spur.tempdir import create_temporary_dir
 from spur.files import FileOperations
 import spur.results
-from .io import IoHandler
+from .io import IoHandler, Channel
 from .errors import NoSuchCommandError
 
 
@@ -341,8 +341,8 @@ class SshProcess(object):
         self._result = None
         
         self._io = IoHandler([
-            (self._stdout, stdout),
-            (self._stderr, stderr),
+            Channel(self._stdout, stdout),
+            Channel(self._stderr, stderr),
         ])
         
     def is_running(self):

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-spur.git



More information about the Python-modules-commits mailing list