Make capsys more like stdio streams in python3. Resolves #1407.
This commit is contained in:
parent
44ad369c17
commit
6ba3475448
1
AUTHORS
1
AUTHORS
|
@ -13,6 +13,7 @@ Andrzej Ostrowski
|
||||||
Andy Freeland
|
Andy Freeland
|
||||||
Anthon van der Neut
|
Anthon van der Neut
|
||||||
Antony Lee
|
Antony Lee
|
||||||
|
Anthony Sottile
|
||||||
Armin Rigo
|
Armin Rigo
|
||||||
Aron Curzon
|
Aron Curzon
|
||||||
Aviv Palivoda
|
Aviv Palivoda
|
||||||
|
|
|
@ -55,6 +55,14 @@ Changes
|
||||||
Thanks `@The-Compiler`_ for the PR.
|
Thanks `@The-Compiler`_ for the PR.
|
||||||
|
|
||||||
|
|
||||||
|
Bug Fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
* Fix ``AttributeError`` on ``sys.stdout.buffer`` / ``sys.stderr.buffer``
|
||||||
|
while using ``capsys`` fixture in python 3. (`#1407`_).
|
||||||
|
Thanks to `@asottile`_.
|
||||||
|
|
||||||
|
|
||||||
.. _@davidszotten: https://github.com/davidszotten
|
.. _@davidszotten: https://github.com/davidszotten
|
||||||
.. _@fushi: https://github.com/fushi
|
.. _@fushi: https://github.com/fushi
|
||||||
.. _@mattduck: https://github.com/mattduck
|
.. _@mattduck: https://github.com/mattduck
|
||||||
|
@ -65,6 +73,7 @@ Changes
|
||||||
.. _@unsignedint: https://github.com/unsignedint
|
.. _@unsignedint: https://github.com/unsignedint
|
||||||
.. _@Kriechi: https://github.com/Kriechi
|
.. _@Kriechi: https://github.com/Kriechi
|
||||||
|
|
||||||
|
.. _#1407: https://github.com/pytest-dev/pytest/issues/1407
|
||||||
.. _#1512: https://github.com/pytest-dev/pytest/issues/1512
|
.. _#1512: https://github.com/pytest-dev/pytest/issues/1512
|
||||||
.. _#1874: https://github.com/pytest-dev/pytest/pull/1874
|
.. _#1874: https://github.com/pytest-dev/pytest/pull/1874
|
||||||
.. _#1952: https://github.com/pytest-dev/pytest/pull/1952
|
.. _#1952: https://github.com/pytest-dev/pytest/pull/1952
|
||||||
|
|
|
@ -12,8 +12,8 @@ from tempfile import TemporaryFile
|
||||||
|
|
||||||
import py
|
import py
|
||||||
import pytest
|
import pytest
|
||||||
|
from _pytest.compat import CaptureIO
|
||||||
|
|
||||||
from py.io import TextIO
|
|
||||||
unicode = py.builtin.text
|
unicode = py.builtin.text
|
||||||
|
|
||||||
patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'}
|
patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'}
|
||||||
|
@ -403,7 +403,7 @@ class SysCapture(object):
|
||||||
if name == "stdin":
|
if name == "stdin":
|
||||||
tmpfile = DontReadFromInput()
|
tmpfile = DontReadFromInput()
|
||||||
else:
|
else:
|
||||||
tmpfile = TextIO()
|
tmpfile = CaptureIO()
|
||||||
self.tmpfile = tmpfile
|
self.tmpfile = tmpfile
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
|
|
|
@ -251,3 +251,19 @@ else:
|
||||||
except UnicodeError:
|
except UnicodeError:
|
||||||
errors = 'replace'
|
errors = 'replace'
|
||||||
return v.encode('ascii', errors)
|
return v.encode('ascii', errors)
|
||||||
|
|
||||||
|
|
||||||
|
if _PY2:
|
||||||
|
from py.io import TextIO as CaptureIO
|
||||||
|
else:
|
||||||
|
import io
|
||||||
|
|
||||||
|
class CaptureIO(io.TextIOWrapper):
|
||||||
|
def __init__(self):
|
||||||
|
super(CaptureIO, self).__init__(
|
||||||
|
io.BytesIO(),
|
||||||
|
encoding='UTF-8', newline='', write_through=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def getvalue(self):
|
||||||
|
return self.buffer.getvalue().decode('UTF-8')
|
||||||
|
|
|
@ -281,7 +281,7 @@ class TestLoggingInteraction(object):
|
||||||
def test_logging():
|
def test_logging():
|
||||||
import logging
|
import logging
|
||||||
import pytest
|
import pytest
|
||||||
stream = capture.TextIO()
|
stream = capture.CaptureIO()
|
||||||
logging.basicConfig(stream=stream)
|
logging.basicConfig(stream=stream)
|
||||||
stream.close() # to free memory/release resources
|
stream.close() # to free memory/release resources
|
||||||
""")
|
""")
|
||||||
|
@ -622,16 +622,16 @@ def test_error_during_readouterr(testdir):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class TestTextIO(object):
|
class TestCaptureIO(object):
|
||||||
def test_text(self):
|
def test_text(self):
|
||||||
f = capture.TextIO()
|
f = capture.CaptureIO()
|
||||||
f.write("hello")
|
f.write("hello")
|
||||||
s = f.getvalue()
|
s = f.getvalue()
|
||||||
assert s == "hello"
|
assert s == "hello"
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
def test_unicode_and_str_mixture(self):
|
def test_unicode_and_str_mixture(self):
|
||||||
f = capture.TextIO()
|
f = capture.CaptureIO()
|
||||||
if sys.version_info >= (3, 0):
|
if sys.version_info >= (3, 0):
|
||||||
f.write("\u00f6")
|
f.write("\u00f6")
|
||||||
pytest.raises(TypeError, "f.write(bytes('hello', 'UTF-8'))")
|
pytest.raises(TypeError, "f.write(bytes('hello', 'UTF-8'))")
|
||||||
|
@ -642,6 +642,18 @@ class TestTextIO(object):
|
||||||
f.close()
|
f.close()
|
||||||
assert isinstance(s, unicode)
|
assert isinstance(s, unicode)
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
sys.version_info[0] == 2,
|
||||||
|
reason='python 3 only behaviour',
|
||||||
|
)
|
||||||
|
def test_write_bytes_to_buffer(self):
|
||||||
|
"""In python3, stdout / stderr are text io wrappers (exposing a buffer
|
||||||
|
property of the underlying bytestream). See issue #1407
|
||||||
|
"""
|
||||||
|
f = capture.CaptureIO()
|
||||||
|
f.buffer.write(b'foo\r\n')
|
||||||
|
assert f.getvalue() == 'foo\r\n'
|
||||||
|
|
||||||
|
|
||||||
def test_bytes_io():
|
def test_bytes_io():
|
||||||
f = py.io.BytesIO()
|
f = py.io.BytesIO()
|
||||||
|
@ -900,8 +912,8 @@ class TestStdCapture(object):
|
||||||
with self.getcapture() as cap:
|
with self.getcapture() as cap:
|
||||||
sys.stdout.write("hello")
|
sys.stdout.write("hello")
|
||||||
sys.stderr.write("world")
|
sys.stderr.write("world")
|
||||||
sys.stdout = capture.TextIO()
|
sys.stdout = capture.CaptureIO()
|
||||||
sys.stderr = capture.TextIO()
|
sys.stderr = capture.CaptureIO()
|
||||||
print ("not seen")
|
print ("not seen")
|
||||||
sys.stderr.write("not seen\n")
|
sys.stderr.write("not seen\n")
|
||||||
out, err = cap.readouterr()
|
out, err = cap.readouterr()
|
||||||
|
|
Loading…
Reference in New Issue