You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
mock_open() should allow reading binary data #67193
"""Traceback (most recent call last):
File "z.py", line 6, in <module>print(f.read())
File "/usr/local/lib/python3.4/unittest/mock.py", line 896, in __call__return _mock_self._mock_call(*args, **kwargs)
File "/usr/local/lib/python3.4/unittest/mock.py", line 962, in _mock_call
ret_val = effect(*args, **kwargs)
File "/usr/local/lib/python3.4/unittest/mock.py", line 2279, in _read_side_effectreturn''.join(_data)
File "/usr/local/lib/python3.4/unittest/mock.py", line 2244, in _iterate_read_data
data_as_list = ['{}\n'.format(l) for l in read_data.split('\n')]
"""
I've created a patch that fixes this, and added an accompanying unit test (which fails without the change).
demianbrecht commented on Dec 13, 2014
demianbrechtmannequin
Mannequin
More actions
Thanks for the patch Aaron. Unfortunately this doesn't quite fix the issue. There are two problems with the patch:
If a bytes object is passed into mock_open, I'd expect a bytes object in the output. In your patch, not only is this not the case (the output is a string object), but the bytes object is being coerced into its string representation in the resulting list. For example (simplified from your patch):
>>> data =b'foo\nbar'
>>> newline =b'\n'
>>>
>>> ['{}\n'.format(l) for l in data.split(newline)]
["b'foo'\n", "b'bar'\n"]
What I would expect to see in this case is:
[b'foo\n', b'bar\n']
demianbrecht commented on Dec 13, 2014
demianbrechtmannequin
Mannequin
More actions
There are two problems with the patch
That was intended to be removed after I changed the wording :P
Aaron1011 commented on Dec 13, 2014
Aaron1011mannequin
Mannequin
More actions
I've created a new patch, which addresses the problem. Your example now currently returns [b'foo\n', b'bar\n']
demianbrecht commented on Dec 14, 2014
demianbrechtmannequin
Mannequin
More actions
Thanks for the update, but this doesn't quite work either as you're assuming utf-8 (which is what .encode() and .decode() default to). For example, when using latin-1:
>>> m = mock_open(read_data=b'\xc6')
>>> with patch('__main__.open', m, create=True) :
... withopen('abc', 'rb') as f :
... print(f.read())
...
Traceback (most recent call last):
[snip]
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc6 in position 0: unexpected end of data
Additionally, a bytes object may simply be binary data that doesn't adhere to any specific encoding.
My suggestion is to remove the use of format() altogether as it's really not doing anything complex and simply append either '\n' or b'\n' depending on the type of object passed in. That way, you can deal with the type of object passed in directly without coercion.
Aaron1011 commented on Dec 14, 2014
Aaron1011mannequin
Mannequin
More actions
Thanks, I've fixed that. Not sure why I thought decoding and re-encoding would work with any binary data.
I've also updated one of the tests to use non-utf8-decodeable binary data, to prevent a future regression.
demianbrecht commented on Dec 15, 2014
demianbrechtmannequin
Mannequin
More actions
Thanks again for the update Aaron, I've left a couple small comments in Rietveld. Other than those, the patch looks good to me. Thanks for the contribution!
Aaron1011 commented on Dec 16, 2014
Aaron1011mannequin
Mannequin
More actions
I've fixed the issues you pointed out.
Is there a better way than uploading a new patch file to make changes?
demianbrecht commented on Dec 16, 2014
demianbrechtmannequin
Mannequin
More actions
Thanks for the updated patch, looks good to me. If you haven't already read it, the patch workflow is here: https://docs.python.org/devguide/patch.html and is the only workflow currently available.
Aaron1011 commented on Dec 20, 2014
Aaron1011mannequin
Mannequin
More actions
I've fixed the formatting issues.
demianbrecht commented on Dec 31, 2014
demianbrechtmannequin
Mannequin
More actions
A few more comments were left in Rietveld for you, likely hidden by spam filters.
splitlines(keepends=True) is not ever equivalent to splitting by just '\n'. I don't know the details here, but switching to that would certainly be a behavior change. (Especially if the code path also applies to non-binary data!):
Activity
jcea commentedon Dec 7, 2014
mock_open(read_data=b'...') gives an error:
Easy to reproduce:
"""
from unittest.mock import mock_open, patch
Looks like this bug was introduced as result of issue bpo-17467. I add those people to the nosy list.
Aaron1011 commentedon Dec 13, 2014
I've created a patch that fixes this, and added an accompanying unit test (which fails without the change).
demianbrecht commentedon Dec 13, 2014
Thanks for the patch Aaron. Unfortunately this doesn't quite fix the issue. There are two problems with the patch:
If a bytes object is passed into mock_open, I'd expect a bytes object in the output. In your patch, not only is this not the case (the output is a string object), but the bytes object is being coerced into its string representation in the resulting list. For example (simplified from your patch):
What I would expect to see in this case is:
[b'foo\n', b'bar\n']
demianbrecht commentedon Dec 13, 2014
That was intended to be removed after I changed the wording :P
Aaron1011 commentedon Dec 13, 2014
I've created a new patch, which addresses the problem. Your example now currently returns [b'foo\n', b'bar\n']
demianbrecht commentedon Dec 14, 2014
Thanks for the update, but this doesn't quite work either as you're assuming utf-8 (which is what .encode() and .decode() default to). For example, when using latin-1:
Additionally, a bytes object may simply be binary data that doesn't adhere to any specific encoding.
My suggestion is to remove the use of format() altogether as it's really not doing anything complex and simply append either '\n' or b'\n' depending on the type of object passed in. That way, you can deal with the type of object passed in directly without coercion.
Aaron1011 commentedon Dec 14, 2014
Thanks, I've fixed that. Not sure why I thought decoding and re-encoding would work with any binary data.
I've also updated one of the tests to use non-utf8-decodeable binary data, to prevent a future regression.
demianbrecht commentedon Dec 15, 2014
Thanks again for the update Aaron, I've left a couple small comments in Rietveld. Other than those, the patch looks good to me. Thanks for the contribution!
Aaron1011 commentedon Dec 16, 2014
I've fixed the issues you pointed out.
Is there a better way than uploading a new patch file to make changes?
demianbrecht commentedon Dec 16, 2014
Thanks for the updated patch, looks good to me. If you haven't already read it, the patch workflow is here: https://docs.python.org/devguide/patch.html and is the only workflow currently available.
Aaron1011 commentedon Dec 20, 2014
I've fixed the formatting issues.
demianbrecht commentedon Dec 31, 2014
A few more comments were left in Rietveld for you, likely hidden by spam filters.
berkerpeksag commentedon Mar 2, 2015
LGTM.
python-dev commentedon Aug 6, 2015
New changeset 3d7adf5b3fb3 by Berker Peksag in branch '3.4':
Issue bpo-23004: mock_open() now reads binary data correctly when the type of read_data is bytes.
https://hg.python.org/cpython/rev/3d7adf5b3fb3
New changeset 526a186de32d by Berker Peksag in branch '3.5':
Issue bpo-23004: mock_open() now reads binary data correctly when the type of read_data is bytes.
https://hg.python.org/cpython/rev/526a186de32d
New changeset ed15f399a292 by Berker Peksag in branch 'default':
Issue bpo-23004: mock_open() now reads binary data correctly when the type of read_data is bytes.
https://hg.python.org/cpython/rev/ed15f399a292
berkerpeksag commentedon Aug 6, 2015
Thanks for the patch, Aaron(also thanks to Demian for reviews). I've fixed the merge conflict and added more tests.
rbtcollins commentedon Aug 6, 2015
Post merge review:
looks like
would be a little cleaner.
berkerpeksag commentedon Aug 7, 2015
is not actually the equivalent of
It will change the behavior of the _iterate_read_data helper. See the comment at
cpython/Lib/unittest/mock.py
Line 2278 in 78d05eb
However, in default branch, we can simplify it to
bitdancer commentedon Aug 7, 2015
splitlines(keepends=True) is not ever equivalent to splitting by just '\n'. I don't know the details here, but switching to that would certainly be a behavior change. (Especially if the code path also applies to non-binary data!):