summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2011-12-16 14:37:37 -0800
committerZac Medico <zmedico@gentoo.org>2011-12-16 14:37:37 -0800
commit9f84f1333bb1b6ee32083fba39da5ce616f2657c (patch)
tree998794c54e64f6223f7b461fa0cc774fdedd0e69
parent071c65bb4abac3c251f335bde20e13368349c55d (diff)
downloadportage-9f84f1333bb1b6ee32083fba39da5ce616f2657c.tar.gz
portage-9f84f1333bb1b6ee32083fba39da5ce616f2657c.tar.bz2
portage-9f84f1333bb1b6ee32083fba39da5ce616f2657c.zip
_test_pty_eof: use os.read, not array.fromfile
We have abandoned array.fromfile() due to bugs that exist in all known versions of Python (including Python 2.7 and Python 3.2). See PipeReaderArrayTestCase, for example.
-rw-r--r--pym/portage/tests/ebuild/test_pty_eof.py29
-rw-r--r--pym/portage/util/_pty.py70
2 files changed, 40 insertions, 59 deletions
diff --git a/pym/portage/tests/ebuild/test_pty_eof.py b/pym/portage/tests/ebuild/test_pty_eof.py
index 0b0bbdb35..fe218b6fa 100644
--- a/pym/portage/tests/ebuild/test_pty_eof.py
+++ b/pym/portage/tests/ebuild/test_pty_eof.py
@@ -1,14 +1,12 @@
# Copyright 2009-2011 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
-import platform
-
from portage.tests import TestCase
from portage.util._pty import _can_test_pty_eof, _test_pty_eof
-class PtyEofFdopenBufferedTestCase(TestCase):
+class PtyEofTestCase(TestCase):
- def testPtyEofFdopenBuffered(self):
+ def testPtyEof(self):
if not _can_test_pty_eof():
skip_reason = "unsupported on this platform"
@@ -23,29 +21,6 @@ class PtyEofFdopenBufferedTestCase(TestCase):
# The result is only valid if openpty does not raise EnvironmentError.
if _can_test_pty_eof():
try:
- self.assertEqual(_test_pty_eof(fdopen_buffered=True), True)
- except EnvironmentError:
- pass
-
-class PtyEofFdopenUnBufferedTestCase(TestCase):
- def testPtyEofFdopenUnBuffered(self):
- # New development: It appears that array.fromfile() is usable
- # with python3 as long as fdopen is called with a bufsize
- # argument of 0.
-
- if not _can_test_pty_eof():
- skip_reason = "unsupported on this platform"
- self.portage_skip = skip_reason
- self.fail(skip_reason)
- return
-
- if platform.python_implementation() == 'PyPy':
- # https://bugs.pypy.org/issue956
- self.todo = True
-
- # The result is only valid if openpty does not raise EnvironmentError.
- if _can_test_pty_eof():
- try:
self.assertEqual(_test_pty_eof(), True)
except EnvironmentError:
pass
diff --git a/pym/portage/util/_pty.py b/pym/portage/util/_pty.py
index af0fc9d8a..97a38c0c3 100644
--- a/pym/portage/util/_pty.py
+++ b/pym/portage/util/_pty.py
@@ -1,7 +1,7 @@
# Copyright 2010-2011 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
-import array
+import errno
import fcntl
import platform
import pty
@@ -28,19 +28,22 @@ def _can_test_pty_eof():
"""
return platform.system() in ("Linux",)
-def _test_pty_eof(fdopen_buffered=False):
+def _test_pty_eof():
"""
- Returns True if this issues is fixed for the currently
- running version of python: http://bugs.python.org/issue5380
- Raises an EnvironmentError from openpty() if it fails.
+ Returns True if EOF appears to be handled correctly with pty
+ devices. Raises an EnvironmentError from openpty() if it fails.
- NOTE: This issue is only problematic when array.fromfile()
- is used, rather than os.read(). However, array.fromfile()
- is preferred since it is approximately 10% faster.
+ This used to be used to detect if the following issue was fixed
+ in the currently running version of python:
- New development: It appears that array.fromfile() is usable
- with python3 as long as fdopen is called with a bufsize
- argument of 0.
+ http://bugs.python.org/issue5380
+
+ However, array.fromfile() use has since been abandoned due to
+ bugs that exist in all known versions of Python (including Python
+ 2.7 and Python 3.2). See PipeReaderArrayTestCase, for example.
+ This is somewhat unfortunate, since the combination of
+ array.fromfile() and array.tofile() is approximately 10% faster
+ than the combination of os.read() and os.write().
"""
use_fork = False
@@ -86,39 +89,42 @@ def _test_pty_eof(fdopen_buffered=False):
if pid is not None:
os.waitpid(pid, 0)
- if fdopen_buffered:
- master_file = os.fdopen(master_fd, 'rb')
- else:
- master_file = os.fdopen(master_fd, 'rb', 0)
- eof = False
data = []
- iwtd = [master_file]
+ iwtd = [master_fd]
owtd = []
ewtd = []
- while not eof:
+ while True:
events = select.select(iwtd, owtd, ewtd)
if not events[0]:
- eof = True
+ # EOF
break
- buf = array.array('B')
+ buf = None
try:
- buf.fromfile(master_file, 1024)
- except (EOFError, IOError):
- eof = True
-
- if not buf:
- eof = True
+ buf = os.read(master_fd, 1024)
+ except OSError as e:
+ # EIO happens with pty on Linux after the
+ # slave end of the pty has been closed.
+ if e.errno == errno.EIO:
+ # EOF: return empty string of bytes
+ buf = b''
+ elif e.errno == errno.EAGAIN:
+ # EAGAIN: return None
+ buf = None
+ else:
+ raise
+
+ if buf is None:
+ pass
+ elif not buf:
+ # EOF
+ break
else:
- try:
- # Python >=3.2
- data.append(buf.tobytes())
- except AttributeError:
- data.append(buf.tostring())
+ data.append(buf)
- master_file.close()
+ os.close(master_fd)
return test_string == _unicode_decode(b''.join(data), encoding='utf_8', errors='strict')