Skip to content

Commit

Permalink
Make capsys more like stdio streams in python3. Resolves #1407.
Browse files Browse the repository at this point in the history
  • Loading branch information
asottile committed Feb 19, 2017
1 parent 21a09f0 commit f6d5651
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 8 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Andrzej Ostrowski
Andy Freeland
Anthon van der Neut
Antony Lee
Anthony Sottile
Armin Rigo
Aron Curzon
Aviv Palivoda
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
3.0.7 (unreleased)
==================

* Fix ``AttributeError`` on ``sys.stdout.buffer`` / ``sys.stderr.buffer``
while using ``capsys`` fixture in python 3. (`#1407`_).
Thanks to `@asottile`_.

* Fix regression, pytest now skips unittest correctly if run with ``--pdb``
(`#2137`_). Thanks to `@gst`_ for the report and `@mbyt`_ for the PR.

Expand Down Expand Up @@ -32,6 +36,7 @@
.. _@sirex: https://github.com/sirex
.. _@vidartf: https://github.com/vidartf

.. _#1407: https://github.com/pytest-dev/pytest/issues/1407
.. _#2137: https://github.com/pytest-dev/pytest/issues/2137
.. _#2160: https://github.com/pytest-dev/pytest/issues/2160
.. _#2231: https://github.com/pytest-dev/pytest/issues/2231
Expand Down
4 changes: 2 additions & 2 deletions _pytest/capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

import py
import pytest
from _pytest.compat import CaptureIO

from py.io import TextIO
unicode = py.builtin.text

patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'}
Expand Down Expand Up @@ -402,7 +402,7 @@ def __init__(self, fd, tmpfile=None):
if name == "stdin":
tmpfile = DontReadFromInput()
else:
tmpfile = TextIO()
tmpfile = CaptureIO()
self.tmpfile = tmpfile

def start(self):
Expand Down
15 changes: 15 additions & 0 deletions _pytest/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,18 @@ def safe_str(v):
except UnicodeError:
errors = 'replace'
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', write_through=True,
)

def getvalue(self):
return self.buffer.getvalue().decode('UTF-8')
19 changes: 13 additions & 6 deletions testing/test_capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ def test_logging_stream_ownership(self, testdir):
def test_logging():
import logging
import pytest
stream = capture.TextIO()
stream = capture.CaptureIO()
logging.basicConfig(stream=stream)
stream.close() # to free memory/release resources
""")
Expand Down Expand Up @@ -622,16 +622,16 @@ def bad_snap(self):
])


class TestTextIO:
class TestCaptureIO:
def test_text(self):
f = capture.TextIO()
f = capture.CaptureIO()
f.write("hello")
s = f.getvalue()
assert s == "hello"
f.close()

def test_unicode_and_str_mixture(self):
f = capture.TextIO()
f = capture.CaptureIO()
if sys.version_info >= (3, 0):
f.write("\u00f6")
pytest.raises(TypeError, "f.write(bytes('hello', 'UTF-8'))")
Expand All @@ -642,6 +642,13 @@ def test_unicode_and_str_mixture(self):
f.close()
assert isinstance(s, unicode)

def test_write_bytes_to_buffer(self):
f = capture.CaptureIO()
# In python3, stdout / stderr are text io wrappers (exposing a buffer
# property of the underlying bytestream).
getattr(f, 'buffer', f).write(b'foo\n')
assert f.getvalue() == 'foo\n'


def test_bytes_io():
f = py.io.BytesIO()
Expand Down Expand Up @@ -900,8 +907,8 @@ def test_capturing_modify_sysouterr_in_between(self):
with self.getcapture() as cap:
sys.stdout.write("hello")
sys.stderr.write("world")
sys.stdout = capture.TextIO()
sys.stderr = capture.TextIO()
sys.stdout = capture.CaptureIO()
sys.stderr = capture.CaptureIO()
print ("not seen")
sys.stderr.write("not seen\n")
out, err = cap.readouterr()
Expand Down

0 comments on commit f6d5651

Please sign in to comment.