Skip to content

Commit dbe0982

Browse files
Issue #8260: The read(), readline() and readlines() methods of
codecs.StreamReader returned incomplete data when were called after readline() or read(size). Based on patch by Amaury Forgeot d'Arc.
1 parent 0742cae commit dbe0982

File tree

3 files changed

+44
-9
lines changed

3 files changed

+44
-9
lines changed

Lib/codecs.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -475,22 +475,21 @@ def read(self, size=-1, chars=-1, firstline=False):
475475
# read until we get the required number of characters (if available)
476476
while True:
477477
# can the request be satisfied from the character buffer?
478-
if chars < 0:
479-
if size < 0:
480-
if self.charbuffer:
481-
break
482-
elif len(self.charbuffer) >= size:
483-
break
484-
else:
478+
if chars >= 0:
485479
if len(self.charbuffer) >= chars:
486480
break
481+
elif size >= 0:
482+
if len(self.charbuffer) >= size:
483+
break
487484
# we need more data
488485
if size < 0:
489486
newdata = self.stream.read()
490487
else:
491488
newdata = self.stream.read(size)
492489
# decode bytes (those remaining from the last call included)
493490
data = self.bytebuffer + newdata
491+
if not data:
492+
break
494493
try:
495494
newchars, decodedbytes = self.decode(data, self.errors)
496495
except UnicodeDecodeError as exc:

Lib/test/test_codecs.py

+34-2
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,40 @@ def readalllines(input, keepends=True, size=None):
175175
size*"a",
176176
)
177177

178+
def test_mixed_readline_and_read(self):
179+
lines = ["Humpty Dumpty sat on a wall,\n",
180+
"Humpty Dumpty had a great fall.\r\n",
181+
"All the king's horses and all the king's men\r",
182+
"Couldn't put Humpty together again."]
183+
data = ''.join(lines)
184+
def getreader():
185+
stream = io.BytesIO(data.encode(self.encoding))
186+
return codecs.getreader(self.encoding)(stream)
187+
188+
# Issue #8260: Test readline() followed by read()
189+
f = getreader()
190+
self.assertEqual(f.readline(), lines[0])
191+
self.assertEqual(f.read(), ''.join(lines[1:]))
192+
self.assertEqual(f.read(), '')
193+
194+
# Issue #16636: Test readline() followed by readlines()
195+
f = getreader()
196+
self.assertEqual(f.readline(), lines[0])
197+
self.assertEqual(f.readlines(), lines[1:])
198+
self.assertEqual(f.read(), '')
199+
200+
# Test read() followed by read()
201+
f = getreader()
202+
self.assertEqual(f.read(size=40, chars=5), data[:5])
203+
self.assertEqual(f.read(), data[5:])
204+
self.assertEqual(f.read(), '')
205+
206+
# Issue #12446: Test read() followed by readlines()
207+
f = getreader()
208+
self.assertEqual(f.read(size=40, chars=5), data[:5])
209+
self.assertEqual(f.readlines(), [lines[0][5:]] + lines[1:])
210+
self.assertEqual(f.read(), '')
211+
178212
def test_bug1175396(self):
179213
s = [
180214
'<%!--===================================================\r\n',
@@ -2370,8 +2404,6 @@ def test_read(self):
23702404

23712405
def test_readline(self):
23722406
for encoding in bytes_transform_encodings:
2373-
if encoding in ['uu_codec', 'zlib_codec']:
2374-
continue
23752407
with self.subTest(encoding=encoding):
23762408
sin = codecs.encode(b"\x80", encoding)
23772409
reader = codecs.getreader(encoding)(io.BytesIO(sin))

Misc/NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ Core and Builtins
3636
Library
3737
-------
3838

39+
- Issue #8260: The read(), readline() and readlines() methods of
40+
codecs.StreamReader returned incomplete data when were called after
41+
readline() or read(size). Based on patch by Amaury Forgeot d'Arc.
42+
3943
- Issue #20105: the codec exception chaining now correctly sets the
4044
traceback of the original exception as its __traceback__ attribute.
4145

0 commit comments

Comments
 (0)