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
python3: behave incorrectly mocks stdout / stderr (Missing buffer
property)
#533
Comments
@asottile |
I'm not sure it's relevant why this is happening (it's really orthogonal given behave's mock is incorrect) but sure I can explain. With a missing $ LANG= python3 -c 'print("\u2603")'
Traceback (most recent call last):
File "<string>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character '\u2603' in position 0: ordinal not in range(128) The bytestream does not suffer from this fault:
|
In another project I maintain, the only interface to plugins is via |
Sorry, I disagree. |
Whether you agree or not >>> import io
>>> import sys
>>> isinstance(sys.stdout, io.TextIOWrapper)
True
>>> isinstance(sys.stderr, io.TextIOWrapper)
True |
@jenisys: your opinion is incorrect. Consider the venerable program"tar”. A common usage is to stream its (decidedly binary) output over SSH, from its stdout. Should we not be able to write this program in Python? (No, we should, and we can.) Should behave prevent it from functioning correctly under test? |
@bukzor |
@jenisys I think you misunderstood @bukzor, let's see if I can make a simpler example: Consider I'm writing Here's a simple test I might write that would ensure it works correctly:
But you'll notice that cat also supports arbitrarily encoded files, including binary files:
If I were to write this in python, I would write it as follows: import argparse
import sys
def main(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument('filenames', nargs='*')
args = parser.parse_args(argv)
# TODO: zero filenames would read from stdin if compliant, but this is a silly example
for filename in args.filenames:
with open(filename, 'rb') as f:
# py2 + py3 compatibility, in python2, sys.stdout is a byte stream, in python3 use the buffer property
getattr(sys.stdout, 'buffer', sys.stdout).write(f.read())
if __name__ == '__main__':
exit(main()) My implementation works!
And I might test it as follows (if behave would allow it! except there's no attribute
|
@asottile The problem is the following. The stdout/stderr streams have an encoding. Your clearly violate the encoding (at least in your example) by using the low-level API (and the randomly generated data) and do not ensure that the encoding is preserved (in the binary data). Therefore, anybody who tries to read back the binary data from the steam output and tries to display it (therefore needs to decode them) is fucked. Just because you can do something, is not a reason to really do it and encourage others to do it. Provide a compelling reason why this is needed (and a solution that complies with the encoding of the output streams), then I might consider it as real problem (and accept the pull-request). NOTE: Behave uses textual streams (meaning unicode) for stdout/stderr. Therefore, the streams have an encoding, for example "UTF-8". What you do with your other streams is not relevant here. |
You'll notice that I change nothing about the interface. These are still text streams, but they add an additional interface which conforms to the interface of sys.stdout and sys.stderr. They still enforce writing of text and they still retrieve text. The interface is entirely backwards compatible! >>> from behave.capture import CaptureIO
>>> io = CaptureIO()
>>> io.write(b'foo')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: write() argument must be str, not bytes
>>> io.write('bar')
3
>>> io.getvalue()
'bar'
>>> type(io.getvalue()) is bytes
False pytest (a much more popular testing framework) considered this to be a bug and accepted an almost identical pull request. Like you said What I do with my other streams is absolutely relevant here. behave is a testing framework! It should keep its opinions to itself and enable me to write code however I want, however you seem to be interjecting your opinions and forcing me to fork or deprecate your framework. If you believe how I do my streams is not relevant, please demonstrate how I can test |
@asottile Behave must display the captured contents of this stream when a failure occurs. When you inject your BAD-BINARY-DATA into it, behave will not deal with this problem. |
I was planning to add a second request if this was accepted to be able to read the binary data. As is it should rightfully crash |
Note that this is already the case in python 2 -- imo not a regression. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. Comment to post when closing a stale issue. Set to
|
I can confirm this is still an issue, I'm running |
@solarkennedy Not sure if it's helpful for your situation but |
Aw, but I like behave! :) |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
From an interactive prompt
Demo Setup
Demo output
Version information
Expected behaviour
The text was updated successfully, but these errors were encountered: