Skip to content
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added

- Missing `mode` attribute to `_MemoryFile` objects returned by `MemoryFS.openbin`.
- Missing `readinto` method for `MemoryFS` and `FTPFS` file objects. Closes
[#380](https://github.com/PyFilesystem/pyfilesystem2/issues/380).

### Changed

Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Many thanks to the following developers for contributing to this project:
- [Justin Charlong](https://github.com/jcharlong)
- [Louis Sautier](https://github.com/sbraz)
- [Martin Larralde](https://github.com/althonos)
- [Nick Henderson](https://github.com/nwh)
- [Will McGugan](https://github.com/willmcgugan)
- [Zmej Serow](https://github.com/zmej-serow)
- [Morten Engelhardt Olsen](https://github.com/xoriath)
7 changes: 7 additions & 0 deletions fs/ftpfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,13 @@ def read(self, size=-1):
remaining -= len(chunk)
return b"".join(chunks)

def readinto(self, buffer):
# type: (bytearray) -> int
data = self.read(len(buffer))
bytes_read = len(data)
buffer[:bytes_read] = data
return bytes_read

def readline(self, size=-1):
# type: (int) -> bytes
return next(line_iterator(self, size)) # type: ignore
Expand Down
4 changes: 2 additions & 2 deletions fs/iotools.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def readinto(self, b):
except AttributeError:
data = self._f.read(len(b))
bytes_read = len(data)
b[: len(data)] = data
b[:bytes_read] = data
return bytes_read

@typing.no_type_check
Expand All @@ -128,7 +128,7 @@ def readinto1(self, b):
except AttributeError:
data = self._f.read1(len(b))
bytes_read = len(data)
b[: len(data)] = data
b[:bytes_read] = data
return bytes_read

def readline(self, limit=-1):
Expand Down
14 changes: 14 additions & 0 deletions fs/memoryfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,15 @@ def __iter__(self):
def next(self):
# type: () -> bytes
with self._seek_lock():
self.on_access()
return next(self._bytes_io)

__next__ = next

def readline(self, size=-1):
# type: (int) -> bytes
if not self._mode.reading:
raise IOError("File not open for reading")
with self._seek_lock():
self.on_access()
return self._bytes_io.readline(size)
Expand All @@ -142,9 +145,20 @@ def readable(self):
# type: () -> bool
return self._mode.reading

def readinto(self, buffer):
# type (bytearray) -> Optional[int]
if not self._mode.reading:
raise IOError("File not open for reading")
with self._seek_lock():
self.on_access()
return self._bytes_io.readinto(buffer)

def readlines(self, hint=-1):
# type: (int) -> List[bytes]
if not self._mode.reading:
raise IOError("File not open for reading")
with self._seek_lock():
self.on_access()
return self._bytes_io.readlines(hint)

def seekable(self):
Expand Down
5 changes: 5 additions & 0 deletions fs/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,11 @@ def test_open_files(self):
self.assertTrue(f.readable())
self.assertFalse(f.closed)
self.assertEqual(f.readlines(8), [b"Hello\n", b"World\n"])
self.assertEqual(f.tell(), 12)
buffer = bytearray(4)
self.assertEqual(f.readinto(buffer), 4)
self.assertEqual(f.tell(), 16)
self.assertEqual(buffer, b"foo\n")
with self.assertRaises(IOError):
f.write(b"no")
self.assertTrue(f.closed)
Expand Down