Search code examples
pythonpython-mock

Is read(n) compatible with mock_open?


[Update: This is a known bug.]

Is there a way to use read(some_number_of_bytes) with mock_open?

mock_open works as expected when reading the entire file (read()) or when reading a single line (readline()), but I can't get it working when reading a number of bytes (read(n))

These snippets (adapted from the Mock documentation) work (Python 2.7):

from mock import mock_open, patch

# works: consume entire "file"
with patch('__main__.open', mock_open(read_data='bibble')) as m:
    with open('foo') as h:
        result = h.read()

assert result == 'bibble'  # ok

# works: consume one line
with patch('__main__.open', mock_open(read_data='bibble\nbobble')) as m:
    with open('foo') as h:
        result = h.readline()

assert result == 'bibble\n'  # ok

But trying to read only a few bytes fails--mock_open returns the entire read_data instead:

# consume first 3 bytes of the "file"
with patch('__main__.open', mock_open(read_data='bibble')) as m:
    with open('foo') as h:
        result = h.read(3)

assert result == 'bib', 'result of read: {}'.format(result)  # fails

Output:

Traceback (most recent call last):
  File "/tmp/t.py", line 25, in <module>
    assert result == 'bib', 'result of read: {}'.format(result)
AssertionError: result of read: bibble

In case this is an XY problem, I'll note that the reason for this question is that I'm mocking a file that I pass into pickle.load, which in turn calls read(1).

with open('/path/to/file.pkl', 'rb') as f:
    x = pickle.load(f)  # this requires f.read(1) to work

I'd prefer to mock the lowest level possible (open rather than pickle.load).


Solution

  • For the record, this issue has been fixed in Python 3.7.