From a6dc5d4e1c9ef465dc1f1ad95c382aa8e32b178f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 31 May 2019 13:03:22 -0700 Subject: [PATCH] bpo-33361: Fix bug with seeking in StreamRecoders (GH-8278) (cherry picked from commit a6ec1ce1ac05b1258931422e96eac215b6a05459) Co-authored-by: Ammar Askar --- Lib/codecs.py | 6 +++++ Lib/test/test_codecs.py | 25 +++++++++++++++++++ .../2018-07-13-20-17-17.bpo-33361.dx2NVn.rst | 2 ++ 3 files changed, 33 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2018-07-13-20-17-17.bpo-33361.dx2NVn.rst diff --git a/Lib/codecs.py b/Lib/codecs.py index 3cd78fc9f19..cfca5d38b07 100644 --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -847,6 +847,12 @@ class StreamRecoder: self.reader.reset() self.writer.reset() + def seek(self, offset, whence=0): + # Seeks must be propagated to both the readers and writers + # as they might need to reset their internal buffers. + self.reader.seek(offset, whence) + self.writer.seek(offset, whence) + def __getattr__(self, name, getattr=getattr): diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index a3a2f6563a1..248ef6fe07d 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -3318,6 +3318,31 @@ class StreamRecoderTest(unittest.TestCase): sr.write(text.encode('latin1')) self.assertEqual(bio.getvalue(), text.encode('utf-8')) + def test_seeking_read(self): + bio = io.BytesIO('line1\nline2\nline3\n'.encode('utf-16-le')) + sr = codecs.EncodedFile(bio, 'utf-8', 'utf-16-le') + + self.assertEqual(sr.readline(), b'line1\n') + sr.seek(0) + self.assertEqual(sr.readline(), b'line1\n') + self.assertEqual(sr.readline(), b'line2\n') + self.assertEqual(sr.readline(), b'line3\n') + self.assertEqual(sr.readline(), b'') + + def test_seeking_write(self): + bio = io.BytesIO('123456789\n'.encode('utf-16-le')) + sr = codecs.EncodedFile(bio, 'utf-8', 'utf-16-le') + + # Test that seek() only resets its internal buffer when offset + # and whence are zero. + sr.seek(2) + sr.write(b'\nabc\n') + self.assertEqual(sr.readline(), b'789\n') + sr.seek(0) + self.assertEqual(sr.readline(), b'1\n') + self.assertEqual(sr.readline(), b'abc\n') + self.assertEqual(sr.readline(), b'789\n') + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2018-07-13-20-17-17.bpo-33361.dx2NVn.rst b/Misc/NEWS.d/next/Library/2018-07-13-20-17-17.bpo-33361.dx2NVn.rst new file mode 100644 index 00000000000..2b71095984a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-07-13-20-17-17.bpo-33361.dx2NVn.rst @@ -0,0 +1,2 @@ +Fix a bug in :class:`codecs.StreamRecoder` where seeking might leave old data in a +buffer and break subsequent read calls. Patch by Ammar Askar.