-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Fix crash when printing while capsysbinary is active #6926
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. @blueyed?
@@ -591,6 +589,11 @@ def snap(self): | |||
self.tmpfile.truncate() | |||
return res | |||
|
|||
def writeorg(self, data): | |||
""" write to original file descriptor. """ | |||
data = data.encode("utf-8") # XXX use encoding of original stream |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm not related to this code, but curious how FDCaptureBinary
still creates tmpfile
with encoding="UTF-8"
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you mean why FDCaptureBinary
wraps the temporary file with EncodedFile
(== TextIOWrapper
), it's for two reasons:
- In FD capturing, in addition to the FD redirection itself, it also does sys capturing. And the sys capturing requires a file object which looks like
sys.stdout
and friends, which are text-mode. - The
FDCapture
subclass uses it in itssnap()
implementation.
I have some plans to untangle all of this, but thought it'd be better not to mix refactorings with bug fixes.
Previously, writing to sys.stdout/stderr in text-mode (e.g. `print('foo')`) while a `capsysbinary` fixture is active, would crash with: /usr/lib/python3.7/contextlib.py:119: in __exit__ next(self.gen) E TypeError: write() argument must be str, not bytes This is due to some confusion in the types. The relevant functions are `snap()` and `writeorg()`. The function `snap()` returns what was captured, and the return type should be `bytes` for the binary captures and `str` for the regular ones. The `snap()` return value is eventually passed to `writeorg()` to be written to the original file, so it's input type should correspond to `snap()`. But this was incorrect for `SysCaptureBinary`, which handled it like `str`. To fix this, be explicit in the `snap()` and `writeorg()` implementations, also of the other Capture types. We can't add type annotations yet, because the current inheritance scheme breaks Liskov Substitution and mypy would complain. To be refactored later. Fixes: pytest-dev#6871 Co-authored-by: Ran Benita (some modifications & commit message)
e3e10bd
to
1fda861
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work @bluetech, thanks!
Sorry, I just realized we have forgotten to backport this to |
Thanks for the great work! :) Just tested this from the current master 2d9dac9 by switching from |
Backport in #7002. Should be fixed in (upcoming) 5.4.2. |
I would like to avoid that extra fork to a child Python interpreter (it looks like something that can be easily avoided). It's something that's possible now that the code ships just some trivial wrappers (which are, in turn, needed for setuptools' `console_scripts`). This cannot use the `capsysbinary` fixture for wrapping of stdout/stderr due to something in pytest which already got fixed, but has not been released yet (May 2020). Let's use `capfdbinary` which works fine. Change-Id: Ic4a124a5cbe2bd24c56e4565d27d313fe4da703f See-also: pytest-dev/pytest#6926
Closes #6880 by replacing that PR with some modifications as described in #6880 (review) (step 2).
Previously, writing to sys.stdout/stderr in text-mode (e.g.
print('foo')
) while acapsysbinary
fixture is active, would crashwith:
This is due to some confusion in the types. The relevant functions are
snap()
andwriteorg()
. The functionsnap()
returns what wascaptured, and the return type should be
bytes
for the binary capturesand
str
for the regular ones. Thesnap()
return value is eventuallypassed to
writeorg()
to be written to the original file, so it's inputtype should correspond to
snap()
. But this was incorrect forSysCaptureBinary
, which handled it likestr
.To fix this, be explicit in the
snap()
andwriteorg()
implementations, also of the other Capture types.
We can't add type annotations yet, because the current inheritance
scheme breaks Liskov Substitution and mypy would complain. To be
refactored later.
Fixes: #6871
Co-authored-by: Ran Benita (some modifications & commit message)