Skip to content

Commit 846fd72

Browse files
gh-115059: Flush the underlying write buffer in io.BufferedRandom.read1() (GH-115163)
1 parent c968dc7 commit 846fd72

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-0
lines changed

Lib/test/test_io.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2497,6 +2497,28 @@ def test_interleaved_read_write(self):
24972497
f.flush()
24982498
self.assertEqual(raw.getvalue(), b'a2c')
24992499

2500+
def test_read1_after_write(self):
2501+
with self.BytesIO(b'abcdef') as raw:
2502+
with self.tp(raw, 3) as f:
2503+
f.write(b"1")
2504+
self.assertEqual(f.read1(1), b'b')
2505+
f.flush()
2506+
self.assertEqual(raw.getvalue(), b'1bcdef')
2507+
with self.BytesIO(b'abcdef') as raw:
2508+
with self.tp(raw, 3) as f:
2509+
f.write(b"1")
2510+
self.assertEqual(f.read1(), b'bcd')
2511+
f.flush()
2512+
self.assertEqual(raw.getvalue(), b'1bcdef')
2513+
with self.BytesIO(b'abcdef') as raw:
2514+
with self.tp(raw, 3) as f:
2515+
f.write(b"1")
2516+
# XXX: read(100) returns different numbers of bytes
2517+
# in Python and C implementations.
2518+
self.assertEqual(f.read1(100)[:3], b'bcd')
2519+
f.flush()
2520+
self.assertEqual(raw.getvalue(), b'1bcdef')
2521+
25002522
def test_interleaved_readline_write(self):
25012523
with self.BytesIO(b'ab\ncdef\ng\n') as raw:
25022524
with self.tp(raw) as f:
@@ -2509,6 +2531,36 @@ def test_interleaved_readline_write(self):
25092531
f.flush()
25102532
self.assertEqual(raw.getvalue(), b'1b\n2def\n3\n')
25112533

2534+
def test_xxx(self):
2535+
with self.BytesIO(b'abcdefgh') as raw:
2536+
with self.tp(raw) as f:
2537+
f.write(b'123')
2538+
self.assertEqual(f.read(), b'defgh')
2539+
f.write(b'456')
2540+
f.flush()
2541+
self.assertEqual(raw.getvalue(), b'123defgh456')
2542+
with self.BytesIO(b'abcdefgh') as raw:
2543+
with self.tp(raw) as f:
2544+
f.write(b'123')
2545+
self.assertEqual(f.read(3), b'def')
2546+
f.write(b'456')
2547+
f.flush()
2548+
self.assertEqual(raw.getvalue(), b'123def456')
2549+
with self.BytesIO(b'abcdefgh') as raw:
2550+
with self.tp(raw) as f:
2551+
f.write(b'123')
2552+
self.assertEqual(f.read1(), b'defgh')
2553+
f.write(b'456')
2554+
f.flush()
2555+
self.assertEqual(raw.getvalue(), b'123defgh456')
2556+
with self.BytesIO(b'abcdefgh') as raw:
2557+
with self.tp(raw) as f:
2558+
f.write(b'123')
2559+
self.assertEqual(f.read1(3), b'def')
2560+
f.write(b'456')
2561+
f.flush()
2562+
self.assertEqual(raw.getvalue(), b'123def456')
2563+
25122564
# You can't construct a BufferedRandom over a non-seekable stream.
25132565
test_unseekable = None
25142566

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:meth:`io.BufferedRandom.read1` now flushes the underlying write buffer.

Modules/_io/bufferedio.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,16 @@ _io__Buffered_read1_impl(buffered *self, Py_ssize_t n)
10501050
Py_DECREF(res);
10511051
return NULL;
10521052
}
1053+
/* Flush the write buffer if necessary */
1054+
if (self->writable) {
1055+
PyObject *r = buffered_flush_and_rewind_unlocked(self);
1056+
if (r == NULL) {
1057+
LEAVE_BUFFERED(self)
1058+
Py_DECREF(res);
1059+
return NULL;
1060+
}
1061+
Py_DECREF(r);
1062+
}
10531063
_bufferedreader_reset_buf(self);
10541064
r = _bufferedreader_raw_read(self, PyBytes_AS_STRING(res), n);
10551065
LEAVE_BUFFERED(self)

0 commit comments

Comments
 (0)