Fix windows console workaround error with non-standard io-streams

Fix #2666
This commit is contained in:
Bruno Oliveira 2017-08-07 20:55:28 -03:00
parent 76c55b31c6
commit cc0f2473eb
3 changed files with 31 additions and 4 deletions

View File

@ -36,7 +36,7 @@ def pytest_addoption(parser):
def pytest_load_initial_conftests(early_config, parser, args): def pytest_load_initial_conftests(early_config, parser, args):
ns = early_config.known_args_namespace ns = early_config.known_args_namespace
if ns.capture == "fd": if ns.capture == "fd":
_py36_windowsconsoleio_workaround() _py36_windowsconsoleio_workaround(sys.stdout)
_colorama_workaround() _colorama_workaround()
_readline_workaround() _readline_workaround()
pluginmanager = early_config.pluginmanager pluginmanager = early_config.pluginmanager
@ -524,7 +524,7 @@ def _readline_workaround():
pass pass
def _py36_windowsconsoleio_workaround(): def _py36_windowsconsoleio_workaround(stream):
""" """
Python 3.6 implemented unicode console handling for Windows. This works Python 3.6 implemented unicode console handling for Windows. This works
by reading/writing to the raw console handle using by reading/writing to the raw console handle using
@ -541,13 +541,20 @@ def _py36_windowsconsoleio_workaround():
also means a different handle by replicating the logic in also means a different handle by replicating the logic in
"Py_lifecycle.c:initstdio/create_stdio". "Py_lifecycle.c:initstdio/create_stdio".
:param stream: in practice ``sys.stdout`` or ``sys.stderr``, but given
here as parameter for unittesting purposes.
See https://github.com/pytest-dev/py/issues/103 See https://github.com/pytest-dev/py/issues/103
""" """
if not sys.platform.startswith('win32') or sys.version_info[:2] < (3, 6): if not sys.platform.startswith('win32') or sys.version_info[:2] < (3, 6):
return return
buffered = hasattr(sys.stdout.buffer, 'raw') # bail out if ``stream`` doesn't seem like a proper ``io`` stream (#2666)
raw_stdout = sys.stdout.buffer.raw if buffered else sys.stdout.buffer if not hasattr(stream, 'buffer'):
return
buffered = hasattr(stream.buffer, 'raw')
raw_stdout = stream.buffer.raw if buffered else stream.buffer
if not isinstance(raw_stdout, io._WindowsConsoleIO): if not isinstance(raw_stdout, io._WindowsConsoleIO):
return return

3
changelog/2666.bugfix Normal file
View File

@ -0,0 +1,3 @@
Fix error on Windows and Python 3.6+ when ``sys.stdout`` has been replaced with
a stream-like object which does not implement the full ``io`` module buffer protocol. In particular this
affects ``pytest-xdist`` users on the aforementioned platform.

View File

@ -1140,6 +1140,23 @@ def test_error_attribute_issue555(testdir):
reprec.assertoutcome(passed=1) reprec.assertoutcome(passed=1)
@pytest.mark.skipif(not sys.platform.startswith('win') and sys.version_info[:2] >= (3, 6),
reason='only py3.6+ on windows')
def test_py36_windowsconsoleio_workaround_non_standard_streams():
"""
Ensure _py36_windowsconsoleio_workaround function works with objects that
do not implement the full ``io``-based stream protocol, for example execnet channels (#2666).
"""
from _pytest.capture import _py36_windowsconsoleio_workaround
class DummyStream:
def write(self, s):
pass
stream = DummyStream()
_py36_windowsconsoleio_workaround(stream)
def test_dontreadfrominput_has_encoding(testdir): def test_dontreadfrominput_has_encoding(testdir):
testdir.makepyfile(""" testdir.makepyfile("""
import sys import sys