New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

capsys + sys.stdout.buffer => AttributeError #1407

Closed
asottile opened this Issue Feb 22, 2016 · 9 comments

Comments

Projects
None yet
4 participants
@asottile
Member

asottile commented Feb 22, 2016

Applicable versions where sys.stdout.buffer should exist and be a bytestream:

  • python3.x
import sys


def test(capsys):
    sys.stdout.buffer.write(b'hi\n')
    assert capsys.readouterr()[0] == 'hi\n'
$ py.test test.py
============================= test session starts ==============================
platform linux -- Python 3.4.3, pytest-2.8.7, py-1.4.31, pluggy-0.3.1
rootdir: /home/asottile/workspace/cheetah_lint, inifile: 
collected 1 items 

test.py F

=================================== FAILURES ===================================
_____________________________________ test _____________________________________

capsys = <_pytest.capture.CaptureFixture object at 0x7f15ca2cd320>

    def test(capsys):
>       sys.stdout.buffer.write(b'hi\n')
E       AttributeError: '_io.StringIO' object has no attribute 'buffer'

test.py:5: AttributeError
=========================== 1 failed in 0.01 seconds ===========================
@nicoddemus

This comment has been minimized.

Member

nicoddemus commented Feb 22, 2016

Hmm I'm not sure how to solve this @asottile... after all io.StringIO doesn't have a buffer object anyway. Do you have any suggestion on how this could be fixed?

@asottile

This comment has been minimized.

Member

asottile commented Feb 23, 2016

Perhaps an object that looks something like this?

class FakeStdout(object):
    def __init__(self):
        self.buffer = io.BytesIO()

    def write(self, s):
        self.buffer.write(s.encode('UTF-8'))

    def _read_out(self):
        return self.buffer.getvalue().decode('UTF-8')

though that has at least 3 cases where I can see it not working :S

Maybe introduce a capsysbytes which handles this case and returns bytes instead of text (str PY3 / unicode PY2)?

@funkyfuture

This comment has been minimized.

funkyfuture commented Nov 12, 2016

i also am in need of such functionality. any idea for a simple workaround for now?

propably i will capsys.close(), replace the capsys.captureclass with a subclass of SysCapture for bytes and capsys._start() at a test's start.

concerning the design of a native support for this, i have these considerations:

  • there should also be support for a binary capfd-like
  • should the data type be configurable per filedescriptor?
    • writing bytes to stdout and text to stderr is propably not uncommon

i'm not really fond of further, longer fixture names. though the idea of configuring the fixtures (e.g. with a set_mode method) per test also doesn't convince me.

@nicoddemus

This comment has been minimized.

Member

nicoddemus commented Nov 12, 2016

should the data type be configurable per filedescriptor?

Good point.

i'm not really fond of further, longer fixture names. though the idea of configuring the fixtures (e.g. with a set_mode method) per test also doesn't convince me.

I think a capsys.set_mode('b', 'out') is not a bad idea actually (if we can change that after the fixture was created, that is). There are plenty of mechanisms that you can use so that you don't need to configure capsys for all tests which need it, from marks to autouse-fixtures.

Btw, I mention capsys.set_mode('b', 'out') instead of the arguably more natural capsys.set_mode('out', 'b') because we can have the second argument optional and mean "all streams" when not given.

@funkyfuture

This comment has been minimized.

funkyfuture commented Nov 12, 2016

There are plenty of mechanisms that you can use so that you don't need to configure capsys for all tests which need it, from marks to autouse-fixtures.

okay, should be well documented.

your signature proposal looks good. the complement should be t (yeah, it's obvious).

when i'm responsible towards myself and my schedule, i will not implement that too soon. :-/ i certainly appreciate if someone else did it.

@nicoddemus

This comment has been minimized.

Member

nicoddemus commented Nov 12, 2016

Yeah, a PR would be most welcome. 😁

@RonnyPfannschmidt

This comment has been minimized.

Member

RonnyPfannschmidt commented Nov 12, 2016

imho capture should NOT support buffer by default, only if its requested as encoded

@funkyfuture

This comment has been minimized.

funkyfuture commented Nov 12, 2016

as far as i understood, no one is proposing a different default behavior. could you elaborate your point?

asottile added a commit to asottile/pytest that referenced this issue Feb 19, 2017

asottile added a commit to asottile/pytest that referenced this issue Feb 19, 2017

asottile added a commit to asottile/pytest that referenced this issue Feb 19, 2017

asottile added a commit to asottile/pytest that referenced this issue Feb 19, 2017

asottile added a commit to asottile/pytest that referenced this issue Feb 19, 2017

asottile added a commit to asottile/pytest that referenced this issue Feb 24, 2017

nicoddemus added a commit that referenced this issue Feb 24, 2017

Merge pull request #2266 from asottile/capture_v2
Make capsys more like stdio streams in python3. Resolves #1407.
@nicoddemus

This comment has been minimized.

Member

nicoddemus commented Feb 24, 2017

Fixed by #2266

This was referenced Mar 6, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment