Issue #6939: Fix file I/O objects in the `io` module to keep the original
file position when calling `truncate()`. It would previously change the
file position to the given argument, which goes against the tradition of
`ftruncate()` and other truncation APIs. Patch by Pascal Chambon.
diff --git a/Lib/io.py b/Lib/io.py
index 70f2aba..d090eec 100644
--- a/Lib/io.py
+++ b/Lib/io.py
@@ -880,7 +880,7 @@
elif pos < 0:
raise ValueError("negative truncate position %r" % (pos,))
del self._buffer[pos:]
- return self.seek(pos)
+ return pos
def readable(self):
return True
@@ -1215,8 +1215,7 @@
if pos is None:
pos = self.tell()
# Use seek to flush the read buffer.
- self.seek(pos)
- return BufferedWriter.truncate(self)
+ return BufferedWriter.truncate(self, pos)
def read(self, n=None):
if n is None:
@@ -1667,8 +1666,7 @@
self.flush()
if pos is None:
pos = self.tell()
- self.seek(pos)
- return self.buffer.truncate()
+ return self.buffer.truncate(pos)
def seek(self, cookie, whence=0):
if self.closed:
diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py
index 928fbec..0eea86b 100644
--- a/Lib/test/test_fileio.py
+++ b/Lib/test/test_fileio.py
@@ -197,6 +197,17 @@
f.close()
self.fail("no error for invalid mode: %s" % bad_mode)
+ def testTruncate(self):
+ f = _fileio._FileIO(TESTFN, 'w')
+ f.write(bytes(bytearray(range(10))))
+ self.assertEqual(f.tell(), 10)
+ f.truncate(5)
+ self.assertEqual(f.tell(), 10)
+ self.assertEqual(f.seek(0, os.SEEK_END), 5)
+ f.truncate(15)
+ self.assertEqual(f.tell(), 5)
+ self.assertEqual(f.seek(0, os.SEEK_END), 15)
+
def testTruncateOnWindows(self):
def bug801631():
# SF bug <http://www.python.org/sf/801631>
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index f0b38b6..38c58c3 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -87,6 +87,12 @@
test_support.unlink(test_support.TESTFN)
def write_ops(self, f):
+
+ self.assertEqual(f.write(b"blah."), 5)
+ f.truncate(0)
+ self.assertEqual(f.tell(), 5)
+ f.seek(0)
+
self.assertEqual(f.write(b"blah."), 5)
self.assertEqual(f.seek(0), 0)
self.assertEqual(f.write(b"Hello."), 6)
@@ -98,8 +104,9 @@
self.assertEqual(f.write(b"h"), 1)
self.assertEqual(f.seek(-1, 2), 13)
self.assertEqual(f.tell(), 13)
+
self.assertEqual(f.truncate(12), 12)
- self.assertEqual(f.tell(), 12)
+ self.assertEqual(f.tell(), 13)
self.assertRaises(TypeError, f.seek, 0.0)
def read_ops(self, f, buffered=False):
@@ -144,7 +151,7 @@
self.assertEqual(f.tell(), self.LARGE + 2)
self.assertEqual(f.seek(0, 2), self.LARGE + 2)
self.assertEqual(f.truncate(self.LARGE + 1), self.LARGE + 1)
- self.assertEqual(f.tell(), self.LARGE + 1)
+ self.assertEqual(f.tell(), self.LARGE + 2)
self.assertEqual(f.seek(0, 2), self.LARGE + 1)
self.assertEqual(f.seek(-1, 2), self.LARGE)
self.assertEqual(f.read(2), b"x")
diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py
index d538a7e..85b5e13 100644
--- a/Lib/test/test_memoryio.py
+++ b/Lib/test/test_memoryio.py
@@ -32,7 +32,7 @@
self.assertEqual(f.seek(0), 0)
self.assertEqual(f.write(t("h")), 1)
self.assertEqual(f.truncate(12), 12)
- self.assertEqual(f.tell(), 12)
+ self.assertEqual(f.tell(), 1)
def test_write(self):
buf = self.buftype("hello world\n")
@@ -83,7 +83,8 @@
# truncate() accepts long objects
self.assertEqual(memio.truncate(4L), 4)
self.assertEqual(memio.getvalue(), buf[:4])
- self.assertEqual(memio.tell(), 4)
+ self.assertEqual(memio.tell(), 6)
+ memio.seek(0, 2)
memio.write(buf)
self.assertEqual(memio.getvalue(), buf[:4] + buf)
pos = memio.tell()