Skip to content

Commit c5d193b

Browse files
authored
Add readinto method for MemoryFS and FTPFS file objects (#381)
* add _MemoryFile.readinto method * update CHANGELOG.md * call on_access in _MemoryFile next and readlines methods * add myself to CONTRIBUTORS.md * add mode checks for _MemoryFile readline and readlines methods * fix type annotation for _MemoryFile.readinto * add test for readinto method in open file object * add FTPFile.readinto method * use buffer as variable name for bytearray objects * use bytes_read variable in readinto methods
1 parent 526438d commit c5d193b

File tree

6 files changed

+31
-2
lines changed

6 files changed

+31
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010
### Added
1111

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

1416
### Changed
1517

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Many thanks to the following developers for contributing to this project:
99
- [Justin Charlong](https://github.com/jcharlong)
1010
- [Louis Sautier](https://github.com/sbraz)
1111
- [Martin Larralde](https://github.com/althonos)
12+
- [Nick Henderson](https://github.com/nwh)
1213
- [Will McGugan](https://github.com/willmcgugan)
1314
- [Zmej Serow](https://github.com/zmej-serow)
1415
- [Morten Engelhardt Olsen](https://github.com/xoriath)

fs/ftpfs.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,13 @@ def read(self, size=-1):
235235
remaining -= len(chunk)
236236
return b"".join(chunks)
237237

238+
def readinto(self, buffer):
239+
# type: (bytearray) -> int
240+
data = self.read(len(buffer))
241+
bytes_read = len(data)
242+
buffer[:bytes_read] = data
243+
return bytes_read
244+
238245
def readline(self, size=-1):
239246
# type: (int) -> bytes
240247
return next(line_iterator(self, size)) # type: ignore

fs/iotools.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def readinto(self, b):
117117
except AttributeError:
118118
data = self._f.read(len(b))
119119
bytes_read = len(data)
120-
b[: len(data)] = data
120+
b[:bytes_read] = data
121121
return bytes_read
122122

123123
@typing.no_type_check
@@ -128,7 +128,7 @@ def readinto1(self, b):
128128
except AttributeError:
129129
data = self._f.read1(len(b))
130130
bytes_read = len(data)
131-
b[: len(data)] = data
131+
b[:bytes_read] = data
132132
return bytes_read
133133

134134
def readline(self, limit=-1):

fs/memoryfs.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,15 @@ def __iter__(self):
113113
def next(self):
114114
# type: () -> bytes
115115
with self._seek_lock():
116+
self.on_access()
116117
return next(self._bytes_io)
117118

118119
__next__ = next
119120

120121
def readline(self, size=-1):
121122
# type: (int) -> bytes
123+
if not self._mode.reading:
124+
raise IOError("File not open for reading")
122125
with self._seek_lock():
123126
self.on_access()
124127
return self._bytes_io.readline(size)
@@ -142,9 +145,20 @@ def readable(self):
142145
# type: () -> bool
143146
return self._mode.reading
144147

148+
def readinto(self, buffer):
149+
# type (bytearray) -> Optional[int]
150+
if not self._mode.reading:
151+
raise IOError("File not open for reading")
152+
with self._seek_lock():
153+
self.on_access()
154+
return self._bytes_io.readinto(buffer)
155+
145156
def readlines(self, hint=-1):
146157
# type: (int) -> List[bytes]
158+
if not self._mode.reading:
159+
raise IOError("File not open for reading")
147160
with self._seek_lock():
161+
self.on_access()
148162
return self._bytes_io.readlines(hint)
149163

150164
def seekable(self):

fs/test.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,11 @@ def test_open_files(self):
870870
self.assertTrue(f.readable())
871871
self.assertFalse(f.closed)
872872
self.assertEqual(f.readlines(8), [b"Hello\n", b"World\n"])
873+
self.assertEqual(f.tell(), 12)
874+
buffer = bytearray(4)
875+
self.assertEqual(f.readinto(buffer), 4)
876+
self.assertEqual(f.tell(), 16)
877+
self.assertEqual(buffer, b"foo\n")
873878
with self.assertRaises(IOError):
874879
f.write(b"no")
875880
self.assertTrue(f.closed)

0 commit comments

Comments
 (0)