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 breaks sys.stdin.encoding #2375

Closed
kpinc opened this Issue Apr 20, 2017 · 4 comments

Comments

Projects
None yet
4 participants
@kpinc

kpinc commented Apr 20, 2017

Hi,

Using capsys breaks the use of sys.stdin.encoding. (And probably does the same for sys.stdout.encoding and other file like object encoding attributes.)

Using sys.stdout.encoding is important when writing portable code that sometimes outputs stdout to the MS Windows console, which may use cp1252 encoding. If you don't explicitly do something to encode your unicode strings and handle encoding failures then printing sometimes crashes your program with a UnicodeEncodeError exception. But testing sys.stdout.encoding with capsys is awkward.

See the example.

$ venv/bin/pip list
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
appdirs (1.4.3)
packaging (16.8)
pip (9.0.1)
py (1.4.33)
pyparsing (2.2.0)
pytest (3.0.7)
setuptools (35.0.1)
six (1.10.0)

Debian stable 8.7 (Jessie)
Python 2.7.9 (from Debian repo)
(You get the same output from Debian's Python 3.4.2.)
#src/test_capsys.py 
from __future__ import print_function

import sys


def func(text):
    print(text.encode(sys.stdout.encoding, 'replace'))


def test_func(capsys):
    func('sample text')
    (out, err) = capsys.readouterr()
    assert out
    assert err == ''
$ venv/bin/pytest 
============================= test session starts ==============================
platform linux2 -- Python 2.7.9, pytest-3.0.7, py-1.4.33, pluggy-0.4.0
rootdir: *REDACTED*, inifile:
collected 1 items 

src/test_capsys.py F

=================================== FAILURES ===================================
__________________________________ test_func ___________________________________

capsys = <_pytest.capture.CaptureFixture instance at 0x7f90ba65a8c0>

    def test_func(capsys):
>       func('sample text')

src/test_capsys.py:11: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

text = 'sample text'

    def func(text):
>       print(text.encode(sys.stdout.encoding, 'replace'))
E       TypeError: encode() argument 1 must be string, not None

src/test_capsys.py:7: TypeError
=========================== 1 failed in 0.40 seconds ===========================

EDIT: fixed formatting

@nicoddemus

This comment has been minimized.

Member

nicoddemus commented Apr 20, 2017

Thanks for the report!

It seems it should be just a matter of copying the encoding attribute from the original stream.

@kpinc

This comment has been minimized.

kpinc commented Apr 20, 2017

@kpinc

This comment has been minimized.

kpinc commented Apr 20, 2017

@maiksensi

This comment has been minimized.

Contributor

maiksensi commented Jul 15, 2017

I could only reproduce this for py27 running it via: tox -e py27,py34,py36,py35 -- testcases/test_capsys.py.

ERROR:   py27: commands failed
  py34: commands succeeded
  py36: commands succeeded
  py35: commands succeeded

The py27 outout is:

testcases/test_capsys.py F
==================================================================================================== short test summary info =====================================================================================================
FAIL testcases/test_capsys.py::test_func

============================================================================================================ FAILURES ============================================================================================================
___________________________________________________________________________________________________________ test_func ____________________________________________________________________________________________________________

capsys = <_pytest.capture.CaptureFixture instance at 0x7f4fc750d680>

    def test_func(capsys):
>       func('sample text')

testcases/test_capsys.py:12: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

text = 'sample text'

    def func(text):
>       print(text.encode(sys.stdout.encoding, 'replace'))
E       TypeError: encode() argument 1 must be string, not None

testcases/test_capsys.py:8: TypeError
==================================================================================================== 1 failed in 0.05 seconds ====================================================================================================
ERROR: InvocationError: '/home/maiksen/repos/pytest/.tox/py27/bin/pytest --lsof -rfsxX testcases/test_capsys.py'

I am on the latest py3.4 available and on ubuntu 16.04.

This doesnt probably change the suggestions on what to change to fix the issue.

Llandy3d added a commit to Llandy3d/pytest that referenced this issue Jul 15, 2017

Set attribute 'encoding' of CaptureIO to 'UTF-8'
Fixes patching sys.stdout.encoding when using Capsys fixture on Python 2.

Fix pytest-dev#2375

Llandy3d added a commit to Llandy3d/pytest that referenced this issue Jul 15, 2017

Provides encoding attribute on CaptureIO
Removed py.io dependency for CaptureIO.

Fix pytest-dev#2375

Llandy3d added a commit to Llandy3d/pytest that referenced this issue Jul 16, 2017

Llandy3d added a commit to Llandy3d/pytest that referenced this issue Jul 16, 2017

@flub flub closed this in #2578 Jul 20, 2017

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