From b27dde24d6fc4e737c685effe18ae121881c976c Mon Sep 17 00:00:00 2001 From: Samuel Dion-Girardeau Date: Sat, 28 Oct 2017 14:53:19 -0400 Subject: [PATCH 1/3] Use a nametuple for `readouterr()` results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows accessing `out` and `err` directly by attribute, while preserving tuple unpacking. Also added tests, one for the `capsys` fixture, and one for the `MultiCapture` class itself. --- _pytest/capture.py | 8 ++++++-- testing/test_capture.py | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/_pytest/capture.py b/_pytest/capture.py index 13e1216cc..f6d3c61b3 100644 --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -4,6 +4,7 @@ per-test stdout/stderr capturing mechanism. """ from __future__ import absolute_import, division, print_function +import collections import contextlib import sys import os @@ -306,6 +307,9 @@ class EncodedFile(object): return getattr(object.__getattribute__(self, "buffer"), name) +CaptureResult = collections.namedtuple("CaptureResult", ["out", "err"]) + + class MultiCapture(object): out = err = in_ = None @@ -366,8 +370,8 @@ class MultiCapture(object): def readouterr(self): """ return snapshot unicode value of stdout/stderr capturings. """ - return (self.out.snap() if self.out is not None else "", - self.err.snap() if self.err is not None else "") + return CaptureResult(self.out.snap() if self.out is not None else "", + self.err.snap() if self.err is not None else "") class NoCapture: diff --git a/testing/test_capture.py b/testing/test_capture.py index f961694ff..a21e767a8 100644 --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -922,6 +922,14 @@ class TestStdCapture(object): out, err = cap.readouterr() assert err == "error2" + def test_capture_results_accessible_by_attribute(self): + with self.getcapture() as cap: + sys.stdout.write("hello") + sys.stderr.write("world") + capture_result = cap.readouterr() + assert capture_result.out == "hello" + assert capture_result.err == "world" + def test_capturing_readouterr_unicode(self): with self.getcapture() as cap: print("hx\xc4\x85\xc4\x87") @@ -1083,6 +1091,14 @@ def test_using_capsys_fixture_works_with_sys_stdout_encoding(capsys): assert err == '' +def test_capsys_results_accessible_by_attribute(capsys): + sys.stdout.write("spam") + sys.stderr.write("eggs") + capture_result = capsys.readouterr() + assert capture_result.out == "spam" + assert capture_result.err == "eggs" + + @needsosdup @pytest.mark.parametrize('use', [True, False]) def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): From 8e28815d4455dbfcd4bcec8ba3c0f096dbcb1abd Mon Sep 17 00:00:00 2001 From: Samuel Dion-Girardeau Date: Sat, 28 Oct 2017 15:07:26 -0400 Subject: [PATCH 2/3] Add changelog entry for issue #2879 --- changelog/2879.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/2879.feature diff --git a/changelog/2879.feature b/changelog/2879.feature new file mode 100644 index 000000000..8932d8c30 --- /dev/null +++ b/changelog/2879.feature @@ -0,0 +1 @@ +Return stdout/stderr capture results as a ``namedtuple``, so ``out`` and ``err`` can be accessed by attribute. From 8e178e9f9b5d8ae217fcd7635651157c5c9a94bc Mon Sep 17 00:00:00 2001 From: Samuel Dion-Girardeau Date: Sat, 28 Oct 2017 15:08:53 -0400 Subject: [PATCH 3/3] Add myself to AUTHORS list --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index aeef6dd9b..ea3b7f50e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -156,6 +156,7 @@ Ronny Pfannschmidt Ross Lawley Russel Winder Ryan Wooden +Samuel Dion-Girardeau Samuele Pedroni Segev Finer Simon Gomizelj